1/*
2 * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.tools.java;
27
28import java.util.*;
29
30/**
31 * The MethodSet structure is used to store methods for a class.
32 * It maintains the invariant that it never stores two methods
33 * with the same signature.  MethodSets are able to lookup
34 * all methods with a given name and the unique method with a given
35 * signature (name, args).
36 *
37 * WARNING: The contents of this source file are not part of any
38 * supported API.  Code that depends on them does so at its own risk:
39 * they are subject to change or removal without notice.
40 */
41
42public
43class MethodSet {
44
45    /**
46     * A Map containing Lists of MemberDefinitions.  The Lists
47     * contain methods which share the same name.
48     */
49    private final Map<Identifier,List<MemberDefinition>> lookupMap;
50
51    /**
52     * The number of methods stored in the MethodSet.
53     */
54    private int count;
55
56    /**
57     * Is this MethodSet currently frozen?  See freeze() for more details.
58     */
59    private boolean frozen;
60
61    /**
62     * Creates a brand new MethodSet
63     */
64    public MethodSet() {
65        frozen = false;
66        lookupMap = new HashMap<>();
67        count = 0;
68    }
69
70    /**
71     * Returns the number of distinct methods stored in the MethodSet.
72     */
73    public int size() {
74        return count;
75    }
76
77    /**
78     * Adds `method' to the MethodSet.  No method of the same signature
79     * should be already defined.
80     */
81    public void add(MemberDefinition method) {
82            // Check for late additions.
83            if (frozen) {
84                throw new CompilerError("add()");
85            }
86
87            // todo: Check for method??
88
89            Identifier name = method.getName();
90
91            // Get a List containing all methods of this name.
92            List<MemberDefinition> methodList = lookupMap.get(name);
93
94            if (methodList == null) {
95                // There is no method with this name already.
96                // Create a List, and insert it into the hash.
97                methodList = new ArrayList<>();
98                lookupMap.put(name, methodList);
99            }
100
101            // Make sure that no method with the same signature has already
102            // been added to the MethodSet.
103            int size = methodList.size();
104            for (int i = 0; i < size; i++) {
105                if ((methodList.get(i))
106                    .getType().equalArguments(method.getType())) {
107                    throw new CompilerError("duplicate addition");
108                }
109            }
110
111            // We add the method to the appropriate list.
112            methodList.add(method);
113            count++;
114    }
115
116    /**
117     * Adds `method' to the MethodSet, replacing any previous definition
118     * with the same signature.
119     */
120    public void replace(MemberDefinition method) {
121            // Check for late additions.
122            if (frozen) {
123                throw new CompilerError("replace()");
124            }
125
126            // todo: Check for method??
127
128            Identifier name = method.getName();
129
130            // Get a List containing all methods of this name.
131            List<MemberDefinition> methodList = lookupMap.get(name);
132
133            if (methodList == null) {
134                // There is no method with this name already.
135                // Create a List, and insert it into the hash.
136                methodList = new ArrayList<>();
137                lookupMap.put(name, methodList);
138            }
139
140            // Replace the element which has the same signature as
141            // `method'.
142            int size = methodList.size();
143            for (int i = 0; i < size; i++) {
144                if ((methodList.get(i))
145                    .getType().equalArguments(method.getType())) {
146                    methodList.set(i, method);
147                    return;
148                }
149            }
150
151            // We add the method to the appropriate list.
152            methodList.add(method);
153            count++;
154    }
155
156    /**
157     * If the MethodSet contains a method with the same signature
158     * then lookup() returns it.  Otherwise, this method returns null.
159     */
160    public MemberDefinition lookupSig(Identifier name, Type type) {
161        // Go through all methods of the same name and see if any
162        // have the right signature.
163        Iterator<MemberDefinition> matches = lookupName(name);
164        MemberDefinition candidate;
165
166        while (matches.hasNext()) {
167            candidate = matches.next();
168            if (candidate.getType().equalArguments(type)) {
169                return candidate;
170            }
171        }
172
173        // No match.
174        return null;
175    }
176
177    /**
178     * Returns an Iterator of all methods contained in the
179     * MethodSet which have a given name.
180     */
181    public Iterator<MemberDefinition> lookupName(Identifier name) {
182        // Find the List containing all methods of this name, and
183        // return that List's Iterator.
184        List<MemberDefinition> methodList = lookupMap.get(name);
185        if (methodList == null) {
186            // If there is no method of this name, return a bogus, empty
187            // Iterator.
188            return Collections.emptyIterator();
189        }
190        return methodList.iterator();
191    }
192
193    /**
194     * Returns an Iterator of all methods in the MethodSet
195     */
196    public Iterator<MemberDefinition> iterator() {
197
198        //----------------------------------------------------------
199        // The inner class MethodIterator is used to create our
200        // Iterator of all methods in the MethodSet.
201        class MethodIterator implements Iterator<MemberDefinition> {
202            Iterator<List<MemberDefinition>> hashIter = lookupMap.values().iterator();
203            Iterator<MemberDefinition> listIter = Collections.emptyIterator();
204
205            public boolean hasNext() {
206                if (listIter.hasNext()) {
207                    return true;
208                } else {
209                    if (hashIter.hasNext()) {
210                        listIter = hashIter.next().iterator();
211
212                        // The following should be always true.
213                        if (listIter.hasNext()) {
214                            return true;
215                        } else {
216                            throw new
217                                CompilerError("iterator() in MethodSet");
218                        }
219                    }
220                }
221
222                // We've run out of Lists.
223                return false;
224            }
225
226            public MemberDefinition next() {
227                return listIter.next();
228            }
229
230            public void remove() {
231                throw new UnsupportedOperationException();
232            }
233        }
234        // end MethodIterator
235        //----------------------------------------------------------
236
237        // A one-liner.
238        return new MethodIterator();
239    }
240
241    /**
242     * After freeze() is called, the MethodSet becomes (mostly)
243     * immutable.  Any calls to add() or addMeet() lead to
244     * CompilerErrors.  Note that the entries themselves are still
245     * (unfortunately) open for mischievous and wanton modification.
246     */
247    public void freeze() {
248        frozen = true;
249    }
250
251    /**
252     * Tells whether freeze() has been called on this MethodSet.
253     */
254    public boolean isFrozen() {
255        return frozen;
256    }
257
258    /**
259     * Returns a (big) string representation of this MethodSet
260     */
261    public String toString() {
262        int len = size();
263        StringBuilder sb = new StringBuilder();
264        Iterator<MemberDefinition> all = iterator();
265        sb.append("{");
266
267        while (all.hasNext()) {
268            sb.append(all.next().toString());
269            len--;
270            if (len > 0) {
271                sb.append(", ");
272            }
273        }
274        sb.append("}");
275        return sb.toString();
276    }
277}
278