/*
* Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.tools.java;
import java.util.*;
/**
* The MethodSet structure is used to store methods for a class.
* It maintains the invariant that it never stores two methods
* with the same signature. MethodSets are able to lookup
* all methods with a given name and the unique method with a given
* signature (name, args).
*
* WARNING: The contents of this source file are not part of any
* supported API. Code that depends on them does so at its own risk:
* they are subject to change or removal without notice.
*/
public
class MethodSet {
/**
* A Map containing Lists of MemberDefinitions. The Lists
* contain methods which share the same name.
*/
private final Map<Identifier,List<MemberDefinition>> lookupMap;
/**
* The number of methods stored in the MethodSet.
*/
private int count;
/**
* Is this MethodSet currently frozen? See freeze() for more details.
*/
private boolean frozen;
/**
* Creates a brand new MethodSet
*/
public MethodSet() {
frozen = false;
lookupMap = new HashMap<>();
count = 0;
}
/**
* Returns the number of distinct methods stored in the MethodSet.
*/
public int size() {
return count;
}
/**
* Adds `method' to the MethodSet. No method of the same signature
* should be already defined.
*/
public void add(MemberDefinition method) {
// Check for late additions.
if (frozen) {
throw new CompilerError("add()");
}
// todo: Check for method??
Identifier name = method.getName();
// Get a List containing all methods of this name.
List<MemberDefinition> methodList = lookupMap.get(name);
if (methodList == null) {
// There is no method with this name already.
// Create a List, and insert it into the hash.
methodList = new ArrayList<>();
lookupMap.put(name, methodList);
}
// Make sure that no method with the same signature has already
// been added to the MethodSet.
int size = methodList.size();
for (int i = 0; i < size; i++) {
if ((methodList.get(i))
.getType().equalArguments(method.getType())) {
throw new CompilerError("duplicate addition");
}
}
// We add the method to the appropriate list.
methodList.add(method);
count++;
}
/**
* Adds `method' to the MethodSet, replacing any previous definition
* with the same signature.
*/
public void replace(MemberDefinition method) {
// Check for late additions.
if (frozen) {
throw new CompilerError("replace()");
}
// todo: Check for method??
Identifier name = method.getName();
// Get a List containing all methods of this name.
List<MemberDefinition> methodList = lookupMap.get(name);
if (methodList == null) {
// There is no method with this name already.
// Create a List, and insert it into the hash.
methodList = new ArrayList<>();
lookupMap.put(name, methodList);
}
// Replace the element which has the same signature as
// `method'.
int size = methodList.size();
for (int i = 0; i < size; i++) {
if ((methodList.get(i))
.getType().equalArguments(method.getType())) {
methodList.set(i, method);
return;
}
}
// We add the method to the appropriate list.
methodList.add(method);
count++;
}
/**
* If the MethodSet contains a method with the same signature
* then lookup() returns it. Otherwise, this method returns null.
*/
public MemberDefinition lookupSig(Identifier name, Type type) {
// Go through all methods of the same name and see if any
// have the right signature.
Iterator<MemberDefinition> matches = lookupName(name);
MemberDefinition candidate;
while (matches.hasNext()) {
candidate = matches.next();
if (candidate.getType().equalArguments(type)) {
return candidate;
}
}
// No match.
return null;
}
/**
* Returns an Iterator of all methods contained in the
* MethodSet which have a given name.
*/
public Iterator<MemberDefinition> lookupName(Identifier name) {
// Find the List containing all methods of this name, and
// return that List's Iterator.
List<MemberDefinition> methodList = lookupMap.get(name);
if (methodList == null) {
// If there is no method of this name, return a bogus, empty
// Iterator.
return Collections.emptyIterator();
}
return methodList.iterator();
}
/**
* Returns an Iterator of all methods in the MethodSet
*/
public Iterator<MemberDefinition> iterator() {
//----------------------------------------------------------
// The inner class MethodIterator is used to create our
// Iterator of all methods in the MethodSet.
class MethodIterator implements Iterator<MemberDefinition> {
Iterator<List<MemberDefinition>> hashIter = lookupMap.values().iterator();
Iterator<MemberDefinition> listIter = Collections.emptyIterator();
public boolean hasNext() {
if (listIter.hasNext()) {
return true;
} else {
if (hashIter.hasNext()) {
listIter = hashIter.next().iterator();
// The following should be always true.
if (listIter.hasNext()) {
return true;
} else {
throw new
CompilerError("iterator() in MethodSet");
}
}
}
// We've run out of Lists.
return false;
}
public MemberDefinition next() {
return listIter.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
// end MethodIterator
//----------------------------------------------------------
// A one-liner.
return new MethodIterator();
}
/**
* After freeze() is called, the MethodSet becomes (mostly)
* immutable. Any calls to add() or addMeet() lead to
* CompilerErrors. Note that the entries themselves are still
* (unfortunately) open for mischievous and wanton modification.
*/
public void freeze() {
frozen = true;
}
/**
* Tells whether freeze() has been called on this MethodSet.
*/
public boolean isFrozen() {
return frozen;
}
/**
* Returns a (big) string representation of this MethodSet
*/
public String toString() {
int len = size();
StringBuilder sb = new StringBuilder();
Iterator<MemberDefinition> all = iterator();
sb.append("{");
while (all.hasNext()) {
sb.append(all.next().toString());
len--;
if (len > 0) {
sb.append(", ");
}
}
sb.append("}");
return sb.toString();
}
}