Collections drop from Classpath:
2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz> * java/util/BitSet.java (and): Fix off-by-one bug, don't skip part of the bitset. (andNot): Likewise. (xor): Likewise. 2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz> * java/util/LinkedList.java (LinkedListItr.add): Don't skip the next entry. 2001-12-15 Eric Blake <ebb9@email.byu.edu> * java/util/TreeMap.java (removeNode): Fix bug in node removal. 2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz> * java/util/AbstractCollection.java (containsAll): Use size of the correct collection for loop bound. * java/util/AbstractList.java (iterator.next): Increment pos after calling get on backing list. (listIterator.next): Likewise. * java/util/LinkedList.java (addLastEntry): Don't increment size before checking for size == 0. (addFirstEntry): Rearrange to match addLastEntry. (add): Do not increment size before inserting the new entry. * java/util/AbstractCollection.java (addAll): Use size of the correct collection for loop bound. 2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz> * java/util/AbstractSet.java (removeAll): Fix scoping thinko. * java/util/HashMap.java (putAllInternal): Set size here. * java/util/Hashtable.java (putAllInternal): New method. Copy contents of a map efficiently without calling put() or putAll(). (Hashtable (map)): Use putAllInternal. (clone): Likewise. 2001-12-15 Eric Blake <ebb9@email.byu.edu> * java/util/Collections.java: * java/util/Vector.java: * java/util/WeakHashMap.java: Fix spelling errors. 2001-12-15 Eric Blake <ebb9@email.byu.edu> * java/util/AbstractCollection.java (removeAllInternal), (retainAllInternal): Add hooks for use by ArrayList. * java/util/AbstractList.java: Minor code updates. Fix some scoping. * java/util/AbstractMap.java: ditto * java/util/ArrayList.java (readObject, writeObject): ditto (removeAllInternal, retainAllInternal): Optimize. * java/util/Arrays.java: ditto * java/util/Collections.java: ditto. Change order of parameters to equals(Object, Object) to match specs. * java/util/Dictionary.java: Improve javadoc. (Dictionary): Add explicit constructor. * java/util/HashMap.java: Improve javadoc. Rearrange methods to follow order in JDK. Cleanups related to recent code migration to AbstractMap. Fix some scoping. (entrySet): Cache the result. (modCount): Ensure that this is updated correctly. * java/util/HashSet.java: Improve javadoc. Fix some scoping. (init): Add hooks for LinkedHashSet. (map): Use "" instead of Boolean.TRUE in backing map. Use package-private API where possible for less overhead. (readObject, writeObject): Fix serialization. * java/util/Hashtable.java: Improve javadoc. Fix some scoping. (entrySet, keySet, values): Cache the result. (modCount): Ensure that this is updated correctly. (contains, remove): Fix NullPointer checking to match specs. (class Enumeration): Make more like HashIterator. * java/util/IdentityHashMap.java: Minor code updates. (modCount): Ensure that this is updated correctly. (readObject, writeObject): Fix serialization. * java/util/LinkedHashMap.java: Minor code updates. Cleanups related to recent code migration to AbstractMap. * java/util/LinkedHashSet.java: New file. * java/util/LinkedList.java: (readObject, writeObject): Fix serialization. * java/util/Makefile.am: List recently added files. * java/util/Stack.java: Minor code updates. * java/util/TreeMap.java: Improve javadoc. Overhaul the class to be more efficient. Fix some scoping. Rearrange the methods. (nil): Ensure that this can be thread-safe, and make it a static final. Initialize it to be more useful as a sentinal node. (Node): Specify color in constructor. (deleteFixup, insertFixup): Improve comments and algorithm. (fabricateTree): Redesign with less overhead. (lowestGreaterThan): Add parameter first to make SubMap easier. (removeNode): Patch hole where nil was being modified. Choose predecessor instead of successor so in-place swap works. (class VerifyResult, verifyTree, verifySub, verifyError): Remove this dead code after verifying the class works. (class SubMap): Rewrite several algorithms to avoid problems with comparing nil. * java/util/TreeSet.java: Improve javadoc. Fix some scoping. (clone): Fix ClassCastException when cloning subSet(). (readObject, writeObject): Fix serialization. * java/util/WeakHashMap.java: Improve javadoc. Fix some scoping. (NULL_KEY): Make it compare as null, for ease elsewhere. (Class WeakEntry): Rename from Entry, to avoid shadowing Map.Entry. Add missing toString. (modCount): Ensure that this is updated correctly. (clear, containsValue, keySet, putAll, values, WeakHashMap(Map)): Add missing methods and constructor. 2001-12-15 Eric Blake <ebb9@email.byu.edu> * java/util/ArrayList.java (checkBoundExclusive), (checkBoundInclusive): Rename from range??clusive, to match AbstractList. * java/util/LinkedList.java (checkBoundsExclusive), (checkBoundsInclusive): ditto * java/util/Vector.java (checkBoundExclusive), (checkBoundInclusive): Move bounds checking into common methods. 2001-12-15 Eric Blake <ebb9@email.byu.edu> * java/util/AbstractList.java: (modCount): Make sure it is updated in all needed places. * java/util/ArrayList.java: Improve javadoc. Implements RandomAccess. Add serialVersionUID. Reorder methods. (modCount): Make sure it is updated in all needed places. (rangeExclusive, rangeInclusive): Add common methods for bounds check. (isEmpty): Add missing method. * java/util/Collections.java: (class SynchronizedList): Make package visible. * java/util/ConcurrentModificationException.java: Improve javadoc. * java/util/EmptyStackException.java: Improve javadoc. * java/util/LinkedList.java: Improve javadoc. (modCount): Make sure it is updated in all needed places. (rangeExclusive, rangeInclusive): Add common methods for bounds check. * java/util/NoSuchElementException.java: Improve javadoc. * java/util/Stack.java: Improve javadoc. Fix synchronization issues. (modCount): Make sure it is updated in all needed places. * java/util/Vector.java: Improve javadoc. Fix synchronization issues. Implements RandomAccess. Reorder methods. (modCount): Make sure it is updated in all needed places. (setSize): Fix according to specifications: this does not dictate the backing array size. (removeAll, retainAll): Faster implementations. 2001-12-15 Eric Blake <ebb9@email.byu.edu> * java/util/BitSet.java: Improve javadoc. (cardinality(), clear(), clear(int, int), flip(int)), (flip(int, int), get(int, int), intersects(BitSet), isEmpty()), (nextClearBit(int), nextSetBit(int), set(int, boolean)), (set(int, int), set(int, int, boolean)): Add new JDK 1.4 methods. (clone): Fix so subclasses clone correctly. 2001-12-15 Eric Blake <ebb9@email.byu.edu> * java/util/AbstractCollection.java: Improve javadoc. (AbstractCollection()): Make constructor protected. (equals(Object, Object), hashCode(Object)): Add utility methods. * java/util/AbstractList.java: Improve javadoc. (AbstractList()): Make constructor protected. (indexOf(Object)): Call listIterator(), not listIterator(int). (iterator()): Follow Sun's requirement to not use listIterator(0). (listIterator(int)): Make AbstractListItr anonymous. (subList(int, int)): Add support for RandomAccess. (SubList.add(int, Object), SubList.remove(Object)): Fix bug with modCount tracking. (SubList.addAll(Collection)): Add missing method. (SubList.listIterator(int)): Fix bugs in indexing, modCount tracking. (class RandomAccessSubList): Add new class. * java/util/AbstractMap.java: Improve javadoc. (keys, values, KEYS, VALUES, ENTRIES): Consolidate common map fields. (AbstractMap()): Make constructor protected. (equals(Object, Object), hashCode(Object)): Add utility methods. (equals(Object)): Change algorithm to entrySet().equals(m.entrySet()), as documented by Sun. (keySet(), values()): Cache the collections. * java/util/AbstractSequentialList.java: Improve javadoc. (AbstractSequentialList()): Make constructor protected. * java/util/AbstractSet.java: Improve javadoc. (AbstractSet()): Make constructor protected. (removeAll(Collection)): Add missing method. * java/util/Arrays.java: Improve javadoc, rearrange method orders. (defaultComparator): Remove, in favor of Collections.compare(Object, Object, Comparator). (binarySearch, equals, sort): Fix natural order comparison of floats and doubles. Also improve Object comparison - when comparator is null, use natural order. (fill, sort): Add missing checks for IllegalArgumentException. (sort, qsort): Fix sorting bugs, rework the code for more legibility. (mergeSort): Inline into sort(Object[], int, int, Comparator). (class ArrayList): Rename from ListImpl, and make compatible with JDK serialization. Add methods which more efficiently override those of AbstractList. * java/util/Collections: Improve javadoc. (isSequential(List)): Add and use a method for deciding between RandomAccess and sequential algorithms on lists. (class Empty*, class Synchronized*, class Unmodifiable*): Make compliant with JDK serializability. (class Singleton*, class CopiesList, class RevereseComparator), (class UnmodifiableMap.UnmodifiableEntrySet), (class *RandomAccessList): New classes for serial compatibility. (class Empty*, class Singleton*, class CopiesList): Add methods which more efficiently override those of Abstract*. (search): Inline into binarySearch(List, Object, Comparator). (binarySearch): Make sequential search only do log(n) comparisons, instead of n. (copy(List, List)): Do bounds checking before starting. (indexOfSubList, lastIndexOfSubList, list, replaceAll, rotate), (swap): Add new JDK 1.4 methods. (binarySearch, max, min, sort): Allow null comparator to represent natural ordering. (reverse(List)): Avoid unnecessary swap. (shuffle(List, Random)): Do shuffle in-place for RandomAccess lists. (SingletonList.get): Fix logic bug. (SingletonMap.entrySet): Make the entry immutable, and cache the returned set. (SynchronizedCollection, SynchronizedMap, UnmodifiableCollection), (UnmodifiableMap): Detect null pointer in construction. (SynchronizedMap, UnmodifiableMap): Cache collection views. * java/util/BasicMapEntry: Improve javadoc. From-SVN: r48035
This commit is contained in:
parent
def9790d51
commit
d9fd7154ec
27 changed files with 12307 additions and 6993 deletions
|
@ -1,4 +1,236 @@
|
|||
2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
|
||||
|
||||
* java/util/BitSet.java (and): Fix off-by-one bug, don't skip part of
|
||||
the bitset.
|
||||
(andNot): Likewise.
|
||||
(xor): Likewise.
|
||||
|
||||
2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
|
||||
|
||||
* java/util/LinkedList.java (LinkedListItr.add): Don't skip the next
|
||||
entry.
|
||||
|
||||
2001-12-15 Eric Blake <ebb9@email.byu.edu>
|
||||
|
||||
* java/util/TreeMap.java (removeNode): Fix bug in node removal.
|
||||
|
||||
2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
|
||||
|
||||
* java/util/AbstractCollection.java (containsAll): Use size of the
|
||||
correct collection for loop bound.
|
||||
* java/util/AbstractList.java (iterator.next): Increment pos after
|
||||
calling get on backing list.
|
||||
(listIterator.next): Likewise.
|
||||
* java/util/LinkedList.java (addLastEntry): Don't increment size before
|
||||
checking for size == 0.
|
||||
(addFirstEntry): Rearrange to match addLastEntry.
|
||||
(add): Do not increment size before inserting the new entry.
|
||||
|
||||
* java/util/AbstractCollection.java (addAll): Use size of the
|
||||
correct collection for loop bound.
|
||||
|
||||
2001-12-15 Bryce McKinlay <bryce@waitaki.otago.ac.nz>
|
||||
|
||||
* java/util/AbstractSet.java (removeAll): Fix scoping thinko.
|
||||
* java/util/HashMap.java (putAllInternal): Set size here.
|
||||
* java/util/Hashtable.java (putAllInternal): New method. Copy contents
|
||||
of a map efficiently without calling put() or putAll().
|
||||
(Hashtable (map)): Use putAllInternal.
|
||||
(clone): Likewise.
|
||||
|
||||
2001-12-15 Eric Blake <ebb9@email.byu.edu>
|
||||
|
||||
* java/util/Collections.java:
|
||||
* java/util/Vector.java:
|
||||
* java/util/WeakHashMap.java: Fix spelling errors.
|
||||
|
||||
2001-12-15 Eric Blake <ebb9@email.byu.edu>
|
||||
|
||||
* java/util/AbstractCollection.java (removeAllInternal),
|
||||
(retainAllInternal): Add hooks for use by ArrayList.
|
||||
* java/util/AbstractList.java: Minor code updates. Fix some
|
||||
scoping.
|
||||
* java/util/AbstractMap.java: ditto
|
||||
* java/util/ArrayList.java (readObject, writeObject): ditto
|
||||
(removeAllInternal, retainAllInternal): Optimize.
|
||||
* java/util/Arrays.java: ditto
|
||||
* java/util/Collections.java: ditto. Change order of parameters
|
||||
to equals(Object, Object) to match specs.
|
||||
* java/util/Dictionary.java: Improve javadoc.
|
||||
(Dictionary): Add explicit constructor.
|
||||
* java/util/HashMap.java: Improve javadoc. Rearrange methods to
|
||||
follow order in JDK. Cleanups related to recent code migration to
|
||||
AbstractMap. Fix some scoping.
|
||||
(entrySet): Cache the result.
|
||||
(modCount): Ensure that this is updated correctly.
|
||||
* java/util/HashSet.java: Improve javadoc. Fix some scoping.
|
||||
(init): Add hooks for LinkedHashSet.
|
||||
(map): Use "" instead of Boolean.TRUE in backing map. Use
|
||||
package-private API where possible for less overhead.
|
||||
(readObject, writeObject): Fix serialization.
|
||||
* java/util/Hashtable.java: Improve javadoc. Fix some scoping.
|
||||
(entrySet, keySet, values): Cache the result.
|
||||
(modCount): Ensure that this is updated correctly.
|
||||
(contains, remove): Fix NullPointer checking to match specs.
|
||||
(class Enumeration): Make more like HashIterator.
|
||||
* java/util/IdentityHashMap.java: Minor code updates.
|
||||
(modCount): Ensure that this is updated correctly.
|
||||
(readObject, writeObject): Fix serialization.
|
||||
* java/util/LinkedHashMap.java: Minor code updates. Cleanups
|
||||
related to recent code migration to AbstractMap.
|
||||
* java/util/LinkedHashSet.java: New file.
|
||||
* java/util/LinkedList.java:
|
||||
(readObject, writeObject): Fix serialization.
|
||||
* java/util/Makefile.am: List recently added files.
|
||||
* java/util/Stack.java: Minor code updates.
|
||||
* java/util/TreeMap.java: Improve javadoc. Overhaul the class to
|
||||
be more efficient. Fix some scoping. Rearrange the methods.
|
||||
(nil): Ensure that this can be thread-safe, and make it a static
|
||||
final. Initialize it to be more useful as a sentinal node.
|
||||
(Node): Specify color in constructor.
|
||||
(deleteFixup, insertFixup): Improve comments and algorithm.
|
||||
(fabricateTree): Redesign with less overhead.
|
||||
(lowestGreaterThan): Add parameter first to make SubMap easier.
|
||||
(removeNode): Patch hole where nil was being modified. Choose
|
||||
predecessor instead of successor so in-place swap works.
|
||||
(class VerifyResult, verifyTree, verifySub, verifyError): Remove
|
||||
this dead code after verifying the class works.
|
||||
(class SubMap): Rewrite several algorithms to avoid problems with
|
||||
comparing nil.
|
||||
* java/util/TreeSet.java: Improve javadoc. Fix some scoping.
|
||||
(clone): Fix ClassCastException when cloning subSet().
|
||||
(readObject, writeObject): Fix serialization.
|
||||
* java/util/WeakHashMap.java: Improve javadoc. Fix some scoping.
|
||||
(NULL_KEY): Make it compare as null, for ease elsewhere.
|
||||
(Class WeakEntry): Rename from Entry, to avoid shadowing
|
||||
Map.Entry. Add missing toString.
|
||||
(modCount): Ensure that this is updated correctly.
|
||||
(clear, containsValue, keySet, putAll, values, WeakHashMap(Map)):
|
||||
Add missing methods and constructor.
|
||||
|
||||
2001-12-15 Eric Blake <ebb9@email.byu.edu>
|
||||
|
||||
* java/util/ArrayList.java (checkBoundExclusive),
|
||||
(checkBoundInclusive): Rename from range??clusive, to match
|
||||
AbstractList.
|
||||
* java/util/LinkedList.java (checkBoundsExclusive),
|
||||
(checkBoundsInclusive): ditto
|
||||
* java/util/Vector.java (checkBoundExclusive),
|
||||
(checkBoundInclusive): Move bounds checking into common methods.
|
||||
|
||||
2001-12-15 Eric Blake <ebb9@email.byu.edu>
|
||||
|
||||
* java/util/AbstractList.java:
|
||||
(modCount): Make sure it is updated in all needed places.
|
||||
* java/util/ArrayList.java: Improve javadoc. Implements
|
||||
RandomAccess. Add serialVersionUID. Reorder methods.
|
||||
(modCount): Make sure it is updated in all needed places.
|
||||
(rangeExclusive, rangeInclusive): Add common methods for bounds
|
||||
check.
|
||||
(isEmpty): Add missing method.
|
||||
* java/util/Collections.java: (class SynchronizedList): Make
|
||||
package visible.
|
||||
* java/util/ConcurrentModificationException.java: Improve
|
||||
javadoc.
|
||||
* java/util/EmptyStackException.java: Improve javadoc.
|
||||
* java/util/LinkedList.java: Improve javadoc.
|
||||
(modCount): Make sure it is updated in all needed places.
|
||||
(rangeExclusive, rangeInclusive): Add common methods for bounds
|
||||
check.
|
||||
* java/util/NoSuchElementException.java: Improve javadoc.
|
||||
* java/util/Stack.java: Improve javadoc. Fix synchronization
|
||||
issues.
|
||||
(modCount): Make sure it is updated in all needed places.
|
||||
* java/util/Vector.java: Improve javadoc. Fix synchronization
|
||||
issues. Implements RandomAccess. Reorder methods.
|
||||
(modCount): Make sure it is updated in all needed places.
|
||||
(setSize): Fix according to specifications: this does not dictate
|
||||
the backing array size.
|
||||
(removeAll, retainAll): Faster implementations.
|
||||
|
||||
2001-12-15 Eric Blake <ebb9@email.byu.edu>
|
||||
|
||||
* java/util/BitSet.java: Improve javadoc.
|
||||
(cardinality(), clear(), clear(int, int), flip(int)),
|
||||
(flip(int, int), get(int, int), intersects(BitSet), isEmpty()),
|
||||
(nextClearBit(int), nextSetBit(int), set(int, boolean)),
|
||||
(set(int, int), set(int, int, boolean)): Add new JDK 1.4 methods.
|
||||
(clone): Fix so subclasses clone correctly.
|
||||
|
||||
2001-12-15 Eric Blake <ebb9@email.byu.edu>
|
||||
|
||||
* java/util/AbstractCollection.java: Improve javadoc.
|
||||
(AbstractCollection()): Make constructor protected.
|
||||
(equals(Object, Object), hashCode(Object)): Add utility methods.
|
||||
* java/util/AbstractList.java: Improve javadoc.
|
||||
(AbstractList()): Make constructor protected.
|
||||
(indexOf(Object)): Call listIterator(), not listIterator(int).
|
||||
(iterator()): Follow Sun's requirement to not use listIterator(0).
|
||||
(listIterator(int)): Make AbstractListItr anonymous.
|
||||
(subList(int, int)): Add support for RandomAccess.
|
||||
(SubList.add(int, Object), SubList.remove(Object)): Fix bug with
|
||||
modCount tracking.
|
||||
(SubList.addAll(Collection)): Add missing method.
|
||||
(SubList.listIterator(int)): Fix bugs in indexing, modCount
|
||||
tracking.
|
||||
(class RandomAccessSubList): Add new class.
|
||||
* java/util/AbstractMap.java: Improve javadoc.
|
||||
(keys, values, KEYS, VALUES, ENTRIES): Consolidate common map
|
||||
fields.
|
||||
(AbstractMap()): Make constructor protected.
|
||||
(equals(Object, Object), hashCode(Object)): Add utility methods.
|
||||
(equals(Object)): Change algorithm to
|
||||
entrySet().equals(m.entrySet()), as documented by Sun.
|
||||
(keySet(), values()): Cache the collections.
|
||||
* java/util/AbstractSequentialList.java: Improve javadoc.
|
||||
(AbstractSequentialList()): Make constructor protected.
|
||||
* java/util/AbstractSet.java: Improve javadoc.
|
||||
(AbstractSet()): Make constructor protected.
|
||||
(removeAll(Collection)): Add missing method.
|
||||
* java/util/Arrays.java: Improve javadoc, rearrange method orders.
|
||||
(defaultComparator): Remove, in favor of
|
||||
Collections.compare(Object, Object, Comparator).
|
||||
(binarySearch, equals, sort): Fix natural order comparison of
|
||||
floats and doubles. Also improve Object comparison - when
|
||||
comparator is null, use natural order.
|
||||
(fill, sort): Add missing checks for IllegalArgumentException.
|
||||
(sort, qsort): Fix sorting bugs, rework the code for more
|
||||
legibility.
|
||||
(mergeSort): Inline into sort(Object[], int, int, Comparator).
|
||||
(class ArrayList): Rename from ListImpl, and make compatible with
|
||||
JDK serialization. Add methods which more efficiently override
|
||||
those of AbstractList.
|
||||
* java/util/Collections: Improve javadoc.
|
||||
(isSequential(List)): Add and use a method for deciding between
|
||||
RandomAccess and sequential algorithms on lists.
|
||||
(class Empty*, class Synchronized*, class Unmodifiable*): Make
|
||||
compliant with JDK serializability.
|
||||
(class Singleton*, class CopiesList, class RevereseComparator),
|
||||
(class UnmodifiableMap.UnmodifiableEntrySet),
|
||||
(class *RandomAccessList): New classes for serial compatibility.
|
||||
(class Empty*, class Singleton*, class CopiesList): Add methods
|
||||
which more efficiently override those of Abstract*.
|
||||
(search): Inline into binarySearch(List, Object, Comparator).
|
||||
(binarySearch): Make sequential search only do log(n) comparisons,
|
||||
instead of n.
|
||||
(copy(List, List)): Do bounds checking before starting.
|
||||
(indexOfSubList, lastIndexOfSubList, list, replaceAll, rotate),
|
||||
(swap): Add new JDK 1.4 methods.
|
||||
(binarySearch, max, min, sort): Allow null comparator to represent
|
||||
natural ordering.
|
||||
(reverse(List)): Avoid unnecessary swap.
|
||||
(shuffle(List, Random)): Do shuffle in-place for RandomAccess
|
||||
lists.
|
||||
(SingletonList.get): Fix logic bug.
|
||||
(SingletonMap.entrySet): Make the entry immutable, and cache the
|
||||
returned set.
|
||||
(SynchronizedCollection, SynchronizedMap, UnmodifiableCollection),
|
||||
(UnmodifiableMap): Detect null pointer in construction.
|
||||
(SynchronizedMap, UnmodifiableMap): Cache collection views.
|
||||
* java/util/BasicMapEntry: Improve javadoc.
|
||||
|
||||
2001-12-14 Hans Boehm <Hans_Boehm@hp.com>
|
||||
|
||||
* libjava/prims.cc: Some old cleanups. The collector now
|
||||
handles test for out of memory.
|
||||
|
||||
|
|
|
@ -1200,6 +1200,7 @@ java/util/IdentityHashMap.java \
|
|||
java/util/Iterator.java \
|
||||
java/util/LinkedList.java \
|
||||
java/util/LinkedHashMap.java \
|
||||
java/util/LinkedHashSet.java \
|
||||
java/util/List.java \
|
||||
java/util/ListIterator.java \
|
||||
java/util/ListResourceBundle.java \
|
||||
|
|
|
@ -123,19 +123,13 @@ libgcj_basedir = @libgcj_basedir@
|
|||
mkinstalldirs = @mkinstalldirs@
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
@TESTSUBDIR_TRUE@SUBDIRS = \
|
||||
@TESTSUBDIR_TRUE@$(DIRLTDL) testsuite gcj include
|
||||
@TESTSUBDIR_FALSE@SUBDIRS = \
|
||||
@TESTSUBDIR_FALSE@$(DIRLTDL) gcj include
|
||||
@USE_LIBDIR_TRUE@toolexeclibdir = \
|
||||
@USE_LIBDIR_TRUE@$(libdir)$(MULTISUBDIR)
|
||||
@USE_LIBDIR_FALSE@toolexeclibdir = \
|
||||
@USE_LIBDIR_FALSE@$(toolexecdir)/lib$(MULTISUBDIR)
|
||||
@USE_LIBDIR_FALSE@toolexecdir = \
|
||||
@USE_LIBDIR_FALSE@$(exec_prefix)/$(target_alias)
|
||||
@XLIB_AWT_TRUE@cond_x_ltlibrary = \
|
||||
@XLIB_AWT_TRUE@libgcjx.la
|
||||
@XLIB_AWT_FALSE@cond_x_ltlibrary = \
|
||||
@TESTSUBDIR_TRUE@SUBDIRS = @TESTSUBDIR_TRUE@$(DIRLTDL) testsuite gcj include
|
||||
@TESTSUBDIR_FALSE@SUBDIRS = @TESTSUBDIR_FALSE@$(DIRLTDL) gcj include
|
||||
@USE_LIBDIR_TRUE@toolexeclibdir = @USE_LIBDIR_TRUE@$(libdir)$(MULTISUBDIR)
|
||||
@USE_LIBDIR_FALSE@toolexeclibdir = @USE_LIBDIR_FALSE@$(toolexecdir)/lib$(MULTISUBDIR)
|
||||
@USE_LIBDIR_FALSE@toolexecdir = @USE_LIBDIR_FALSE@$(exec_prefix)/$(target_alias)
|
||||
@XLIB_AWT_TRUE@cond_x_ltlibrary = @XLIB_AWT_TRUE@libgcjx.la
|
||||
@XLIB_AWT_FALSE@cond_x_ltlibrary =
|
||||
|
||||
toolexeclib_LTLIBRARIES = libgcj.la $(cond_x_ltlibrary)
|
||||
toolexeclib_DATA = libgcj.spec
|
||||
|
@ -143,20 +137,14 @@ data_DATA = libgcj.jar
|
|||
|
||||
secdir = $(libdir)/security
|
||||
|
||||
@NATIVE_TRUE@bin_PROGRAMS = \
|
||||
@NATIVE_TRUE@jv-convert gij rmic rmiregistry
|
||||
@NATIVE_TRUE@bin_PROGRAMS = @NATIVE_TRUE@jv-convert gij rmic rmiregistry
|
||||
|
||||
bin_SCRIPTS = addr2name.awk
|
||||
@CANADIAN_TRUE@@NULL_TARGET_TRUE@ZIP = \
|
||||
@CANADIAN_TRUE@@NULL_TARGET_TRUE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
|
||||
@CANADIAN_TRUE@@NULL_TARGET_FALSE@ZIP = \
|
||||
@CANADIAN_TRUE@@NULL_TARGET_FALSE@jar
|
||||
@CANADIAN_FALSE@ZIP = \
|
||||
@CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
|
||||
@CANADIAN_TRUE@GCJH = \
|
||||
@CANADIAN_TRUE@gcjh
|
||||
@CANADIAN_FALSE@GCJH = \
|
||||
@CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/gcc/gcjh$(EXEEXT)
|
||||
@CANADIAN_TRUE@@NULL_TARGET_TRUE@ZIP = @CANADIAN_TRUE@@NULL_TARGET_TRUE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
|
||||
@CANADIAN_TRUE@@NULL_TARGET_FALSE@ZIP = @CANADIAN_TRUE@@NULL_TARGET_FALSE@jar
|
||||
@CANADIAN_FALSE@ZIP = @CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
|
||||
@CANADIAN_TRUE@GCJH = @CANADIAN_TRUE@gcjh
|
||||
@CANADIAN_FALSE@GCJH = @CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/gcc/gcjh$(EXEEXT)
|
||||
|
||||
GCJ_WITH_FLAGS = $(GCJ) --encoding=UTF-8
|
||||
|
||||
|
@ -176,10 +164,8 @@ AM_CXXFLAGS = -fno-rtti -fnon-call-exceptions \
|
|||
@LIBGCJ_CXXFLAGS@ @X_CFLAGS@ $(WARNINGS) -D_GNU_SOURCE \
|
||||
-DPREFIX="\"$(prefix)\""
|
||||
|
||||
@USING_GCC_TRUE@AM_CFLAGS = \
|
||||
@USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS)
|
||||
@USING_GCC_FALSE@AM_CFLAGS = \
|
||||
@USING_GCC_FALSE@@LIBGCJ_CFLAGS@
|
||||
@USING_GCC_TRUE@AM_CFLAGS = @USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS)
|
||||
@USING_GCC_FALSE@AM_CFLAGS = @USING_GCC_FALSE@@LIBGCJ_CFLAGS@
|
||||
|
||||
JCFLAGS = -g
|
||||
JC1FLAGS = @LIBGCJ_JAVAFLAGS@ $(GCJFLAGS)
|
||||
|
@ -252,8 +238,7 @@ extra_headers = java/lang/Object.h java/lang/Class.h
|
|||
|
||||
NM = nm
|
||||
|
||||
@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = \
|
||||
@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS
|
||||
@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = @NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS
|
||||
|
||||
CONVERT_DIR = gnu/gcj/convert
|
||||
|
||||
|
@ -950,6 +935,7 @@ java/util/IdentityHashMap.java \
|
|||
java/util/Iterator.java \
|
||||
java/util/LinkedList.java \
|
||||
java/util/LinkedHashMap.java \
|
||||
java/util/LinkedHashSet.java \
|
||||
java/util/List.java \
|
||||
java/util/ListIterator.java \
|
||||
java/util/ListResourceBundle.java \
|
||||
|
@ -1585,7 +1571,7 @@ libgcj-test.spec.in libgcj.spec.in
|
|||
|
||||
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
|
||||
|
||||
TAR = tar
|
||||
TAR = gtar
|
||||
GZIP_ENV = --best
|
||||
DIST_SUBDIRS = @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include
|
||||
DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
|
||||
|
@ -2224,10 +2210,11 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \
|
|||
.deps/java/util/GregorianCalendar.P .deps/java/util/HashMap.P \
|
||||
.deps/java/util/HashSet.P .deps/java/util/Hashtable.P \
|
||||
.deps/java/util/IdentityHashMap.P .deps/java/util/Iterator.P \
|
||||
.deps/java/util/LinkedHashMap.P .deps/java/util/LinkedList.P \
|
||||
.deps/java/util/List.P .deps/java/util/ListIterator.P \
|
||||
.deps/java/util/ListResourceBundle.P .deps/java/util/Locale.P \
|
||||
.deps/java/util/Map.P .deps/java/util/MissingResourceException.P \
|
||||
.deps/java/util/LinkedHashMap.P .deps/java/util/LinkedHashSet.P \
|
||||
.deps/java/util/LinkedList.P .deps/java/util/List.P \
|
||||
.deps/java/util/ListIterator.P .deps/java/util/ListResourceBundle.P \
|
||||
.deps/java/util/Locale.P .deps/java/util/Map.P \
|
||||
.deps/java/util/MissingResourceException.P \
|
||||
.deps/java/util/NoSuchElementException.P .deps/java/util/Observable.P \
|
||||
.deps/java/util/Observer.P .deps/java/util/Properties.P \
|
||||
.deps/java/util/PropertyPermission.P \
|
||||
|
@ -2735,7 +2722,7 @@ distdir: $(DISTFILES)
|
|||
@for file in $(DISTFILES); do \
|
||||
d=$(srcdir); \
|
||||
if test -d $$d/$$file; then \
|
||||
cp -pr $$/$$file $(distdir)/$$file; \
|
||||
cp -pr $$d/$$file $(distdir)/$$file; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* AbstractCollection.java -- Abstract implementation of most of Collection
|
||||
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -42,74 +42,116 @@ import java.lang.reflect.Array;
|
|||
* backing data structure allows for a more efficient implementation. The
|
||||
* precise implementation used by AbstractCollection is documented, so that
|
||||
* subclasses can tell which methods could be implemented more efficiently.
|
||||
* <p>
|
||||
*
|
||||
* The programmer should provide a no-argument constructor, and one that
|
||||
* accepts another Collection, as recommended by the Collection interface.
|
||||
* Unfortunately, there is no way to enforce this in Java.
|
||||
*
|
||||
* @author Original author unknown
|
||||
* @author Bryce McKinlay
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Collection
|
||||
* @see AbstractSet
|
||||
* @see AbstractList
|
||||
* @since 1.2
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public abstract class AbstractCollection implements Collection
|
||||
{
|
||||
/**
|
||||
* The main constructor, for use by subclasses.
|
||||
*/
|
||||
protected AbstractCollection()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Iterator over this collection. The iterator must provide the
|
||||
* hasNext and next methods and should in addition provide remove if the
|
||||
* collection is modifiable.
|
||||
*
|
||||
* @return an iterator
|
||||
*/
|
||||
public abstract Iterator iterator();
|
||||
|
||||
/**
|
||||
* Return the number of elements in this collection.
|
||||
* Return the number of elements in this collection. If there are more than
|
||||
* Integer.MAX_VALUE elements, return Integer.MAX_VALUE.
|
||||
*
|
||||
* @return the size
|
||||
*/
|
||||
public abstract int size();
|
||||
|
||||
/**
|
||||
* Add an object to the collection. This implementation always throws an
|
||||
* UnsupportedOperationException - it should be overridden if the collection
|
||||
* is to be modifiable.
|
||||
* Add an object to the collection (optional operation). This implementation
|
||||
* always throws an UnsupportedOperationException - it should be
|
||||
* overridden if the collection is to be modifiable. If the collection
|
||||
* does not accept duplicates, simply return false. Collections may specify
|
||||
* limitations on what may be added.
|
||||
*
|
||||
* @param o the object to add
|
||||
* @return true if the add operation caused the Collection to change
|
||||
* @exception UnsupportedOperationException if the add operation is not
|
||||
* @throws UnsupportedOperationException if the add operation is not
|
||||
* supported on this collection
|
||||
* @throws NullPointerException if the collection does not support null
|
||||
* @throws ClassCastException if the object is of the wrong type
|
||||
* @throws IllegalArgumentException if some aspect of the object prevents
|
||||
* it from being added
|
||||
*/
|
||||
public boolean add(Object o)
|
||||
{
|
||||
throw new java.lang.UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all the elements of a given collection to this collection. This
|
||||
* implementation obtains an Iterator over the given collection and iterates
|
||||
* over it, adding each element with the add(Object) method (thus this method
|
||||
* will fail with an UnsupportedOperationException if the add method does).
|
||||
* Add all the elements of a given collection to this collection (optional
|
||||
* operation). This implementation obtains an Iterator over the given
|
||||
* collection and iterates over it, adding each element with the
|
||||
* add(Object) method (thus this method will fail with an
|
||||
* UnsupportedOperationException if the add method does). The behavior is
|
||||
* unspecified if the specified collection is modified during the iteration,
|
||||
* including the special case of trying addAll(this) on a non-empty
|
||||
* collection.
|
||||
*
|
||||
* @param c the collection to add the elements of to this collection
|
||||
* @return true if the add operation caused the Collection to change
|
||||
* @exception UnsupportedOperationException if the add operation is not
|
||||
* @throws UnsupportedOperationException if the add operation is not
|
||||
* supported on this collection
|
||||
* @throws NullPointerException if this collection does not support null,
|
||||
* or if the specified collection is null
|
||||
* @throws ClassCastException if an object in c is of the wrong type
|
||||
* @throws IllegalArgumentException if some aspect of an object in c prevents
|
||||
* it from being added
|
||||
* @see #add(Object)
|
||||
*/
|
||||
public boolean addAll(Collection c)
|
||||
{
|
||||
Iterator itr = c.iterator();
|
||||
int size = c.size();
|
||||
boolean modified = false;
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
int pos = c.size();
|
||||
while (--pos >= 0)
|
||||
modified |= add(itr.next());
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all elements from the collection. This implementation obtains an
|
||||
* iterator over the collection and calls next and remove on it repeatedly
|
||||
* (thus this method will fail with an UnsupportedOperationException if the
|
||||
* Iterator's remove method does) until there are no more elements to remove.
|
||||
* Remove all elements from the collection (optional operation). This
|
||||
* implementation obtains an iterator over the collection and calls next
|
||||
* and remove on it repeatedly (thus this method will fail with an
|
||||
* UnsupportedOperationException if the Iterator's remove method does)
|
||||
* until there are no more elements to remove.
|
||||
* Many implementations will have a faster way of doing this.
|
||||
*
|
||||
* @exception UnsupportedOperationException if the Iterator returned by
|
||||
* @throws UnsupportedOperationException if the Iterator returned by
|
||||
* iterator does not provide an implementation of remove
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
int size = size();
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
{
|
||||
itr.next();
|
||||
itr.remove();
|
||||
|
@ -130,12 +172,10 @@ public abstract class AbstractCollection implements Collection
|
|||
public boolean contains(Object o)
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
int size = size();
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
if (o == null ? itr.next() == null : o.equals(itr.next()))
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
if (equals(o, itr.next()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -148,16 +188,16 @@ public abstract class AbstractCollection implements Collection
|
|||
* @param c the collection to test against
|
||||
* @return true if this collection contains all the elements in the given
|
||||
* collection
|
||||
* @throws NullPointerException if the given collection is null
|
||||
* @see #contains(Object)
|
||||
*/
|
||||
public boolean containsAll(Collection c)
|
||||
{
|
||||
Iterator itr = c.iterator();
|
||||
int size = c.size();
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
int pos = c.size();
|
||||
while (--pos >= 0)
|
||||
if (!contains(itr.next()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -166,6 +206,7 @@ public abstract class AbstractCollection implements Collection
|
|||
* size() == 0.
|
||||
*
|
||||
* @return true if this collection is empty.
|
||||
* @see #size()
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
{
|
||||
|
@ -173,92 +214,131 @@ public abstract class AbstractCollection implements Collection
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove a single instance of an object from this collection. That is,
|
||||
* remove one element e such that (o == null ? e == null : o.equals(e)), if
|
||||
* such an element exists. This implementation obtains an iterator over the
|
||||
* collection and iterates over it, testing each element for equality with
|
||||
* the given object. If it is equal, it is removed by the iterator's remove
|
||||
* method (thus this method will fail with an UnsupportedOperationException
|
||||
* if the Iterator's remove method does). After the first element has been
|
||||
* Remove a single instance of an object from this collection (optional
|
||||
* operation). That is, remove one element e such that
|
||||
* <code>(o == null ? e == null : o.equals(e))</code>, if such an element
|
||||
* exists. This implementation obtains an iterator over the collection
|
||||
* and iterates over it, testing each element for equality with the given
|
||||
* object. If it is equal, it is removed by the iterator's remove method
|
||||
* (thus this method will fail with an UnsupportedOperationException if
|
||||
* the Iterator's remove method does). After the first element has been
|
||||
* removed, true is returned; if the end of the collection is reached, false
|
||||
* is returned.
|
||||
*
|
||||
* @param o the object to remove from this collection
|
||||
* @return true if the remove operation caused the Collection to change, or
|
||||
* equivalently if the collection did contain o.
|
||||
* @exception UnsupportedOperationException if this collection's Iterator
|
||||
* @throws UnsupportedOperationException if this collection's Iterator
|
||||
* does not support the remove method
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
int size = size();
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
if (o == null ? itr.next() == null : o.equals(itr.next()))
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
if (equals(o, itr.next()))
|
||||
{
|
||||
itr.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove from this collection all its elements that are contained in a given
|
||||
* collection. This implementation iterates over this collection, and for
|
||||
* each element tests if it is contained in the given collection. If so, it
|
||||
* is removed by the Iterator's remove method (thus this method will fail
|
||||
* with an UnsupportedOperationException if the Iterator's remove method
|
||||
* does).
|
||||
* collection (optional operation). This implementation iterates over this
|
||||
* collection, and for each element tests if it is contained in the given
|
||||
* collection. If so, it is removed by the Iterator's remove method (thus
|
||||
* this method will fail with an UnsupportedOperationException if the
|
||||
* Iterator's remove method does).
|
||||
*
|
||||
* @param c the collection to remove the elements of
|
||||
* @return true if the remove operation caused the Collection to change
|
||||
* @exception UnsupportedOperationException if this collection's Iterator
|
||||
* @throws UnsupportedOperationException if this collection's Iterator
|
||||
* does not support the remove method
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
public boolean removeAll(Collection c)
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
int size = size();
|
||||
boolean modified = false;
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
return removeAllInternal(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove from this collection all its elements that are contained in a given
|
||||
* collection (optional operation). This implementation iterates over this
|
||||
* collection, and for each element tests if it is contained in the given
|
||||
* collection. If so, it is removed by the Iterator's remove method (thus
|
||||
* this method will fail with an UnsupportedOperationException if the
|
||||
* Iterator's remove method does). This method is necessary for ArrayList,
|
||||
* which cannot publicly override removeAll but can optimize this call.
|
||||
*
|
||||
* @param c the collection to remove the elements of
|
||||
* @return true if the remove operation caused the Collection to change
|
||||
* @throws UnsupportedOperationException if this collection's Iterator
|
||||
* does not support the remove method
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
boolean removeAllInternal(Collection c)
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
boolean modified = false;
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
if (c.contains(itr.next()))
|
||||
{
|
||||
itr.remove();
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove from this collection all its elements that are not contained in a
|
||||
* given collection. This implementation iterates over this collection, and
|
||||
* for each element tests if it is contained in the given collection. If not,
|
||||
* it is removed by the Iterator's remove method (thus this method will fail
|
||||
* with an UnsupportedOperationException if the Iterator's remove method
|
||||
* does).
|
||||
* given collection (optional operation). This implementation iterates over
|
||||
* this collection, and for each element tests if it is contained in the
|
||||
* given collection. If not, it is removed by the Iterator's remove method
|
||||
* (thus this method will fail with an UnsupportedOperationException if
|
||||
* the Iterator's remove method does).
|
||||
*
|
||||
* @param c the collection to retain the elements of
|
||||
* @return true if the remove operation caused the Collection to change
|
||||
* @exception UnsupportedOperationException if this collection's Iterator
|
||||
* @throws UnsupportedOperationException if this collection's Iterator
|
||||
* does not support the remove method
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
public boolean retainAll(Collection c)
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
int size = size();
|
||||
boolean modified = false;
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
return retainAllInternal(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove from this collection all its elements that are not contained in a
|
||||
* given collection (optional operation). This implementation iterates over
|
||||
* this collection, and for each element tests if it is contained in the
|
||||
* given collection. If not, it is removed by the Iterator's remove method
|
||||
* (thus this method will fail with an UnsupportedOperationException if
|
||||
* the Iterator's remove method does). This method is necessary for
|
||||
* ArrayList, which cannot publicly override retainAll but can optimize
|
||||
* this call.
|
||||
*
|
||||
* @param c the collection to retain the elements of
|
||||
* @return true if the remove operation caused the Collection to change
|
||||
* @throws UnsupportedOperationException if this collection's Iterator
|
||||
* does not support the remove method
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
boolean retainAllInternal(Collection c)
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
boolean modified = false;
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
if (!c.contains(itr.next()))
|
||||
{
|
||||
itr.remove();
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
|
@ -266,18 +346,18 @@ public abstract class AbstractCollection implements Collection
|
|||
* Return an array containing the elements of this collection. This
|
||||
* implementation creates an Object array of size size() and then iterates
|
||||
* over the collection, setting each element of the array from the value
|
||||
* returned by the iterator.
|
||||
* returned by the iterator. The returned array is safe, and is not backed
|
||||
* by the collection.
|
||||
*
|
||||
* @return an array containing the elements of this collection
|
||||
*/
|
||||
public Object[] toArray()
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
Object[]a = new Object[size()];
|
||||
for (int pos = 0; pos < a.length; pos++)
|
||||
{
|
||||
int size = size();
|
||||
Object[] a = new Object[size];
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
a[pos] = itr.next();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
@ -293,29 +373,29 @@ public abstract class AbstractCollection implements Collection
|
|||
* obtained over the collection and the elements are placed in the array as
|
||||
* they are returned by the iterator. Finally the first spare element, if
|
||||
* any, of the array is set to null, and the created array is returned.
|
||||
* The returned array is safe; it is not backed by the collection. Note that
|
||||
* null may not mark the last element, if the collection allows null
|
||||
* elements.
|
||||
*
|
||||
* @param a the array to copy into, or of the correct run-time type
|
||||
* @return the array that was produced
|
||||
* @exception ClassCastException if the type of the array precludes holding
|
||||
* @throws NullPointerException if the given array is null
|
||||
* @throws ArrayStoreException if the type of the array precludes holding
|
||||
* one of the elements of the Collection
|
||||
*/
|
||||
public Object[] toArray(Object[] a)
|
||||
{
|
||||
int size = size();
|
||||
if (a.length < size)
|
||||
{
|
||||
a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
|
||||
size);
|
||||
}
|
||||
else if (a.length > size)
|
||||
a[size] = null;
|
||||
|
||||
Iterator itr = iterator();
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
a[pos] = itr.next();
|
||||
}
|
||||
if (a.length > size)
|
||||
{
|
||||
a[size] = null;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
@ -331,15 +411,41 @@ public abstract class AbstractCollection implements Collection
|
|||
public String toString()
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
int size = size();
|
||||
StringBuffer r = new StringBuffer("[");
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
for (int pos = size(); pos > 0; pos--)
|
||||
{
|
||||
r.append(itr.next());
|
||||
if (pos < size - 1)
|
||||
if (pos > 1)
|
||||
r.append(", ");
|
||||
}
|
||||
r.append("]");
|
||||
return r.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two objects according to Collection semantics.
|
||||
*
|
||||
* @param o1 the first object
|
||||
* @param o2 the second object
|
||||
* @return o1 == null ? o2 == null : o1.equals(o2)
|
||||
*/
|
||||
// Package visible for use throughout java.util.
|
||||
// It may be inlined since it is final.
|
||||
static final boolean equals(Object o1, Object o2)
|
||||
{
|
||||
return o1 == null ? o2 == null : o1.equals(o2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash an object according to Collection semantics.
|
||||
*
|
||||
* @param o the object to hash
|
||||
* @return o1 == null ? 0 : o1.hashCode()
|
||||
*/
|
||||
// Package visible for use throughout java.util.
|
||||
// It may be inlined since it is final.
|
||||
static final int hashCode(Object o)
|
||||
{
|
||||
return o == null ? 0 : o.hashCode();
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
/* AbstractMap.java -- Abstract implementation of most of Map
|
||||
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -25,22 +25,71 @@ This exception does not however invalidate any other reasons why the
|
|||
executable file might be covered by the GNU General Public License. */
|
||||
|
||||
|
||||
// TO DO:
|
||||
// comments
|
||||
// test suite
|
||||
|
||||
package java.util;
|
||||
|
||||
/**
|
||||
* An abstract implementation of Map to make it easier to create your own
|
||||
* implementations. In order to create an unmodifiable Map, subclass
|
||||
* AbstractMap and implement the <code>entrySet</code> (usually via an
|
||||
* AbstractSet). To make it modifiable, also implement <code>put</code>,
|
||||
* and have <code>entrySet().iterator()</code> support <code>remove</code>.
|
||||
* <p>
|
||||
*
|
||||
* It is recommended that classes which extend this support at least the
|
||||
* no-argument constructor, and a constructor which accepts another Map.
|
||||
* Further methods in this class may be overridden if you have a more
|
||||
* efficient implementation.
|
||||
*
|
||||
* @author Original author unknown
|
||||
* @author Bryce McKinlay
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Map
|
||||
* @see Collection
|
||||
* @see HashMap
|
||||
* @see LinkedHashMap
|
||||
* @see TreeMap
|
||||
* @see WeakHashMap
|
||||
* @see IdentityHashMap
|
||||
* @since 1.2
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public abstract class AbstractMap implements Map
|
||||
{
|
||||
/** An "enum" of iterator types. */
|
||||
// Package visible for use by subclasses.
|
||||
static final int KEYS = 0,
|
||||
VALUES = 1,
|
||||
ENTRIES = 2;
|
||||
|
||||
/**
|
||||
* Remove all entries from this Map. This default implementation calls
|
||||
* entrySet().clear().
|
||||
* The cache for {@link #keySet()}.
|
||||
*/
|
||||
// Package visible for use by subclasses.
|
||||
Set keys;
|
||||
|
||||
/**
|
||||
* The cache for {@link #values()}.
|
||||
*/
|
||||
// Package visible for use by subclasses.
|
||||
Collection values;
|
||||
|
||||
/**
|
||||
* The main constructor, for use by subclasses.
|
||||
*/
|
||||
protected AbstractMap()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all entries from this Map (optional operation). This default
|
||||
* implementation calls entrySet().clear(). NOTE: If the entry set does
|
||||
* not permit clearing, then this will fail, too. Subclasses often
|
||||
* override this for efficiency. Your implementation of entrySet() should
|
||||
* not call <code>AbstractMap.clear</code> unless you want an infinite loop.
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* @specnote The JCL book claims that this implementation always throws
|
||||
* UnsupportedOperationException, while the online docs claim it
|
||||
* calls entrySet().clear(). We take the later to be correct.
|
||||
* @throws UnsupportedOperationException if <code>entrySet().clear()</code>
|
||||
* does not support clearing.
|
||||
* @see Set#clear()
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
|
@ -48,107 +97,174 @@ public abstract class AbstractMap implements Map
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a shallow copy of this Map, no keys or values are copied.
|
||||
* Create a shallow copy of this Map, no keys or values are copied. The
|
||||
* default implementation simply calls <code>super.clone()</code>.
|
||||
*
|
||||
* @return the shallow clone
|
||||
* @throws CloneNotSupportedException if a subclass is not Cloneable
|
||||
* @see Cloneable
|
||||
* @see Object#clone()
|
||||
*/
|
||||
protected Object clone() throws CloneNotSupportedException
|
||||
{
|
||||
return super.clone ();
|
||||
AbstractMap copy = (AbstractMap) super.clone();
|
||||
// Clear out the caches; they are stale.
|
||||
copy.keys = null;
|
||||
copy.values = null;
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this contains a mapping for the given key. This
|
||||
* implementation does a linear search, O(n), over the
|
||||
* <code>entrySet()</code>, returning <code>true</code> if a match
|
||||
* is found, <code>false</code> if the iteration ends. Many subclasses
|
||||
* can implement this more efficiently.
|
||||
*
|
||||
* @param key the key to search for
|
||||
* @return true if the map contains the key
|
||||
* @throws NullPointerException if key is <code>null</code> but the map
|
||||
* does not permit null keys
|
||||
* @see #containsValue(Object)
|
||||
*/
|
||||
public boolean containsKey(Object key)
|
||||
{
|
||||
Object k;
|
||||
Set es = entrySet();
|
||||
Iterator entries = es.iterator();
|
||||
int size = size();
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
k = ((Map.Entry) entries.next()).getKey();
|
||||
if (key == null ? k == null : key.equals(k))
|
||||
Iterator entries = entrySet().iterator();
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
if (equals(key, ((Map.Entry) entries.next()).getKey()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this contains at least one mapping with the given value.
|
||||
* This implementation does a linear search, O(n), over the
|
||||
* <code>entrySet()</code>, returning <code>true</code> if a match
|
||||
* is found, <code>false</code> if the iteration ends. A match is
|
||||
* defined as <code>(value == null ? v == null : value.equals(v))</code>
|
||||
* Subclasses are unlikely to implement this more efficiently.
|
||||
*
|
||||
* @param value the value to search for
|
||||
* @return true if the map contains the value
|
||||
* @see #containsKey(Object)
|
||||
*/
|
||||
public boolean containsValue(Object value)
|
||||
{
|
||||
Object v;
|
||||
Set es = entrySet();
|
||||
Iterator entries = es.iterator();
|
||||
int size = size();
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
v = ((Map.Entry) entries.next()).getValue();
|
||||
if (value == null ? v == null : value.equals(v))
|
||||
Iterator entries = entrySet().iterator();
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
if (equals(value, ((Map.Entry) entries.next()).getValue()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set view of the mappings in this Map. Each element in the
|
||||
* set must be an implementation of Map.Entry. The set is backed by
|
||||
* the map, so that changes in one show up in the other. Modifications
|
||||
* made while an iterator is in progress cause undefined behavior. If
|
||||
* the set supports removal, these methods must be valid:
|
||||
* <code>Iterator.remove</code>, <code>Set.remove</code>,
|
||||
* <code>removeAll</code>, <code>retainAll</code>, and <code>clear</code>.
|
||||
* Element addition is not supported via this set.
|
||||
*
|
||||
* @return the entry set
|
||||
* @see Map.Entry
|
||||
*/
|
||||
public abstract Set entrySet();
|
||||
|
||||
/**
|
||||
* Compares the specified object with this map for equality. Returns
|
||||
* <code>true</code> if the other object is a Map with the same mappings,
|
||||
* that is,<br>
|
||||
* <code>o instanceof Map && entrySet().equals(((Map) o).entrySet();</code>
|
||||
*
|
||||
* @param o the object to be compared
|
||||
* @return true if the object equals this map
|
||||
* @see Set#equals(Object)
|
||||
*/
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o == this)
|
||||
return true;
|
||||
if (!(o instanceof Map))
|
||||
return false;
|
||||
|
||||
Map m = (Map) o;
|
||||
Set s = m.entrySet();
|
||||
Iterator itr = entrySet().iterator();
|
||||
int size = size();
|
||||
|
||||
if (m.size() != size)
|
||||
return false;
|
||||
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
if (!s.contains(itr.next()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return (o == this ||
|
||||
(o instanceof Map &&
|
||||
entrySet().equals(((Map) o).entrySet())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value mapped by the given key. Returns <code>null</code> if
|
||||
* there is no mapping. However, in Maps that accept null values, you
|
||||
* must rely on <code>containsKey</code> to determine if a mapping exists.
|
||||
* This iteration takes linear time, searching entrySet().iterator() of
|
||||
* the key. Many implementations override this method.
|
||||
*
|
||||
* @param key the key to look up
|
||||
* @return the value associated with the key, or null if key not in map
|
||||
* @throws NullPointerException if this map does not accept null keys
|
||||
* @see #containsKey(Object)
|
||||
*/
|
||||
public Object get(Object key)
|
||||
{
|
||||
Set s = entrySet();
|
||||
Iterator entries = s.iterator();
|
||||
int size = size();
|
||||
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
Iterator entries = entrySet().iterator();
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
{
|
||||
Map.Entry entry = (Map.Entry) entries.next();
|
||||
Object k = entry.getKey();
|
||||
if (key == null ? k == null : key.equals(k))
|
||||
if (equals(key, entry.getKey()))
|
||||
return entry.getValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code for this map. As defined in Map, this is the sum
|
||||
* of all hashcodes for each Map.Entry object in entrySet, or basically
|
||||
* entrySet().hashCode().
|
||||
*
|
||||
* @return the hash code
|
||||
* @see Map.Entry#hashCode()
|
||||
* @see Set#hashCode()
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
int hashcode = 0;
|
||||
Iterator itr = entrySet().iterator();
|
||||
int size = size();
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
hashcode += itr.next().hashCode();
|
||||
}
|
||||
return hashcode;
|
||||
return entrySet().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the map contains no mappings. This is implemented by
|
||||
* <code>size() == 0</code>.
|
||||
*
|
||||
* @return true if the map is empty
|
||||
* @see #size()
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set view of this map's keys. The set is backed by the map,
|
||||
* so changes in one show up in the other. Modifications while an iteration
|
||||
* is in progress produce undefined behavior. The set supports removal
|
||||
* if entrySet() does, but does not support element addition.
|
||||
* <p>
|
||||
*
|
||||
* This implementation creates an AbstractSet, where the iterator wraps
|
||||
* the entrySet iterator, size defers to the Map's size, and contains
|
||||
* defers to the Map's containsKey. The set is created on first use, and
|
||||
* returned on subsequent uses, although since no synchronization occurs,
|
||||
* there is a slight possibility of creating two sets.
|
||||
*
|
||||
* @return a Set view of the keys
|
||||
* @see Set#iterator()
|
||||
* @see #size()
|
||||
* @see #containsKey(Object)
|
||||
* @see #values()
|
||||
*/
|
||||
public Set keySet()
|
||||
{
|
||||
if (this.keySet == null)
|
||||
{
|
||||
this.keySet = new AbstractSet()
|
||||
if (keys == null)
|
||||
keys = new AbstractSet()
|
||||
{
|
||||
public int size()
|
||||
{
|
||||
|
@ -157,14 +273,14 @@ public abstract class AbstractMap implements Map
|
|||
|
||||
public boolean contains(Object key)
|
||||
{
|
||||
return AbstractMap.this.containsKey(key);
|
||||
return containsKey(key);
|
||||
}
|
||||
|
||||
public Iterator iterator()
|
||||
{
|
||||
return new Iterator()
|
||||
{
|
||||
Iterator map_iterator = AbstractMap.this.entrySet().iterator();
|
||||
private final Iterator map_iterator = entrySet().iterator();
|
||||
|
||||
public boolean hasNext()
|
||||
{
|
||||
|
@ -183,77 +299,156 @@ public abstract class AbstractMap implements Map
|
|||
};
|
||||
}
|
||||
};
|
||||
return keys;
|
||||
}
|
||||
|
||||
return this.keySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the given key to the given value (optional operation). If the
|
||||
* map already contains the key, its value is replaced. This implementation
|
||||
* simply throws an UnsupportedOperationException. Be aware that in a map
|
||||
* that permits <code>null</code> values, a null return does not always
|
||||
* imply that the mapping was created.
|
||||
*
|
||||
* @param key the key to map
|
||||
* @param value the value to be mapped
|
||||
* @return the previous value of the key, or null if there was no mapping
|
||||
* @throws UnsupportedOperationException if the operation is not supported
|
||||
* @throws ClassCastException if the key or value is of the wrong type
|
||||
* @throws IllegalArgumentException if something about this key or value
|
||||
* prevents it from existing in this map
|
||||
* @throws NullPointerException if the map forbids null keys or values
|
||||
* @see #containsKey(Object)
|
||||
*/
|
||||
public Object put(Object key, Object value)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all entries of the given map to this one (optional operation). If
|
||||
* the map already contains a key, its value is replaced. This implementation
|
||||
* simply iterates over the map's entrySet(), calling <code>put</code>,
|
||||
* so it is not supported if puts are not.
|
||||
*
|
||||
* @param m the mapping to load into this map
|
||||
* @throws UnsupportedOperationException if the operation is not supported
|
||||
* @throws ClassCastException if a key or value is of the wrong type
|
||||
* @throws IllegalArgumentException if something about a key or value
|
||||
* prevents it from existing in this map
|
||||
* @throws NullPointerException if the map forbids null keys or values, or
|
||||
* if <code>m</code> is null.
|
||||
* @see #put(Object, Object)
|
||||
*/
|
||||
public void putAll(Map m)
|
||||
{
|
||||
Map.Entry entry;
|
||||
Iterator entries = m.entrySet().iterator();
|
||||
int size = m.size();
|
||||
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
{
|
||||
entry = (Map.Entry) entries.next();
|
||||
Map.Entry entry = (Map.Entry) entries.next();
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the mapping for this key if present (optional operation). This
|
||||
* implementation iterates over the entrySet searching for a matching
|
||||
* key, at which point it calls the iterator's <code>remove</code> method.
|
||||
* It returns the result of <code>getValue()</code> on the entry, if found,
|
||||
* or null if no entry is found. Note that maps which permit null values
|
||||
* may also return null if the key was removed. If the entrySet does not
|
||||
* support removal, this will also fail. This is O(n), so many
|
||||
* implementations override it for efficiency.
|
||||
*
|
||||
* @param key the key to remove
|
||||
* @return the value the key mapped to, or null if not present
|
||||
* @throws UnsupportedOperationException if deletion is unsupported
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
public Object remove(Object key)
|
||||
{
|
||||
Iterator entries = entrySet().iterator();
|
||||
int size = size();
|
||||
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
{
|
||||
Map.Entry entry = (Map.Entry) entries.next();
|
||||
Object k = entry.getKey();
|
||||
if (key == null ? k == null : key.equals(k))
|
||||
if (equals(key, entry.getKey()))
|
||||
{
|
||||
Object value = entry.getValue();
|
||||
// Must get the value before we remove it from iterator.
|
||||
Object r = entry.getValue();
|
||||
entries.remove();
|
||||
return value;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of key-value mappings in the map. If there are more
|
||||
* than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. This is
|
||||
* implemented as <code>entrySet().size()</code>.
|
||||
*
|
||||
* @return the number of mappings
|
||||
* @see Set#size()
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return entrySet().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String representation of this map. This is a listing of the
|
||||
* map entries (which are specified in Map.Entry as being
|
||||
* <code>getKey() + "=" + getValue()</code>), separated by a comma and
|
||||
* space (", "), and surrounded by braces ('{' and '}'). This implementation
|
||||
* uses a StringBuffer and iterates over the entrySet to build the String.
|
||||
* Note that this can fail with an exception if underlying keys or
|
||||
* values complete abruptly in toString().
|
||||
*
|
||||
* @return a String representation
|
||||
* @see Map.Entry#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
Iterator entries = entrySet().iterator();
|
||||
int size = size();
|
||||
StringBuffer r = new StringBuffer("{");
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
for (int pos = size(); pos > 0; pos--)
|
||||
{
|
||||
// Append the toString value of the entries rather than calling
|
||||
// getKey/getValue. This is more efficient and it matches the JDK
|
||||
// behaviour.
|
||||
r.append(entries.next());
|
||||
if (pos < size - 1)
|
||||
if (pos > 1)
|
||||
r.append(", ");
|
||||
}
|
||||
r.append("}");
|
||||
return r.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection or bag view of this map's values. The collection
|
||||
* is backed by the map, so changes in one show up in the other.
|
||||
* Modifications while an iteration is in progress produce undefined
|
||||
* behavior. The collection supports removal if entrySet() does, but
|
||||
* does not support element addition.
|
||||
* <p>
|
||||
*
|
||||
* This implementation creates an AbstractCollection, where the iterator
|
||||
* wraps the entrySet iterator, size defers to the Map's size, and contains
|
||||
* defers to the Map's containsValue. The collection is created on first
|
||||
* use, and returned on subsequent uses, although since no synchronization
|
||||
* occurs, there is a slight possibility of creating two collections.
|
||||
*
|
||||
* @return a Collection view of the values
|
||||
* @see Collection#iterator()
|
||||
* @see #size()
|
||||
* @see #containsValue(Object)
|
||||
* @see #keySet()
|
||||
*/
|
||||
public Collection values()
|
||||
{
|
||||
if (this.valueCollection == null)
|
||||
{
|
||||
this.valueCollection = new AbstractCollection()
|
||||
if (values == null)
|
||||
values = new AbstractCollection()
|
||||
{
|
||||
public int size()
|
||||
{
|
||||
|
@ -264,7 +459,7 @@ public abstract class AbstractMap implements Map
|
|||
{
|
||||
return new Iterator()
|
||||
{
|
||||
Iterator map_iterator = AbstractMap.this.entrySet().iterator();
|
||||
private final Iterator map_iterator = entrySet().iterator();
|
||||
|
||||
public boolean hasNext()
|
||||
{
|
||||
|
@ -283,11 +478,33 @@ public abstract class AbstractMap implements Map
|
|||
};
|
||||
}
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
return this.valueCollection;
|
||||
/**
|
||||
* Compare two objects according to Collection semantics.
|
||||
*
|
||||
* @param o1 the first object
|
||||
* @param o2 the second object
|
||||
* @return o1 == null ? o2 == null : o1.equals(o2)
|
||||
*/
|
||||
// Package visible for use throughout java.util.
|
||||
// It may be inlined since it is final.
|
||||
static final boolean equals(Object o1, Object o2)
|
||||
{
|
||||
return o1 == null ? o2 == null : o1.equals(o2);
|
||||
}
|
||||
|
||||
private Collection valueCollection = null;
|
||||
private Set keySet = null;
|
||||
/**
|
||||
* Hash an object according to Collection semantics.
|
||||
*
|
||||
* @param o the object to hash
|
||||
* @return o1 == null ? 0 : o1.hashCode()
|
||||
*/
|
||||
// Package visible for use throughout java.util.
|
||||
// It may be inlined since it is final.
|
||||
static final int hashCode(Object o)
|
||||
{
|
||||
return o == null ? 0 : o.hashCode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* AbstractSequentialList.java -- List implementation for sequential access
|
||||
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -25,100 +25,192 @@ This exception does not however invalidate any other reasons why the
|
|||
executable file might be covered by the GNU General Public License. */
|
||||
|
||||
|
||||
// TO DO:
|
||||
// ~ Lots of doc comments still missing.
|
||||
// ~ The class comment should include a description of what should be overridden
|
||||
// to provide what features, as should the listIterator comment.
|
||||
|
||||
package java.util;
|
||||
|
||||
/**
|
||||
* Abstract superclass to make it easier to implement the List interface when
|
||||
* backed by a sequential-access store, such as a linked list.
|
||||
* backed by a sequential-access store, such as a linked list. For random
|
||||
* access data, use AbstractList. This class implements the random access
|
||||
* methods (<code>get</code>, <code>set</code>, <code>add</code>, and
|
||||
* <code>remove</code>) atop the list iterator, opposite of AbstractList's
|
||||
* approach of implementing the iterator atop random access.
|
||||
* <p>
|
||||
*
|
||||
* To implement a list, you need an implementation for <code>size()</code>
|
||||
* and <code>listIterator</code>. With just <code>hasNext</code>,
|
||||
* <code>next</code>, <code>hasPrevious</code>, <code>previous</code>,
|
||||
* <code>nextIndex</code>, and <code>previousIndex</code>, you have an
|
||||
* unmodifiable list. For a modifiable one, add <code>set</code>, and for
|
||||
* a variable-size list, add <code>add</code> and <code>remove</code>.
|
||||
* <p>
|
||||
*
|
||||
* The programmer should provide a no-argument constructor, and one that
|
||||
* accepts another Collection, as recommended by the Collection interface.
|
||||
* Unfortunately, there is no way to enforce this in Java.
|
||||
*
|
||||
* @author Original author unknown
|
||||
* @author Bryce McKinlay
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Collection
|
||||
* @see List
|
||||
* @see AbstractList
|
||||
* @see AbstractCollection
|
||||
* @see ListIterator
|
||||
* @see LinkedList
|
||||
* @since 1.2
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public abstract class AbstractSequentialList extends AbstractList
|
||||
{
|
||||
/**
|
||||
* The main constructor, for use by subclasses.
|
||||
*/
|
||||
protected AbstractSequentialList()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ListIterator over the list, starting from position index.
|
||||
* Subclasses must provide an implementation of this method.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if index < 0 || index > size()
|
||||
* @param index the starting position of the list
|
||||
* @return the list iterator
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||||
*/
|
||||
public abstract ListIterator listIterator(int index);
|
||||
|
||||
/**
|
||||
* Add an element to the list at a given index. This implementation obtains a
|
||||
* ListIterator positioned at the specified index, and then adds the element
|
||||
* using the ListIterator's add method.
|
||||
* Insert an element into the list at a given position (optional operation).
|
||||
* This shifts all existing elements from that position to the end one
|
||||
* index to the right. This version of add has no return, since it is
|
||||
* assumed to always succeed if there is no exception. This iteration
|
||||
* uses listIterator(index).add(o).
|
||||
*
|
||||
* @param index the position to add the element
|
||||
* @param o the element to insert
|
||||
* @exception IndexOutOfBoundsException if index < 0 || index > size()
|
||||
* @exception UnsupportedOperationException if the iterator returned by
|
||||
* listIterator(index) does not support the add method.
|
||||
* @param index the location to insert the item
|
||||
* @param o the object to insert
|
||||
* @throws UnsupportedOperationException if this list does not support the
|
||||
* add operation
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||||
* @throws ClassCastException if o cannot be added to this list due to its
|
||||
* type
|
||||
* @throws IllegalArgumentException if o cannot be added to this list for
|
||||
* some other reason
|
||||
*/
|
||||
public void add(int index, Object o)
|
||||
{
|
||||
ListIterator i = listIterator(index);
|
||||
i.add(o);
|
||||
listIterator(index).add(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* @specnote The spec in the JDK1.3 online docs is wrong. The implementation
|
||||
* should not call next() to skip over new elements as they are
|
||||
* added, because iterator.add() should add new elements BEFORE
|
||||
* the cursor.
|
||||
* Insert the contents of a collection into the list at a given position
|
||||
* (optional operation). Shift all elements at that position to the right
|
||||
* by the number of elements inserted. This operation is undefined if
|
||||
* this list is modified during the operation (for example, if you try
|
||||
* to insert a list into itself).
|
||||
* <p>
|
||||
*
|
||||
* This implementation grabs listIterator(index), then proceeds to use add
|
||||
* for each element returned by c's iterator. Sun's online specs are wrong,
|
||||
* claiming that this also calls next(): listIterator.add() correctly
|
||||
* skips the added element.
|
||||
*
|
||||
* @param index the location to insert the collection
|
||||
* @param c the collection to insert
|
||||
* @return true if the list was modified by this action, that is, if c is
|
||||
* non-empty
|
||||
* @throws UnsupportedOperationException if this list does not support the
|
||||
* addAll operation
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||||
* @throws ClassCastException if some element of c cannot be added to this
|
||||
* list due to its type
|
||||
* @throws IllegalArgumentException if some element of c cannot be added
|
||||
* to this list for some other reason
|
||||
* @throws NullPointerException if the specified collection is null
|
||||
* @see #add(int, Object)
|
||||
*/
|
||||
public boolean addAll(int index, Collection c)
|
||||
{
|
||||
boolean modified = false;
|
||||
Iterator ci = c.iterator();
|
||||
int size = c.size();
|
||||
ListIterator i = listIterator(index);
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
for (int pos = size; pos > 0; pos--)
|
||||
i.add(ci.next());
|
||||
}
|
||||
return (size > 0);
|
||||
}
|
||||
|
||||
public Object get(int index)
|
||||
{
|
||||
ListIterator i = listIterator(index);
|
||||
if (index < 0 || index > size())
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size());
|
||||
return i.next();
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Iterator over this List. This implementation returns
|
||||
* listIterator().
|
||||
* Get the element at a given index in this list. This implementation
|
||||
* returns listIterator(index).next().
|
||||
*
|
||||
* @return an Iterator over this List
|
||||
* @param index the index of the element to be returned
|
||||
* @return the element at index index in this list
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||||
*/
|
||||
public Object get(int index)
|
||||
{
|
||||
// This is a legal listIterator position, but an illegal get.
|
||||
if (index == size())
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
|
||||
+ size());
|
||||
return listIterator(index).next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain an Iterator over this list, whose sequence is the list order. This
|
||||
* implementation returns listIterator().
|
||||
*
|
||||
* @return an Iterator over the elements of this list, in order
|
||||
*/
|
||||
public Iterator iterator()
|
||||
{
|
||||
return listIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the element at a given position in this list (optional operation).
|
||||
* Shifts all remaining elements to the left to fill the gap. This
|
||||
* implementation uses listIterator(index) and ListIterator.remove().
|
||||
*
|
||||
* @param index the position within the list of the object to remove
|
||||
* @return the object that was removed
|
||||
* @throws UnsupportedOperationException if this list does not support the
|
||||
* remove operation
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||||
*/
|
||||
public Object remove(int index)
|
||||
{
|
||||
// This is a legal listIterator position, but an illegal remove.
|
||||
if (index == size())
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
|
||||
+ size());
|
||||
ListIterator i = listIterator(index);
|
||||
if (index < 0 || index > size())
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size());
|
||||
Object removed = i.next();
|
||||
i.remove();
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace an element of this list with another object (optional operation).
|
||||
* This implementation uses listIterator(index) and ListIterator.set(o).
|
||||
*
|
||||
* @param index the position within this list of the element to be replaced
|
||||
* @param o the object to replace it with
|
||||
* @return the object that was replaced
|
||||
* @throws UnsupportedOperationException if this list does not support the
|
||||
* set operation
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||||
* @throws ClassCastException if o cannot be added to this list due to its
|
||||
* type
|
||||
* @throws IllegalArgumentException if o cannot be added to this list for
|
||||
* some other reason
|
||||
*/
|
||||
public Object set(int index, Object o)
|
||||
{
|
||||
// This is a legal listIterator position, but an illegal set.
|
||||
if (index == size())
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
|
||||
+ size());
|
||||
ListIterator i = listIterator(index);
|
||||
if (index < 0 || index > size())
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size());
|
||||
Object old = i.next();
|
||||
i.set(o);
|
||||
return old;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* AbstractSet.java -- Abstract implementation of most of Set
|
||||
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -35,9 +35,27 @@ package java.util;
|
|||
* on them - specifically, no element may be in the set more than once). This
|
||||
* class simply provides implementations of equals() and hashCode() to fulfil
|
||||
* the requirements placed on them by the Set interface.
|
||||
*
|
||||
* @author Original author unknown
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Collection
|
||||
* @see AbstractCollection
|
||||
* @see Set
|
||||
* @see HashSet
|
||||
* @see TreeSet
|
||||
* @see LinkedHashSet
|
||||
* @since 1.2
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public abstract class AbstractSet extends AbstractCollection implements Set
|
||||
{
|
||||
/**
|
||||
* The main constructor, for use by subclasses.
|
||||
*/
|
||||
protected AbstractSet()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the given object is equal to this Set. This implementation
|
||||
* first checks whether this set <em>is</em> the given object, and returns
|
||||
|
@ -50,12 +68,9 @@ public abstract class AbstractSet extends AbstractCollection implements Set
|
|||
*/
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o == this)
|
||||
return true;
|
||||
else if (o instanceof Set && ((Set) o).size() == size())
|
||||
return containsAll((Collection) o);
|
||||
else
|
||||
return false;
|
||||
return (o == this ||
|
||||
(o instanceof Set && ((Set) o).size() == size()
|
||||
&& containsAll((Collection) o)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,14 +84,45 @@ public abstract class AbstractSet extends AbstractCollection implements Set
|
|||
public int hashCode()
|
||||
{
|
||||
Iterator itr = iterator();
|
||||
int size = size();
|
||||
int hash = 0;
|
||||
for (int pos = 0; pos < size; pos++)
|
||||
{
|
||||
Object obj = itr.next();
|
||||
if (obj != null)
|
||||
hash += obj.hashCode();
|
||||
}
|
||||
int pos = size();
|
||||
while (--pos >= 0)
|
||||
hash += hashCode(itr.next());
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from this set all elements in the given collection (optional
|
||||
* operation). This implementation uses <code>size()</code> to determine
|
||||
* the smaller collection. Then, if this set is smaller, it iterates
|
||||
* over the set, calling Iterator.remove if the collection contains
|
||||
* the element. If this set is larger, it iterates over the collection,
|
||||
* calling Set.remove for all elements in the collection. Note that
|
||||
* this operation will fail if a remove methods is not supported.
|
||||
*
|
||||
* @param c the collection of elements to remove
|
||||
* @return true if the set was modified as a result
|
||||
* @throws UnsupportedOperationException if remove is not supported
|
||||
* @throws NullPointerException if the collection is null
|
||||
* @see AbstractCollection#remove(Object)
|
||||
* @see Collection#contains(Object)
|
||||
* @see Iterator#remove()
|
||||
*/
|
||||
public boolean removeAll(Collection c)
|
||||
{
|
||||
int oldsize = size();
|
||||
int count = c.size();
|
||||
Iterator i;
|
||||
if (oldsize < count)
|
||||
{
|
||||
for (i = iterator(), count = oldsize; count > 0; count--)
|
||||
if (c.contains(i.next()))
|
||||
i.remove();
|
||||
}
|
||||
else
|
||||
for (i = c.iterator(); count > 0; count--)
|
||||
remove(i.next());
|
||||
return oldsize != size();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* ArrayList.java -- JDK1.2's answer to Vector; this is an array-backed
|
||||
implementation of the List interface
|
||||
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -35,39 +35,81 @@ import java.io.ObjectInputStream;
|
|||
import java.io.ObjectOutputStream;
|
||||
|
||||
/**
|
||||
* An array-backed implementation of the List interface. ArrayList
|
||||
* performs well on simple tasks: random access into a list, appending
|
||||
* to or removing from the end of a list, checking the size, &c.
|
||||
* An array-backed implementation of the List interface. This implements
|
||||
* all optional list operations, and permits null elements, so that it is
|
||||
* better than Vector, which it replaces. Random access is roughly constant
|
||||
* time, and iteration is roughly linear time, so it is nice and fast, with
|
||||
* less overhead than a LinkedList.
|
||||
* <p>
|
||||
*
|
||||
* Each list has a capacity, and as the array reaches that capacity it
|
||||
* is automatically transferred to a larger array. You also have access to
|
||||
* ensureCapacity and trimToSize to control the backing array's size, avoiding
|
||||
* reallocation or wasted memory.
|
||||
* <p>
|
||||
*
|
||||
* ArrayList is not synchronized, so if you need multi-threaded access,
|
||||
* consider using:<br>
|
||||
* <code>List l = Collections.synchronizedList(new ArrayList(...));</code>
|
||||
* <p>
|
||||
*
|
||||
* The iterators are <i>fail-fast</i>, meaning that any structural
|
||||
* modification, except for <code>remove()</code> called on the iterator
|
||||
* itself, cause the iterator to throw a
|
||||
* {@link ConcurrentModificationException} rather than exhibit
|
||||
* non-deterministic behavior.
|
||||
*
|
||||
* @author Jon A. Zeppieri
|
||||
* @see java.util.AbstractList
|
||||
* @see java.util.List
|
||||
* @author Bryce McKinlay
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Collection
|
||||
* @see List
|
||||
* @see LinkedList
|
||||
* @see Vector
|
||||
* @see Collections#synchronizedList(List)
|
||||
* @see AbstractList
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class ArrayList extends AbstractList
|
||||
implements List, Cloneable, Serializable
|
||||
implements List, RandomAccess, Cloneable, Serializable
|
||||
{
|
||||
/** the default capacity for new ArrayLists */
|
||||
/**
|
||||
* Compatible with JDK 1.2
|
||||
*/
|
||||
private static final long serialVersionUID = 8683452581122892189L;
|
||||
|
||||
/**
|
||||
* The default capacity for new ArrayLists.
|
||||
*/
|
||||
private static final int DEFAULT_CAPACITY = 16;
|
||||
|
||||
/** the number of elements in this list */
|
||||
int size;
|
||||
/**
|
||||
* The number of elements in this list.
|
||||
* @serial the list size
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/** where the data is stored */
|
||||
transient Object[] data;
|
||||
/**
|
||||
* Where the data is stored.
|
||||
*/
|
||||
private transient Object[] data;
|
||||
|
||||
/**
|
||||
* Construct a new ArrayList with the supplied initial capacity.
|
||||
*
|
||||
* @param capacity Initial capacity of this ArrayList
|
||||
* @param capacity initial capacity of this ArrayList
|
||||
* @throws IllegalArgumentException if capacity is negative
|
||||
*/
|
||||
public ArrayList(int capacity)
|
||||
{
|
||||
// Must explicitly check, to get correct exception.
|
||||
if (capacity < 0)
|
||||
throw new IllegalArgumentException();
|
||||
data = new Object[capacity];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new ArrayList with the default capcity
|
||||
* Construct a new ArrayList with the default capcity (16).
|
||||
*/
|
||||
public ArrayList()
|
||||
{
|
||||
|
@ -76,71 +118,60 @@ public class ArrayList extends AbstractList
|
|||
|
||||
/**
|
||||
* Construct a new ArrayList, and initialize it with the elements
|
||||
* in the supplied Collection; Sun specs say that the initial
|
||||
* capacity is 110% of the Collection's size.
|
||||
* in the supplied Collection. The initial capacity is 110% of the
|
||||
* Collection's size.
|
||||
*
|
||||
* @param c the collection whose elements will initialize this list
|
||||
* @throws NullPointerException if c is null
|
||||
*/
|
||||
public ArrayList(Collection c)
|
||||
{
|
||||
this((int) (c.size() * 1.1));
|
||||
this((int) (c.size() * 1.1f));
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guarantees that this list will have at least enough capacity to
|
||||
* hold minCapacity elements.
|
||||
*
|
||||
* @specnote This implementation will grow the list to
|
||||
* max(current * 2, minCapacity) if (minCapacity > current). The JCL says
|
||||
* explictly that "this method increases its capacity to minCap", while
|
||||
* the JDK 1.3 online docs specify that the list will grow to at least the
|
||||
* size specified.
|
||||
* @param minCapacity the minimum guaranteed capacity
|
||||
* Trims the capacity of this List to be equal to its size;
|
||||
* a memory saver.
|
||||
*/
|
||||
public void ensureCapacity(int minCapacity)
|
||||
public void trimToSize()
|
||||
{
|
||||
Object[] newData;
|
||||
int current = data.length;
|
||||
|
||||
if (minCapacity > current)
|
||||
// Not a structural change from the perspective of iterators on this list,
|
||||
// so don't update modCount.
|
||||
if (size != data.length)
|
||||
{
|
||||
newData = new Object[Math.max((current * 2), minCapacity)];
|
||||
Object[] newData = new Object[size];
|
||||
System.arraycopy(data, 0, newData, 0, size);
|
||||
data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the supplied element to the end of this list.
|
||||
* Guarantees that this list will have at least enough capacity to
|
||||
* hold minCapacity elements. This implementation will grow the list to
|
||||
* max(current * 2, minCapacity) if (minCapacity > current). The JCL says
|
||||
* explictly that "this method increases its capacity to minCap", while
|
||||
* the JDK 1.3 online docs specify that the list will grow to at least the
|
||||
* size specified.
|
||||
*
|
||||
* @param e the element to be appended to this list
|
||||
* @param minCapacity the minimum guaranteed capacity
|
||||
*/
|
||||
public boolean add(Object e)
|
||||
public void ensureCapacity(int minCapacity)
|
||||
{
|
||||
modCount++;
|
||||
if (size == data.length)
|
||||
ensureCapacity(size + 1);
|
||||
data[size++] = e;
|
||||
return true;
|
||||
int current = data.length;
|
||||
|
||||
if (minCapacity > current)
|
||||
{
|
||||
Object[] newData = new Object[Math.max(current * 2, minCapacity)];
|
||||
System.arraycopy(data, 0, newData, 0, size);
|
||||
data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the element at the user-supplied index.
|
||||
* Returns the number of elements in this list.
|
||||
*
|
||||
* @param index the index of the element we are fetching
|
||||
* @throws IndexOutOfBoundsException (iIndex < 0) || (iIndex >= size())
|
||||
*/
|
||||
public Object get(int index)
|
||||
{
|
||||
if (index < 0 || index >= size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
return data[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this list
|
||||
* @return the list size
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
|
@ -148,106 +179,60 @@ public class ArrayList extends AbstractList
|
|||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the user-supplied index
|
||||
* Checks if the list is empty.
|
||||
*
|
||||
* @param iIndex the index of the element to be removed
|
||||
* @return the removed Object
|
||||
* @throws IndexOutOfBoundsException (iIndex < 0) || (iIndex >= size())
|
||||
* @return true if there are no elements
|
||||
*/
|
||||
public Object remove(int index)
|
||||
public boolean isEmpty()
|
||||
{
|
||||
modCount++;
|
||||
if (index < 0 || index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
Object r = data[index];
|
||||
if (index != --size)
|
||||
System.arraycopy(data, (index + 1), data, index, (size - index));
|
||||
data[size] = null;
|
||||
return r;
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements in the half-open interval [iFromIndex, iToIndex).
|
||||
* Returns true iff element is in this ArrayList.
|
||||
*
|
||||
* @param fromIndex the first index which will be removed
|
||||
* @param toIndex one greater than the last index which will be
|
||||
* removed
|
||||
* @param e the element whose inclusion in the List is being tested
|
||||
* @return true if the list contains e
|
||||
*/
|
||||
protected void removeRange(int fromIndex, int toIndex)
|
||||
public boolean contains(Object e)
|
||||
{
|
||||
modCount++;
|
||||
if (fromIndex != toIndex)
|
||||
{
|
||||
System.arraycopy(data, toIndex, data, fromIndex, size - toIndex);
|
||||
size -= (toIndex - fromIndex);
|
||||
}
|
||||
return indexOf(e) != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the supplied element at the specified index, shifting all
|
||||
* elements currently at that index or higher one to the right.
|
||||
* Returns the lowest index at which element appears in this List, or
|
||||
* -1 if it does not appear.
|
||||
*
|
||||
* @param index the index at which the element is being added
|
||||
* @param e the item being added
|
||||
* @param e the element whose inclusion in the List is being tested
|
||||
* @return the index where e was found
|
||||
*/
|
||||
public void add(int index, Object e)
|
||||
public int indexOf(Object e)
|
||||
{
|
||||
modCount++;
|
||||
if (index < 0 || index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
if (size == data.length)
|
||||
ensureCapacity(size + 1);
|
||||
if (index != size)
|
||||
System.arraycopy(data, index, data, index + 1, size - index);
|
||||
data[index] = e;
|
||||
size++;
|
||||
for (int i = 0; i < size; i++)
|
||||
if (equals(e, data[i]))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add each element in the supplied Collection to this List.
|
||||
* Returns the highest index at which element appears in this List, or
|
||||
* -1 if it does not appear.
|
||||
*
|
||||
* @param c a Collection containing elements to be
|
||||
* added to this List
|
||||
* @param e the element whose inclusion in the List is being tested
|
||||
* @return the index where e was found
|
||||
*/
|
||||
public boolean addAll(Collection c)
|
||||
public int lastIndexOf(Object e)
|
||||
{
|
||||
return addAll(size, c);
|
||||
for (int i = size - 1; i >= 0; i--)
|
||||
if (equals(e, data[i]))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all elements in the supplied collection, inserting them beginning
|
||||
* at the specified index.
|
||||
* Creates a shallow copy of this ArrayList (elements are not cloned).
|
||||
*
|
||||
* @param index the index at which the elements will be inserted
|
||||
* @param c the Collection containing the elements to be
|
||||
* inserted
|
||||
*/
|
||||
public boolean addAll(int index, Collection c)
|
||||
{
|
||||
if (index < 0 || index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
modCount++;
|
||||
Iterator itr = c.iterator();
|
||||
int csize = c.size();
|
||||
|
||||
if (csize + size > data.length)
|
||||
ensureCapacity(size + csize);
|
||||
int end = index + csize;
|
||||
if (size > 0 && index != size)
|
||||
System.arraycopy(data, index, data, end, csize);
|
||||
size += csize;
|
||||
for (; index < end; index++)
|
||||
{
|
||||
data[index] = itr.next();
|
||||
}
|
||||
return (csize > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow copy of this ArrayList
|
||||
* @return the cloned object
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
|
@ -255,95 +240,20 @@ public class ArrayList extends AbstractList
|
|||
try
|
||||
{
|
||||
clone = (ArrayList) super.clone();
|
||||
clone.data = new Object[data.length];
|
||||
System.arraycopy(data, 0, clone.data, 0, size);
|
||||
clone.data = (Object[]) data.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
// Impossible to get here.
|
||||
}
|
||||
catch (CloneNotSupportedException e) {}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff oElement is in this ArrayList.
|
||||
* Returns an Object array containing all of the elements in this ArrayList.
|
||||
* The array is independent of this list.
|
||||
*
|
||||
* @param e the element whose inclusion in the List is being
|
||||
* tested
|
||||
*/
|
||||
public boolean contains(Object e)
|
||||
{
|
||||
return (indexOf(e) != -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowest index at which oElement appears in this List, or
|
||||
* -1 if it does not appear.
|
||||
*
|
||||
* @param e the element whose inclusion in the List is being
|
||||
* tested
|
||||
*/
|
||||
public int indexOf(Object e)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (e == null ? data[i] == null : e.equals(data[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest index at which oElement appears in this List, or
|
||||
* -1 if it does not appear.
|
||||
*
|
||||
* @param e the element whose inclusion in the List is being
|
||||
* tested
|
||||
*/
|
||||
public int lastIndexOf(Object e)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = size - 1; i >= 0; i--)
|
||||
{
|
||||
if (e == null ? data[i] == null : e.equals(data[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from this List
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
modCount++;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
data[i] = null;
|
||||
}
|
||||
size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the element at the specified index.
|
||||
*
|
||||
* @param index the index at which the element is being set
|
||||
* @param e the element to be set
|
||||
* @return the element previously at the specified index, or null if
|
||||
* none was there
|
||||
*/
|
||||
public Object set(int index, Object e)
|
||||
{
|
||||
Object result;
|
||||
if (index < 0 || index >= size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
result = data[index];
|
||||
// SEH: no structural change, so don't update modCount
|
||||
data[index] = e;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Object Array containing all of the elements in this ArrayList
|
||||
* @return an array representation of this list
|
||||
*/
|
||||
public Object[] toArray()
|
||||
{
|
||||
|
@ -360,58 +270,300 @@ public class ArrayList extends AbstractList
|
|||
* and returned; if the passed-in Array is <i>larger</i> than the size
|
||||
* of this List, then size() index will be set to null.
|
||||
*
|
||||
* @param array the passed-in Array
|
||||
* @param a the passed-in Array
|
||||
* @return an array representation of this list
|
||||
* @throws ArrayStoreException if the runtime type of a does not allow
|
||||
* an element in this list
|
||||
* @throws NullPointerException if a is null
|
||||
*/
|
||||
public Object[] toArray(Object[] array)
|
||||
public Object[] toArray(Object[] a)
|
||||
{
|
||||
if (array.length < size)
|
||||
array = (Object[]) Array.newInstance(array.getClass().getComponentType(),
|
||||
if (a.length < size)
|
||||
a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
|
||||
size);
|
||||
else if (array.length > size)
|
||||
array[size] = null;
|
||||
System.arraycopy(data, 0, array, 0, size);
|
||||
return array;
|
||||
else if (a.length > size)
|
||||
a[size] = null;
|
||||
System.arraycopy(data, 0, a, 0, size);
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims the capacity of this List to be equal to its size;
|
||||
* a memory saver.
|
||||
* Retrieves the element at the user-supplied index.
|
||||
*
|
||||
* @param index the index of the element we are fetching
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||||
*/
|
||||
public void trimToSize()
|
||||
public Object get(int index)
|
||||
{
|
||||
// not a structural change from the perspective of iterators on this list,
|
||||
// so don't update modCount
|
||||
Object[] newData = new Object[size];
|
||||
System.arraycopy(data, 0, newData, 0, size);
|
||||
data = newData;
|
||||
checkBoundExclusive(index);
|
||||
return data[index];
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException
|
||||
/**
|
||||
* Sets the element at the specified index.
|
||||
*
|
||||
* @param index the index at which the element is being set
|
||||
* @param e the element to be set
|
||||
* @return the element previously at the specified index
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= 0
|
||||
*/
|
||||
public Object set(int index, Object e)
|
||||
{
|
||||
checkBoundExclusive(index);
|
||||
Object result = data[index];
|
||||
data[index] = e;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the supplied element to the end of this list.
|
||||
*
|
||||
* @param e the element to be appended to this list
|
||||
* @return true, the add will always succeed
|
||||
*/
|
||||
public boolean add(Object e)
|
||||
{
|
||||
modCount++;
|
||||
if (size == data.length)
|
||||
ensureCapacity(size + 1);
|
||||
data[size++] = e;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the supplied element at the specified index, shifting all
|
||||
* elements currently at that index or higher one to the right.
|
||||
*
|
||||
* @param index the index at which the element is being added
|
||||
* @param e the item being added
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||||
*/
|
||||
public void add(int index, Object e)
|
||||
{
|
||||
checkBoundInclusive(index);
|
||||
modCount++;
|
||||
if (size == data.length)
|
||||
ensureCapacity(size + 1);
|
||||
if (index != size)
|
||||
System.arraycopy(data, index, data, index + 1, size - index);
|
||||
data[index] = e;
|
||||
size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the user-supplied index.
|
||||
*
|
||||
* @param index the index of the element to be removed
|
||||
* @return the removed Object
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||||
*/
|
||||
public Object remove(int index)
|
||||
{
|
||||
checkBoundExclusive(index);
|
||||
Object r = data[index];
|
||||
modCount++;
|
||||
if (index != --size)
|
||||
System.arraycopy(data, index + 1, data, index, size - index);
|
||||
// Aid for garbage collection by releasing this pointer.
|
||||
data[size] = null;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from this List
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
if (size > 0)
|
||||
{
|
||||
modCount++;
|
||||
// Allow for garbage collection.
|
||||
Arrays.fill(data, 0, size, null);
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add each element in the supplied Collection to this List. It is undefined
|
||||
* what happens if you modify the list while this is taking place; for
|
||||
* example, if the collection contains this list.
|
||||
*
|
||||
* @param c a Collection containing elements to be added to this List
|
||||
* @return true if the list was modified, in other words c is not empty
|
||||
* @throws NullPointerException if c is null
|
||||
*/
|
||||
public boolean addAll(Collection c)
|
||||
{
|
||||
return addAll(size, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all elements in the supplied collection, inserting them beginning
|
||||
* at the specified index.
|
||||
*
|
||||
* @param index the index at which the elements will be inserted
|
||||
* @param c the Collection containing the elements to be inserted
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > 0
|
||||
* @throws NullPointerException if c is null
|
||||
*/
|
||||
public boolean addAll(int index, Collection c)
|
||||
{
|
||||
checkBoundInclusive(index);
|
||||
Iterator itr = c.iterator();
|
||||
int csize = c.size();
|
||||
|
||||
modCount++;
|
||||
if (csize + size > data.length)
|
||||
ensureCapacity(size + csize);
|
||||
int end = index + csize;
|
||||
if (index != size)
|
||||
System.arraycopy(data, index, data, end, csize);
|
||||
size += csize;
|
||||
for ( ; index < end; index++)
|
||||
data[index] = itr.next();
|
||||
return csize > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements in the half-open interval [fromIndex, toIndex).
|
||||
* You asked for it if you call this with invalid arguments.
|
||||
*
|
||||
* @param fromIndex the first index which will be removed
|
||||
* @param toIndex one greater than the last index which will be removed
|
||||
*/
|
||||
protected void removeRange(int fromIndex, int toIndex)
|
||||
{
|
||||
if (fromIndex != toIndex)
|
||||
{
|
||||
modCount++;
|
||||
System.arraycopy(data, toIndex, data, fromIndex, size - toIndex);
|
||||
size -= toIndex - fromIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the index is in the range of possible elements (inclusive).
|
||||
*
|
||||
* @param index the index to check
|
||||
* @throws IndexOutOfBoundsException if index > size
|
||||
*/
|
||||
private void checkBoundInclusive(int index)
|
||||
{
|
||||
// Implementation note: we do not check for negative ranges here, since
|
||||
// use of a negative index will cause an ArrayIndexOutOfBoundsException,
|
||||
// a subclass of the required exception, with no effort on our part.
|
||||
if (index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
|
||||
+ size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the index is in the range of existing elements (exclusive).
|
||||
*
|
||||
* @param index the index to check
|
||||
* @throws IndexOutOfBoundsException if index >= size
|
||||
*/
|
||||
private void checkBoundExclusive(int index)
|
||||
{
|
||||
// Implementation note: we do not check for negative ranges here, since
|
||||
// use of a negative index will cause an ArrayIndexOutOfBoundsException,
|
||||
// a subclass of the required exception, with no effort on our part.
|
||||
if (index >= size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
|
||||
+ size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove from this list all elements contained in the given collection.
|
||||
* This is not public, due to Sun's API, but this performs in linear
|
||||
* time while the default behavior of AbstractList would be quadratic.
|
||||
*
|
||||
* @param c the collection to filter out
|
||||
* @return true if this list changed
|
||||
* @throws NullPointerException if c is null
|
||||
*/
|
||||
boolean removeAllInternal(Collection c)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
for (i = 0; i < size; i++)
|
||||
if (c.contains(data[i]))
|
||||
break;
|
||||
if (i == size)
|
||||
return false;
|
||||
|
||||
// The 'size' field.
|
||||
out.defaultWriteObject();
|
||||
|
||||
// FIXME: Do we really want to serialize unused list entries??
|
||||
out.writeInt(data.length);
|
||||
for (i = 0; i < data.length; i++)
|
||||
out.writeObject(data[i]);
|
||||
modCount++;
|
||||
for (j = i++; i < size; i++)
|
||||
if (! c.contains(data[i]))
|
||||
data[j++] = data[i];
|
||||
size -= i - j;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
/**
|
||||
* Retain in this vector only the elements contained in the given collection.
|
||||
* This is not public, due to Sun's API, but this performs in linear
|
||||
* time while the default behavior of AbstractList would be quadratic.
|
||||
*
|
||||
* @param c the collection to filter by
|
||||
* @return true if this vector changed
|
||||
* @throws NullPointerException if c is null
|
||||
* @since 1.2
|
||||
*/
|
||||
boolean retainAllInternal(Collection c)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
for (i = 0; i < size; i++)
|
||||
if (! c.contains(data[i]))
|
||||
break;
|
||||
if (i == size)
|
||||
return false;
|
||||
|
||||
modCount++;
|
||||
for (j = i++; i < size; i++)
|
||||
if (c.contains(data[i]))
|
||||
data[j++] = data[i];
|
||||
size -= i - j;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this object to the given stream.
|
||||
*
|
||||
* @param out the stream to write to
|
||||
* @throws IOException if the underlying stream fails
|
||||
* @serialData the size field (int), the length of the backing array
|
||||
* (int), followed by its elements (Objects) in proper order.
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream s) throws IOException
|
||||
{
|
||||
// The 'size' field.
|
||||
s.defaultWriteObject();
|
||||
// We serialize unused list entries to preserve capacity.
|
||||
int len = data.length;
|
||||
s.writeInt(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
s.writeObject(data[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes this object from the given stream.
|
||||
*
|
||||
* @param in the stream to read from
|
||||
* @throws ClassNotFoundException if the underlying stream fails
|
||||
* @throws IOException if the underlying stream fails
|
||||
* @serialData the size field (int), the length of the backing array
|
||||
* (int), followed by its elements (Objects) in proper order.
|
||||
*/
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
int i;
|
||||
int capacity;
|
||||
|
||||
// the `size' field.
|
||||
in.defaultReadObject();
|
||||
|
||||
capacity = in.readInt();
|
||||
s.defaultReadObject();
|
||||
int capacity = s.readInt();
|
||||
data = new Object[capacity];
|
||||
|
||||
for (i = 0; i < capacity; i++)
|
||||
data[i] = in.readObject();
|
||||
for (int i = 0; i < capacity; i++)
|
||||
data[i] = s.readObject();
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/* BasicMapEntry.java -- a class providing a plain-vanilla implementation of
|
||||
the Map.Entry interface; could be used anywhere in java.util
|
||||
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -29,52 +29,113 @@ executable file might be covered by the GNU General Public License. */
|
|||
package java.util;
|
||||
|
||||
/**
|
||||
* A class which implements Map.Entry. It is shared by HashMap, TreeMap, and
|
||||
* Hashtable.
|
||||
* A class which implements Map.Entry. It is shared by HashMap, TreeMap,
|
||||
* Hashtable, and Collections. It is not specified by the JDK, but makes
|
||||
* life much easier.
|
||||
*
|
||||
* @author Jon Zeppieri
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
*/
|
||||
class BasicMapEntry implements Map.Entry
|
||||
{
|
||||
/**
|
||||
* The key. Package visible for direct manipulation.
|
||||
*/
|
||||
Object key;
|
||||
|
||||
/**
|
||||
* The value. Package visible for direct manipulation.
|
||||
*/
|
||||
Object value;
|
||||
|
||||
/**
|
||||
* Basic constructor initializes the fields.
|
||||
* @param newKey the key
|
||||
* @param newValue the value
|
||||
*/
|
||||
BasicMapEntry(Object newKey, Object newValue)
|
||||
{
|
||||
key = newKey;
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the specified object with this entry. Returns true only if
|
||||
* the object is a mapping of identical key and value. In other words,
|
||||
* this must be:
|
||||
* <pre>
|
||||
* (o instanceof Map.Entry) &&
|
||||
* (getKey() == null ? ((HashMap) o).getKey() == null
|
||||
* : getKey().equals(((HashMap) o).getKey())) &&
|
||||
* (getValue() == null ? ((HashMap) o).getValue() == null
|
||||
* : getValue().equals(((HashMap) o).getValue()))
|
||||
* </pre>
|
||||
*
|
||||
* @param o the object to compare
|
||||
* @return true if it is equal
|
||||
*/
|
||||
public final boolean equals(Object o)
|
||||
{
|
||||
if (! (o instanceof Map.Entry))
|
||||
return false;
|
||||
// Optimize for our own entries.
|
||||
if (o instanceof BasicMapEntry)
|
||||
{
|
||||
BasicMapEntry e = (BasicMapEntry) o;
|
||||
return (AbstractCollection.equals(key, e.key)
|
||||
&& AbstractCollection.equals(value, e.value));
|
||||
}
|
||||
Map.Entry e = (Map.Entry) o;
|
||||
return (key == null ? e.getKey() == null : key.equals(e.getKey())
|
||||
&& value == null ? e.getValue() == null
|
||||
: value.equals(e.getValue()));
|
||||
return (AbstractCollection.equals(key, e.getKey())
|
||||
&& AbstractCollection.equals(value, e.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key corresponding to this entry.
|
||||
*
|
||||
* @return the key
|
||||
*/
|
||||
public final Object getKey()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value corresponding to this entry. If you already called
|
||||
* Iterator.remove(), the behavior undefined, but in this case it works.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public final Object getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code of the entry. This is defined as the exclusive-or
|
||||
* of the hashcodes of the key and value (using 0 for null). In other
|
||||
* words, this must be:
|
||||
* <pre>
|
||||
* (getKey() == null ? 0 : getKey().hashCode()) ^
|
||||
* (getValue() == null ? 0 : getValue().hashCode())
|
||||
* </pre>
|
||||
*
|
||||
* @return the hash code
|
||||
*/
|
||||
public final int hashCode()
|
||||
{
|
||||
int kc = (key == null ? 0 : key.hashCode());
|
||||
int vc = (value == null ? 0 : value.hashCode());
|
||||
return kc ^ vc;
|
||||
return (AbstractCollection.hashCode(key)
|
||||
^ AbstractCollection.hashCode(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the value of this Map.Entry. Note that this is overriden by
|
||||
* Hashtable.Entry, which does not permit a null value.
|
||||
* Replaces the value with the specified object. This writes through
|
||||
* to the map, unless you have already called Iterator.remove(). It
|
||||
* may be overridden to restrict a null value.
|
||||
*
|
||||
* @param newVal the new value to store
|
||||
* @return the old value
|
||||
* @throws NullPointerException if the map forbids null values
|
||||
*/
|
||||
public Object setValue(Object newVal)
|
||||
{
|
||||
|
@ -83,6 +144,12 @@ class BasicMapEntry implements Map.Entry
|
|||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* This provides a string representation of the entry. It is of the form
|
||||
* "key=value", where string concatenation is used on key and value.
|
||||
*
|
||||
* @return the string representation
|
||||
*/
|
||||
public final String toString()
|
||||
{
|
||||
return key + "=" + value;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// BitSet - A vector of bits.
|
||||
|
||||
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
|
||||
/* BitSet.java -- A vector of bits.
|
||||
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -50,22 +49,32 @@ import java.io.Serializable;
|
|||
* while another thread is simultaneously modifying it, the results are
|
||||
* undefined.
|
||||
*
|
||||
* @specnote Historically, there has been some confusion as to whether or not
|
||||
* this class should be synchronized. From an efficiency perspective,
|
||||
* it is very undesirable to synchronize it because multiple locks
|
||||
* and explicit lock ordering are required to safely synchronize some
|
||||
* methods. The JCL 1.2 supplement book specifies that as of JDK
|
||||
* 1.2, the class is no longer synchronized.
|
||||
*
|
||||
* @author Jochen Hoenicke
|
||||
* @author Tom Tromey <tromey@cygnus.com>
|
||||
* @date October 23, 1998.
|
||||
* @status API complete to JDK 1.3.
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class BitSet implements Cloneable, Serializable
|
||||
{
|
||||
/**
|
||||
* Create a new empty bit set.
|
||||
* Compatible with JDK 1.0.
|
||||
*/
|
||||
private static final long serialVersionUID = 7997698588986878753L;
|
||||
|
||||
/**
|
||||
* A common mask.
|
||||
*/
|
||||
private static final int LONG_MASK = 0x3f;
|
||||
|
||||
/**
|
||||
* The actual bits.
|
||||
* @serial the i'th bit is in bits[i/64] at position i%64 (where position
|
||||
* 0 is the least significant).
|
||||
*/
|
||||
private long[] bits;
|
||||
|
||||
/**
|
||||
* Create a new empty bit set. All bits are initially false.
|
||||
*/
|
||||
public BitSet()
|
||||
{
|
||||
|
@ -76,17 +85,14 @@ public class BitSet implements Cloneable, Serializable
|
|||
* Create a new empty bit set, with a given size. This
|
||||
* constructor reserves enough space to represent the integers
|
||||
* from <code>0</code> to <code>nbits-1</code>.
|
||||
* @param nbits the initial size of the bit set.
|
||||
* @throws NegativeArraySizeException if the specified initial
|
||||
* size is negative.
|
||||
* @require nbits >= 0
|
||||
*
|
||||
* @param nbits the initial size of the bit set
|
||||
* @throws NegativeArraySizeException if nbits < 0
|
||||
*/
|
||||
public BitSet(int nbits)
|
||||
{
|
||||
if (nbits < 0)
|
||||
throw new NegativeArraySizeException();
|
||||
int length = nbits / 64;
|
||||
if (nbits % 64 != 0)
|
||||
int length = nbits >>> 6;
|
||||
if ((nbits & LONG_MASK) != 0)
|
||||
++length;
|
||||
bits = new long[length];
|
||||
}
|
||||
|
@ -95,8 +101,9 @@ public class BitSet implements Cloneable, Serializable
|
|||
* Performs the logical AND operation on this bit set and the
|
||||
* given <code>set</code>. This means it builds the intersection
|
||||
* of the two sets. The result is stored into this bit set.
|
||||
* @param set the second bit set.
|
||||
* @require set != null
|
||||
*
|
||||
* @param set the second bit set
|
||||
* @throws NullPointerException if set is null
|
||||
*/
|
||||
public void and(BitSet bs)
|
||||
{
|
||||
|
@ -104,8 +111,8 @@ public class BitSet implements Cloneable, Serializable
|
|||
int i;
|
||||
for (i = 0; i < max; ++i)
|
||||
bits[i] &= bs.bits[i];
|
||||
for (; i < bits.length; ++i)
|
||||
bits[i] = 0;
|
||||
while (i < bits.length)
|
||||
bits[i++] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,54 +120,134 @@ public class BitSet implements Cloneable, Serializable
|
|||
* complement of the given <code>set</code>. This means it
|
||||
* selects every element in the first set, that isn't in the
|
||||
* second set. The result is stored into this bit set.
|
||||
* @param set the second bit set.
|
||||
* @require set != null
|
||||
* @since JDK1.2
|
||||
*
|
||||
* @param set the second bit set
|
||||
* @throws NullPointerException if set is null
|
||||
* @since 1.2
|
||||
*/
|
||||
public void andNot(BitSet bs)
|
||||
{
|
||||
int max = Math.min(bits.length, bs.bits.length);
|
||||
int i;
|
||||
for (i = 0; i < max; ++i)
|
||||
int i = Math.min(bits.length, bs.bits.length);
|
||||
while (--i >= 0)
|
||||
bits[i] &= ~bs.bits[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bits set to true.
|
||||
*
|
||||
* @return the number of true bits
|
||||
* @since 1.4
|
||||
*/
|
||||
public int cardinality()
|
||||
{
|
||||
int card = 0;
|
||||
for (int i = bits.length - 1; i >= 0; i--)
|
||||
{
|
||||
long a = bits[i];
|
||||
// Take care of common cases.
|
||||
if (a == 0)
|
||||
continue;
|
||||
if (a == -1)
|
||||
{
|
||||
card += 64;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Successively collapse alternating bit groups into a sum.
|
||||
a = ((a >> 1) & 0x5555555555555555L) + (a & 0x5555555555555555L);
|
||||
a = ((a >> 2) & 0x3333333333333333L) + (a & 0x3333333333333333L);
|
||||
int b = (int) ((a >>> 32) + a);
|
||||
b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f);
|
||||
b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff);
|
||||
card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff);
|
||||
}
|
||||
return card;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all bits in the set to false.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
Arrays.fill(bits, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the integer <code>bitIndex</code> from this set. That is
|
||||
* the corresponding bit is cleared. If the index is not in the set,
|
||||
* this method does nothing.
|
||||
* @param bitIndex a non-negative integer.
|
||||
* @exception ArrayIndexOutOfBoundsException if the specified bit index
|
||||
* is negative.
|
||||
* @require bitIndex >= 0
|
||||
*
|
||||
* @param bitIndex a non-negative integer
|
||||
* @throws IndexOutOfBoundsException if bitIndex < 0
|
||||
*/
|
||||
public void clear(int pos)
|
||||
{
|
||||
if (pos < 0)
|
||||
throw new IndexOutOfBoundsException();
|
||||
int bit = pos % 64;
|
||||
int offset = pos / 64;
|
||||
int offset = pos >>> 6;
|
||||
ensure(offset);
|
||||
bits[offset] &= ~(1L << bit);
|
||||
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
|
||||
// so we'll just let that be our exception.
|
||||
bits[offset] &= ~(1L << pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits between from (inclusive) and to (exclusive) to false.
|
||||
*
|
||||
* @param from the start range (inclusive)
|
||||
* @param to the end range (exclusive)
|
||||
* @throws IndexOutOfBoundsException if from < 0 || from > to
|
||||
* @since 1.4
|
||||
*/
|
||||
public void clear(int from, int to)
|
||||
{
|
||||
if (from < 0 || from > to)
|
||||
throw new IndexOutOfBoundsException();
|
||||
if (from == to)
|
||||
return;
|
||||
int lo_offset = from >>> 6;
|
||||
int hi_offset = to >>> 6;
|
||||
ensure(hi_offset);
|
||||
if (lo_offset == hi_offset)
|
||||
{
|
||||
bits[hi_offset] &= ((1L << from) - 1) | (-1L << to);
|
||||
return;
|
||||
}
|
||||
|
||||
bits[lo_offset] &= (1L << from) - 1;
|
||||
bits[hi_offset] &= -1L << to;
|
||||
for (int i = lo_offset + 1; i < hi_offset; i++)
|
||||
bits[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of this bit set, that is an instance of the same
|
||||
* class and contains the same elements. But it doesn't change when
|
||||
* this bit set changes.
|
||||
*
|
||||
* @return the clone of this object.
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
BitSet bs = new BitSet(bits.length * 64);
|
||||
System.arraycopy(bits, 0, bs.bits, 0, bits.length);
|
||||
try
|
||||
{
|
||||
BitSet bs = (BitSet) super.clone();
|
||||
bs.bits = (long[]) bits.clone();
|
||||
return bs;
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
// Impossible to get here.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the <code>obj</code> is a bit set that contains
|
||||
* exactly the same elements as this bit set, otherwise false.
|
||||
* @return true if obj equals this bit set.
|
||||
*
|
||||
* @param obj the object to compare to
|
||||
* @return true if obj equals this bit set
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
|
@ -182,27 +269,109 @@ public class BitSet implements Cloneable, Serializable
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit at the index to the opposite value.
|
||||
*
|
||||
* @param index the index of the bit
|
||||
* @throws IndexOutOfBoundsException if index is negative
|
||||
* @since 1.4
|
||||
*/
|
||||
public void flip(int index)
|
||||
{
|
||||
int offset = index >>> 6;
|
||||
ensure(offset);
|
||||
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
|
||||
// so we'll just let that be our exception.
|
||||
bits[offset] ^= 1L << index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a range of bits to the opposite value.
|
||||
*
|
||||
* @param from the low index (inclusive)
|
||||
* @param to the high index (exclusive)
|
||||
* @throws IndexOutOfBoundsException if from > to || from < 0
|
||||
* @since 1.4
|
||||
*/
|
||||
public void flip(int from, int to)
|
||||
{
|
||||
if (from < 0 || from > to)
|
||||
throw new IndexOutOfBoundsException();
|
||||
if (from == to)
|
||||
return;
|
||||
int lo_offset = from >>> 6;
|
||||
int hi_offset = to >>> 6;
|
||||
ensure(hi_offset);
|
||||
if (lo_offset == hi_offset)
|
||||
{
|
||||
bits[hi_offset] ^= (-1L << from) & ((1L << to) - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
bits[lo_offset] ^= -1L << from;
|
||||
bits[hi_offset] ^= (1L << to) - 1;
|
||||
for (int i = lo_offset + 1; i < hi_offset; i++)
|
||||
bits[i] ^= -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the integer <code>bitIndex</code> is in this bit
|
||||
* set, otherwise false.
|
||||
* @param bitIndex a non-negative integer
|
||||
* @return the value of the bit at the specified index.
|
||||
* @exception ArrayIndexOutOfBoundsException if the specified bit index
|
||||
* is negative.
|
||||
* @require bitIndex >= 0
|
||||
*
|
||||
* @param pos a non-negative integer
|
||||
* @return the value of the bit at the specified index
|
||||
* @throws IndexOutOfBoundsException if the index is negative
|
||||
*/
|
||||
public boolean get(int pos)
|
||||
{
|
||||
if (pos < 0)
|
||||
throw new IndexOutOfBoundsException();
|
||||
|
||||
int bit = pos % 64;
|
||||
int offset = pos / 64;
|
||||
|
||||
int offset = pos >>> 6;
|
||||
if (offset >= bits.length)
|
||||
return false;
|
||||
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
|
||||
// so we'll just let that be our exception.
|
||||
return (bits[offset] & (1L << pos)) != 0;
|
||||
}
|
||||
|
||||
return (bits[offset] & (1L << bit)) == 0 ? false : true;
|
||||
/**
|
||||
* Returns a new <code>BitSet</code> composed of a range of bits from
|
||||
* this one.
|
||||
*
|
||||
* @param from the low index (inclusive)
|
||||
* @param to the high index (exclusive)
|
||||
* @throws IndexOutOfBoundsException if from > to || from < 0
|
||||
* @since 1.4
|
||||
*/
|
||||
public BitSet get(int from, int to)
|
||||
{
|
||||
if (from < 0 || from > to)
|
||||
throw new IndexOutOfBoundsException();
|
||||
BitSet bs = new BitSet(to - from);
|
||||
int lo_offset = from >>> 6;
|
||||
if (lo_offset >= bits.length)
|
||||
return bs;
|
||||
|
||||
int lo_bit = from & LONG_MASK;
|
||||
int hi_offset = to >>> 6;
|
||||
if (lo_bit == 0)
|
||||
{
|
||||
int len = Math.min(hi_offset - lo_offset + 1, bits.length - lo_offset);
|
||||
System.arraycopy(bits, lo_offset, bs.bits, 0, len);
|
||||
if (hi_offset < bits.length)
|
||||
bs.bits[hi_offset - lo_offset] &= (1L << to) - 1;
|
||||
return bs;
|
||||
}
|
||||
|
||||
int len = Math.min(hi_offset, bits.length - 1);
|
||||
int reverse = ~lo_bit;
|
||||
int i;
|
||||
for (i = 0; lo_offset < len; lo_offset++, i++)
|
||||
bs.bits[i] = ((bits[lo_offset] >>> lo_bit)
|
||||
| (bits[lo_offset + 1] << reverse));
|
||||
if ((to & LONG_MASK) > lo_bit)
|
||||
bs.bits[i++] = bits[lo_offset] >>> lo_bit;
|
||||
if (hi_offset < bits.length)
|
||||
bs.bits[i - 1] &= (1L << (to - from)) - 1;
|
||||
return bs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -233,20 +402,54 @@ public class BitSet implements Cloneable, Serializable
|
|||
* </pre>
|
||||
*
|
||||
* Note that the hash code values changes, if the set is changed.
|
||||
*
|
||||
* @return the hash code value for this bit set.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
long h = 1234;
|
||||
for (int i = bits.length - 1; i >= 0; --i)
|
||||
h ^= bits[i] * (i + 1);
|
||||
for (int i = bits.length; i > 0; )
|
||||
h ^= i * bits[--i];
|
||||
return (int) ((h >> 32) ^ h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified BitSet and this one share at least one
|
||||
* common true bit.
|
||||
*
|
||||
* @param set the set to check for intersection
|
||||
* @return true if the sets intersect
|
||||
* @throws NullPointerException if set is null
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean intersects(BitSet set)
|
||||
{
|
||||
int i = Math.min(bits.length, set.bits.length);
|
||||
while (--i >= 0)
|
||||
if ((bits[i] & set.bits[i]) != 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this set contains no true bits.
|
||||
*
|
||||
* @return true if all bits are false
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
{
|
||||
for (int i = bits.length - 1; i >= 0; i--)
|
||||
if (bits[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logical number of bits actually used by this bit
|
||||
* set. It returns the index of the highest set bit plus one.
|
||||
* Note that this method doesn't return the number of set bits.
|
||||
*
|
||||
* @return the index of the highest set bit plus one.
|
||||
*/
|
||||
public int length()
|
||||
|
@ -273,20 +476,88 @@ public class BitSet implements Cloneable, Serializable
|
|||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the next false bit, from the specified bit
|
||||
* (inclusive).
|
||||
*
|
||||
* @param from the start location
|
||||
* @return the first false bit
|
||||
* @throws IndexOutOfBoundsException if from is negative
|
||||
* @since 1.4
|
||||
*/
|
||||
public int nextClearBit(int from)
|
||||
{
|
||||
int offset = from >>> 6;
|
||||
long mask = 1L << from;
|
||||
while (offset < bits.length)
|
||||
{
|
||||
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
|
||||
// so we'll just let that be our exception.
|
||||
long h = bits[offset];
|
||||
do
|
||||
{
|
||||
if ((h & mask) == 0)
|
||||
return from;
|
||||
mask <<= 1;
|
||||
from++;
|
||||
}
|
||||
while (mask != 0);
|
||||
mask = 1;
|
||||
offset++;
|
||||
}
|
||||
return from;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the next true bit, from the specified bit
|
||||
* (inclusive). If there is none, -1 is returned. You can iterate over
|
||||
* all true bits with this loop:<br>
|
||||
* <pre>
|
||||
* for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
|
||||
* { // operate on i here }
|
||||
* </pre>
|
||||
*
|
||||
* @param from the start location
|
||||
* @return the first true bit, or -1
|
||||
* @throws IndexOutOfBoundsException if from is negative
|
||||
* @since 1.4
|
||||
*/
|
||||
public int nextSetBit(int from)
|
||||
{
|
||||
int offset = from >>> 6;
|
||||
long mask = 1L << from;
|
||||
while (offset < bits.length)
|
||||
{
|
||||
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
|
||||
// so we'll just let that be our exception.
|
||||
long h = bits[offset];
|
||||
do
|
||||
{
|
||||
if ((h & mask) != 0)
|
||||
return from;
|
||||
mask <<= 1;
|
||||
from++;
|
||||
}
|
||||
while (mask != 0);
|
||||
mask = 1;
|
||||
offset++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the logical OR operation on this bit set and the
|
||||
* given <code>set</code>. This means it builds the union
|
||||
* of the two sets. The result is stored into this bit set, which
|
||||
* grows as necessary.
|
||||
* @param set the second bit set.
|
||||
* @exception OutOfMemoryError if the current set can't grow.
|
||||
* @require set != null
|
||||
*
|
||||
* @param bs the second bit set
|
||||
* @throws NullPointerException if bs is null
|
||||
*/
|
||||
public void or(BitSet bs)
|
||||
{
|
||||
ensure(bs.bits.length - 1);
|
||||
int i;
|
||||
for (i = 0; i < bs.bits.length; ++i)
|
||||
for (int i = bs.bits.length - 1; i >= 0; i--)
|
||||
bits[i] |= bs.bits[i];
|
||||
}
|
||||
|
||||
|
@ -295,25 +566,89 @@ public class BitSet implements Cloneable, Serializable
|
|||
* the corresponding bit is set to true. If the index was already in
|
||||
* the set, this method does nothing. The size of this structure
|
||||
* is automatically increased as necessary.
|
||||
* @param bitIndex a non-negative integer.
|
||||
* @exception ArrayIndexOutOfBoundsException if the specified bit index
|
||||
* is negative.
|
||||
* @require bitIndex >= 0
|
||||
*
|
||||
* @param pos a non-negative integer.
|
||||
* @throws IndexOutOfBoundsException if pos is negative
|
||||
*/
|
||||
public void set(int pos)
|
||||
{
|
||||
if (pos < 0)
|
||||
throw new IndexOutOfBoundsException();
|
||||
int bit = pos % 64;
|
||||
int offset = pos / 64;
|
||||
int offset = pos >>> 6;
|
||||
ensure(offset);
|
||||
bits[offset] |= 1L << bit;
|
||||
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
|
||||
// so we'll just let that be our exception.
|
||||
bits[offset] |= 1L << pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit at the given index to the specified value. The size of
|
||||
* this structure is automatically increased as necessary.
|
||||
*
|
||||
* @param index the position to set
|
||||
* @param value the value to set it to
|
||||
* @throws IndexOutOfBoundsException if index is negative
|
||||
* @since 1.4
|
||||
*/
|
||||
public void set(int index, boolean value)
|
||||
{
|
||||
if (value)
|
||||
set(index);
|
||||
else
|
||||
clear(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits between from (inclusive) and to (exclusive) to true.
|
||||
*
|
||||
* @param from the start range (inclusive)
|
||||
* @param to the end range (exclusive)
|
||||
* @throws IndexOutOfBoundsException if from < 0 || from > to
|
||||
* @since 1.4
|
||||
*/
|
||||
public void set(int from, int to)
|
||||
{
|
||||
if (from < 0 || from > to)
|
||||
throw new IndexOutOfBoundsException();
|
||||
if (from == to)
|
||||
return;
|
||||
int lo_offset = from >>> 6;
|
||||
int hi_offset = to >>> 6;
|
||||
ensure(hi_offset);
|
||||
if (lo_offset == hi_offset)
|
||||
{
|
||||
bits[hi_offset] |= (-1L << from) & ((1L << to) - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
bits[lo_offset] |= -1L << from;
|
||||
bits[hi_offset] |= (1L << to) - 1;
|
||||
for (int i = lo_offset + 1; i < hi_offset; i++)
|
||||
bits[i] = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits between from (inclusive) and to (exclusive) to the
|
||||
* specified value.
|
||||
*
|
||||
* @param from the start range (inclusive)
|
||||
* @param to the end range (exclusive)
|
||||
* @param value the value to set it to
|
||||
* @throws IndexOutOfBoundsException if from < 0 || from > to
|
||||
* @since 1.4
|
||||
*/
|
||||
public void set(int from, int to, boolean value)
|
||||
{
|
||||
if (value)
|
||||
set(from, to);
|
||||
else
|
||||
clear(from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bits actually used by this bit set. Note
|
||||
* that this method doesn't return the number of set bits.
|
||||
* @returns the number of bits currently used.
|
||||
* that this method doesn't return the number of set bits, and that
|
||||
* future requests for larger bits will make this automatically grow.
|
||||
*
|
||||
* @return the number of bits currently used.
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
|
@ -324,11 +659,12 @@ public class BitSet implements Cloneable, Serializable
|
|||
* Returns the string representation of this bit set. This
|
||||
* consists of a comma separated list of the integers in this set
|
||||
* surrounded by curly braces. There is a space after each comma.
|
||||
* A sample string is thus "{1, 3, 53}".
|
||||
* @return the string representation.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
String r = "{";
|
||||
StringBuffer r = new StringBuffer("{");
|
||||
boolean first = true;
|
||||
for (int i = 0; i < bits.length; ++i)
|
||||
{
|
||||
|
@ -341,15 +677,14 @@ public class BitSet implements Cloneable, Serializable
|
|||
if ((word & bit) != 0)
|
||||
{
|
||||
if (! first)
|
||||
r += ", ";
|
||||
r += Integer.toString(64 * i + j);
|
||||
r.append(", ");
|
||||
r.append(64 * i + j);
|
||||
first = false;
|
||||
}
|
||||
bit <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return r += "}";
|
||||
return r.append("}").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -358,31 +693,29 @@ public class BitSet implements Cloneable, Serializable
|
|||
* remainder of the two sets (the elements that are in one set,
|
||||
* but not in the other). The result is stored into this bit set,
|
||||
* which grows as necessary.
|
||||
* @param set the second bit set.
|
||||
* @exception OutOfMemoryError if the current set can't grow.
|
||||
* @require set != null
|
||||
*
|
||||
* @param bs the second bit set
|
||||
* @throws NullPointerException if bs is null
|
||||
*/
|
||||
public void xor(BitSet bs)
|
||||
{
|
||||
ensure(bs.bits.length - 1);
|
||||
int i;
|
||||
for (i = 0; i < bs.bits.length; ++i)
|
||||
for (int i = bs.bits.length - 1; i >= 0; i--)
|
||||
bits[i] ^= bs.bits[i];
|
||||
}
|
||||
|
||||
// Make sure the vector is big enough.
|
||||
/**
|
||||
* Make sure the vector is big enough.
|
||||
*
|
||||
* @param lastElt the size needed for the bits array
|
||||
*/
|
||||
private final void ensure(int lastElt)
|
||||
{
|
||||
if (lastElt + 1 > bits.length)
|
||||
if (lastElt >= bits.length)
|
||||
{
|
||||
long[] nd = new long[lastElt + 1];
|
||||
System.arraycopy(bits, 0, nd, 0, bits.length);
|
||||
bits = nd;
|
||||
}
|
||||
}
|
||||
|
||||
// The actual bits.
|
||||
long[] bits;
|
||||
|
||||
private static final long serialVersionUID = 7997698588986878753L;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/* Dictionary.java -- an abstract (and essentially worthless)
|
||||
class which is Hashtable's superclass
|
||||
Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -35,49 +35,88 @@ package java.util;
|
|||
* This is an abstract class which has really gone by the wayside.
|
||||
* People at Javasoft are probably embarrassed by it. At this point,
|
||||
* it might as well be an interface rather than a class, but it remains
|
||||
* this poor, laugable skeleton for the sake of backwards compatibility.
|
||||
* this poor, laughable skeleton for the sake of backwards compatibility.
|
||||
* At any rate, this was what came before the <pre>Map</pre> interface
|
||||
* in the Collections framework.
|
||||
*
|
||||
* @author Jon Zeppieri
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Map
|
||||
* @see Hashtable
|
||||
* @since 1.0
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public abstract class Dictionary extends Object
|
||||
{
|
||||
/** returns an Enumeration of the values in this Dictionary */
|
||||
/**
|
||||
* Sole constructor (often called implicitly).
|
||||
*/
|
||||
public Dictionary()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Enumeration of the values in this Dictionary.
|
||||
*
|
||||
* @return an Enumeration of the values
|
||||
* @see #keys()
|
||||
*/
|
||||
public abstract Enumeration elements();
|
||||
|
||||
/**
|
||||
* returns the value associated with the supplied key, or null
|
||||
* if no such value exists
|
||||
* Returns the value associated with the supplied key, or null
|
||||
* if no such value exists. Since Dictionaries are not allowed null keys
|
||||
* or elements, a null result always means the key is not present.
|
||||
*
|
||||
* @param key the key to use to fetch the value
|
||||
* @return the mapped value
|
||||
* @throws NullPointerException if key is null
|
||||
* @see #put(Object, Object)
|
||||
*/
|
||||
public abstract Object get(Object key);
|
||||
|
||||
/** returns true IFF there are no elements in this Dictionary (size() == 0) */
|
||||
/**
|
||||
* Returns true when there are no elements in this Dictionary.
|
||||
*
|
||||
* @return <code>size() == 0</code>
|
||||
*/
|
||||
public abstract boolean isEmpty();
|
||||
|
||||
/** returns an Enumeration of the keys in this Dictionary */
|
||||
/**
|
||||
* Returns an Enumeration of the keys in this Dictionary
|
||||
*
|
||||
* @return an Enumeration of the keys
|
||||
* @see #elements()
|
||||
*/
|
||||
public abstract Enumeration keys();
|
||||
|
||||
/**
|
||||
* inserts a new value into this Dictionary, located by the
|
||||
* supllied key; note: Dictionary's subclasses (all 1 of them)
|
||||
* do not support null keys or values (I can only assume this
|
||||
* would have been more general)
|
||||
* Inserts a new value into this Dictionary, located by the
|
||||
* supplied key. Dictionary does not support null keys or values, so
|
||||
* a null return can safely be interpreted as adding a new key.
|
||||
*
|
||||
* @param key the key which locates the value
|
||||
* @param value the value to put into the Dictionary
|
||||
* @return the previous value of the key, or null if there was none
|
||||
* @throws NullPointerException if key or value is null
|
||||
* @see #get(Object)
|
||||
*/
|
||||
public abstract Object put(Object key, Object value);
|
||||
|
||||
/**
|
||||
* removes fro the Dictionary the value located by the given key
|
||||
* Removes from the Dictionary the value located by the given key. A null
|
||||
* return safely means that the key was not mapped in the Dictionary.
|
||||
*
|
||||
* @param key the key used to locate the value to be removed
|
||||
* @return the value associated with the removed key
|
||||
* @throws NullPointerException if key is null
|
||||
*/
|
||||
public abstract Object remove(Object key);
|
||||
|
||||
/** returns the number of values currently in this Dictionary */
|
||||
/**
|
||||
* Returns the number of values currently in this Dictionary.
|
||||
*
|
||||
* @return the number of keys in the Dictionary
|
||||
*/
|
||||
public abstract int size();
|
||||
}
|
||||
|
|
|
@ -53,14 +53,16 @@ import java.io.ObjectOutputStream;
|
|||
* <p>
|
||||
*
|
||||
* Under ideal circumstances (no collisions), HashMap offers O(1)
|
||||
* performance on most operations (<pre>containsValue()</pre> is,
|
||||
* performance on most operations (<code>containsValue()</code> is,
|
||||
* of course, O(n)). In the worst case (all keys map to the same
|
||||
* hash code -- very unlikely), most operations are O(n).
|
||||
* <p>
|
||||
*
|
||||
* HashMap is part of the JDK1.2 Collections API. It differs from
|
||||
* Hashtable in that it accepts the null key and null values, and it
|
||||
* does not support "Enumeration views."
|
||||
* does not support "Enumeration views." Also, it is not synchronized;
|
||||
* if you plan to use it in multiple threads, consider using:<br>
|
||||
* <code>Map m = Collections.synchronizedMap(new HashMap(...));</code>
|
||||
* <p>
|
||||
*
|
||||
* The iterators are <i>fail-fast</i>, meaning that any structural
|
||||
|
@ -81,6 +83,7 @@ import java.io.ObjectOutputStream;
|
|||
* @see IdentityHashMap
|
||||
* @see Hashtable
|
||||
* @since 1.2
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class HashMap extends AbstractMap
|
||||
implements Map, Cloneable, Serializable
|
||||
|
@ -88,19 +91,16 @@ public class HashMap extends AbstractMap
|
|||
/**
|
||||
* Default number of buckets. This is the value the JDK 1.3 uses. Some
|
||||
* early documentation specified this value as 101. That is incorrect.
|
||||
* Package visible for use by HashSet.
|
||||
*/
|
||||
static final int DEFAULT_CAPACITY = 11;
|
||||
|
||||
/**
|
||||
* The default load factor; this is explicitly specified by the spec.
|
||||
* Package visible for use by HashSet.
|
||||
*/
|
||||
static final float DEFAULT_LOAD_FACTOR = 0.75f;
|
||||
|
||||
/** "enum" of iterator types. */
|
||||
static final int KEYS = 0,
|
||||
VALUES = 1,
|
||||
ENTRIES = 2;
|
||||
|
||||
/**
|
||||
* Compatible with JDK 1.2.
|
||||
*/
|
||||
|
@ -108,41 +108,54 @@ public class HashMap extends AbstractMap
|
|||
|
||||
/**
|
||||
* The rounded product of the capacity and the load factor; when the number
|
||||
* of elements exceeds the threshold, the HashMap calls <pre>rehash()</pre>.
|
||||
* @serial
|
||||
* of elements exceeds the threshold, the HashMap calls
|
||||
* <code>rehash()</code>.
|
||||
* @serial the threshold for rehashing
|
||||
*/
|
||||
int threshold;
|
||||
private int threshold;
|
||||
|
||||
/**
|
||||
* Load factor of this HashMap: used in computing the threshold.
|
||||
* @serial
|
||||
* Package visible for use by HashSet.
|
||||
* @serial the load factor
|
||||
*/
|
||||
final float loadFactor;
|
||||
|
||||
/**
|
||||
* Array containing the actual key-value mappings.
|
||||
* Package visible for use by nested and subclasses.
|
||||
*/
|
||||
transient HashEntry[] buckets;
|
||||
|
||||
/**
|
||||
* Counts the number of modifications this HashMap has undergone, used
|
||||
* by Iterators to know when to throw ConcurrentModificationExceptions.
|
||||
* Package visible for use by nested and subclasses.
|
||||
*/
|
||||
transient int modCount;
|
||||
|
||||
/**
|
||||
* The size of this HashMap: denotes the number of key-value pairs.
|
||||
* Package visible for use by nested and subclasses.
|
||||
*/
|
||||
transient int size;
|
||||
|
||||
/**
|
||||
* Class to represent an entry in the hash table. Holds a single key-value
|
||||
* pair. This is extended again in LinkedHashMap. See {@link clone()}
|
||||
* for why this must be Cloneable.
|
||||
* The cache for {@link #entrySet()}.
|
||||
*/
|
||||
static class HashEntry extends BasicMapEntry implements Cloneable
|
||||
private transient Set entries;
|
||||
|
||||
/**
|
||||
* Class to represent an entry in the hash table. Holds a single key-value
|
||||
* pair. Package visible for use by subclass.
|
||||
*
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
*/
|
||||
static class HashEntry extends BasicMapEntry
|
||||
{
|
||||
/** The next entry in the linked list. */
|
||||
/**
|
||||
* The next entry in the linked list. Package visible for use by subclass.
|
||||
*/
|
||||
HashEntry next;
|
||||
|
||||
/**
|
||||
|
@ -158,7 +171,8 @@ public class HashMap extends AbstractMap
|
|||
/**
|
||||
* Called when this entry is removed from the map. This version simply
|
||||
* returns the value, but in LinkedHashMap, it must also do bookkeeping.
|
||||
* @return the value of this key as it is removed.
|
||||
*
|
||||
* @return the value of this key as it is removed
|
||||
*/
|
||||
Object cleanup()
|
||||
{
|
||||
|
@ -182,9 +196,8 @@ public class HashMap extends AbstractMap
|
|||
*
|
||||
* Every element in Map m will be put into this new HashMap.
|
||||
*
|
||||
* @param m a Map whose key / value pairs will be put into
|
||||
* the new HashMap. <b>NOTE: key / value pairs
|
||||
* are not cloned in this constructor.</b>
|
||||
* @param m a Map whose key / value pairs will be put into the new HashMap.
|
||||
* <b>NOTE: key / value pairs are not cloned in this constructor.</b>
|
||||
* @throws NullPointerException if m is null
|
||||
*/
|
||||
public HashMap(Map m)
|
||||
|
@ -197,8 +210,8 @@ public class HashMap extends AbstractMap
|
|||
* Construct a new HashMap with a specific inital capacity and
|
||||
* default load factor of 0.75.
|
||||
*
|
||||
* @param initialCapacity the initial capacity of this HashMap (>=0)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0)
|
||||
* @param initialCapacity the initial capacity of this HashMap (>=0)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0)
|
||||
*/
|
||||
public HashMap(int initialCapacity)
|
||||
{
|
||||
|
@ -208,10 +221,10 @@ public class HashMap extends AbstractMap
|
|||
/**
|
||||
* Construct a new HashMap with a specific inital capacity and load factor.
|
||||
*
|
||||
* @param initialCapacity the initial capacity (>=0)
|
||||
* @param loadFactor the load factor (>0, not NaN)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0) ||
|
||||
* ! (loadFactor > 0.0)
|
||||
* @param initialCapacity the initial capacity (>=0)
|
||||
* @param loadFactor the load factor (> 0, not NaN)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0) ||
|
||||
* ! (loadFactor > 0.0)
|
||||
*/
|
||||
public HashMap(int initialCapacity, float loadFactor)
|
||||
{
|
||||
|
@ -229,7 +242,8 @@ public class HashMap extends AbstractMap
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the number of kay-value mappings currently in this Map
|
||||
* Returns the number of kay-value mappings currently in this Map.
|
||||
*
|
||||
* @return the size
|
||||
*/
|
||||
public int size()
|
||||
|
@ -238,7 +252,8 @@ public class HashMap extends AbstractMap
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if there are no key-value mappings currently in this Map
|
||||
* Returns true if there are no key-value mappings currently in this Map.
|
||||
*
|
||||
* @return <code>size() == 0</code>
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
|
@ -246,52 +261,9 @@ public class HashMap extends AbstractMap
|
|||
return size == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this HashMap contains a value <pre>o</pre>, such that
|
||||
* <pre>o.equals(value)</pre>.
|
||||
*
|
||||
* @param value the value to search for in this HashMap
|
||||
* @return true if at least one key maps to the value
|
||||
*/
|
||||
public boolean containsValue(Object value)
|
||||
{
|
||||
for (int i = buckets.length - 1; i >= 0; i--)
|
||||
{
|
||||
HashEntry e = buckets[i];
|
||||
while (e != null)
|
||||
{
|
||||
if (value == null ? e.value == null : value.equals(e.value))
|
||||
return true;
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the supplied object <pre>equals()</pre> a key
|
||||
* in this HashMap.
|
||||
*
|
||||
* @param key the key to search for in this HashMap
|
||||
* @return true if the key is in the table
|
||||
* @see #containsValue(Object)
|
||||
*/
|
||||
public boolean containsKey(Object key)
|
||||
{
|
||||
int idx = hash(key);
|
||||
HashEntry e = buckets[idx];
|
||||
while (e != null)
|
||||
{
|
||||
if (key == null ? e.key == null : key.equals(e.key))
|
||||
return true;
|
||||
e = e.next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value in this HashMap associated with the supplied key,
|
||||
* or <pre>null</pre> if the key maps to nothing. NOTE: Since the value
|
||||
* or <code>null</code> if the key maps to nothing. NOTE: Since the value
|
||||
* could also be null, you must use containsKey to see if this key
|
||||
* actually maps to something.
|
||||
*
|
||||
|
@ -306,13 +278,34 @@ public class HashMap extends AbstractMap
|
|||
HashEntry e = buckets[idx];
|
||||
while (e != null)
|
||||
{
|
||||
if (key == null ? e.key == null : key.equals(e.key))
|
||||
if (equals(key, e.key))
|
||||
return e.value;
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the supplied object <code>equals()</code> a key
|
||||
* in this HashMap.
|
||||
*
|
||||
* @param key the key to search for in this HashMap
|
||||
* @return true if the key is in the table
|
||||
* @see #containsValue(Object)
|
||||
*/
|
||||
public boolean containsKey(Object key)
|
||||
{
|
||||
int idx = hash(key);
|
||||
HashEntry e = buckets[idx];
|
||||
while (e != null)
|
||||
{
|
||||
if (equals(key, e.key))
|
||||
return true;
|
||||
e = e.next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the supplied value into the Map, mapped by the supplied key.
|
||||
* The value may be retrieved by any object which <code>equals()</code>
|
||||
|
@ -328,13 +321,12 @@ public class HashMap extends AbstractMap
|
|||
*/
|
||||
public Object put(Object key, Object value)
|
||||
{
|
||||
modCount++;
|
||||
int idx = hash(key);
|
||||
HashEntry e = buckets[idx];
|
||||
|
||||
while (e != null)
|
||||
{
|
||||
if (key == null ? e.key == null : key.equals(e.key))
|
||||
if (equals(key, e.key))
|
||||
// Must use this method for necessary bookkeeping in LinkedHashMap.
|
||||
return e.setValue(value);
|
||||
else
|
||||
|
@ -342,6 +334,7 @@ public class HashMap extends AbstractMap
|
|||
}
|
||||
|
||||
// At this point, we know we need to add a new entry.
|
||||
modCount++;
|
||||
if (++size > threshold)
|
||||
{
|
||||
rehash();
|
||||
|
@ -354,59 +347,6 @@ public class HashMap extends AbstractMap
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for put, that creates and adds a new Entry. This is
|
||||
* overridden in LinkedHashMap for bookkeeping purposes.
|
||||
*
|
||||
* @param key the key of the new Entry
|
||||
* @param value the value
|
||||
* @param idx the index in buckets where the new Entry belongs
|
||||
* @param callRemove Whether to call the removeEldestEntry method.
|
||||
* @see #put(Object, Object)
|
||||
*/
|
||||
void addEntry(Object key, Object value, int idx, boolean callRemove)
|
||||
{
|
||||
HashEntry e = new HashEntry(key, value);
|
||||
|
||||
e.next = buckets[idx];
|
||||
buckets[idx] = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from the HashMap and returns the value which is mapped by the
|
||||
* supplied key. If the key maps to nothing, then the HashMap remains
|
||||
* unchanged, and <pre>null</pre> is returned. NOTE: Since the value
|
||||
* could also be null, you must use containsKey to see if you are
|
||||
* actually removing a mapping.
|
||||
*
|
||||
* @param key the key used to locate the value to remove
|
||||
* @return whatever the key mapped to, if present
|
||||
*/
|
||||
public Object remove(Object key)
|
||||
{
|
||||
modCount++;
|
||||
int idx = hash(key);
|
||||
HashEntry e = buckets[idx];
|
||||
HashEntry last = null;
|
||||
|
||||
while (e != null)
|
||||
{
|
||||
if (key == null ? e.key == null : key.equals(e.key))
|
||||
{
|
||||
if (last == null)
|
||||
buckets[idx] = e.next;
|
||||
else
|
||||
last.next = e.next;
|
||||
size--;
|
||||
// Method call necessary for LinkedHashMap to work correctly.
|
||||
return e.cleanup();
|
||||
}
|
||||
last = e;
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all elements of the given map into this hashtable. If this table
|
||||
* already has a mapping for a key, the new mapping replaces the current
|
||||
|
@ -434,15 +374,76 @@ public class HashMap extends AbstractMap
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from the HashMap and returns the value which is mapped by the
|
||||
* supplied key. If the key maps to nothing, then the HashMap remains
|
||||
* unchanged, and <code>null</code> is returned. NOTE: Since the value
|
||||
* could also be null, you must use containsKey to see if you are
|
||||
* actually removing a mapping.
|
||||
*
|
||||
* @param key the key used to locate the value to remove
|
||||
* @return whatever the key mapped to, if present
|
||||
*/
|
||||
public Object remove(Object key)
|
||||
{
|
||||
int idx = hash(key);
|
||||
HashEntry e = buckets[idx];
|
||||
HashEntry last = null;
|
||||
|
||||
while (e != null)
|
||||
{
|
||||
if (equals(key, e.key))
|
||||
{
|
||||
modCount++;
|
||||
if (last == null)
|
||||
buckets[idx] = e.next;
|
||||
else
|
||||
last.next = e.next;
|
||||
size--;
|
||||
// Method call necessary for LinkedHashMap to work correctly.
|
||||
return e.cleanup();
|
||||
}
|
||||
last = e;
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the Map so it has no keys. This is O(1).
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
modCount++;
|
||||
Arrays.fill(buckets, null);
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this HashMap contains a value <code>o</code>, such that
|
||||
* <code>o.equals(value)</code>.
|
||||
*
|
||||
* @param value the value to search for in this HashMap
|
||||
* @return true if at least one key maps to the value
|
||||
* @see containsKey(Object)
|
||||
*/
|
||||
public boolean containsValue(Object value)
|
||||
{
|
||||
for (int i = buckets.length - 1; i >= 0; i--)
|
||||
{
|
||||
HashEntry e = buckets[i];
|
||||
while (e != null)
|
||||
{
|
||||
if (equals(value, e.value))
|
||||
return true;
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shallow clone of this HashMap. The Map itself is cloned,
|
||||
|
@ -463,6 +464,8 @@ public class HashMap extends AbstractMap
|
|||
}
|
||||
copy.buckets = new HashEntry[buckets.length];
|
||||
copy.putAllInternal(this);
|
||||
// Clear the entry cache. AbstractMap.clone() does the others.
|
||||
copy.entries = null;
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
@ -477,9 +480,10 @@ public class HashMap extends AbstractMap
|
|||
*/
|
||||
public Set keySet()
|
||||
{
|
||||
// Create an AbstractSet with custom implementations of those methods that
|
||||
// can be overridden easily and efficiently.
|
||||
return new AbstractSet()
|
||||
if (keys == null)
|
||||
// Create an AbstractSet with custom implementations of those methods
|
||||
// that can be overridden easily and efficiently.
|
||||
keys = new AbstractSet()
|
||||
{
|
||||
public int size()
|
||||
{
|
||||
|
@ -499,19 +503,20 @@ public class HashMap extends AbstractMap
|
|||
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
return HashMap.this.containsKey(o);
|
||||
return containsKey(o);
|
||||
}
|
||||
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
// Test against the size of the HashMap to determine if anything
|
||||
// really got removed. This is necessary because the return value of
|
||||
// HashMap.remove() is ambiguous in the null case.
|
||||
// really got removed. This is neccessary because the return value
|
||||
// of HashMap.remove() is ambiguous in the null case.
|
||||
int oldsize = size;
|
||||
HashMap.this.remove(o);
|
||||
return (oldsize != size);
|
||||
return oldsize != size;
|
||||
}
|
||||
};
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -526,9 +531,10 @@ public class HashMap extends AbstractMap
|
|||
*/
|
||||
public Collection values()
|
||||
{
|
||||
if (values == null)
|
||||
// We don't bother overriding many of the optional methods, as doing so
|
||||
// wouldn't provide any significant performance advantage.
|
||||
return new AbstractCollection()
|
||||
values = new AbstractCollection()
|
||||
{
|
||||
public int size()
|
||||
{
|
||||
|
@ -546,13 +552,13 @@ public class HashMap extends AbstractMap
|
|||
HashMap.this.clear();
|
||||
}
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "set view" of this HashMap's entries. The set is backed by
|
||||
* the HashMap, so changes in one show up in the other. The set supports
|
||||
* element removal, but not element addition.
|
||||
* <p>
|
||||
* element removal, but not element addition.<p>
|
||||
*
|
||||
* Note that the iterators for all three views, from keySet(), entrySet(),
|
||||
* and values(), traverse the HashMap in the same sequence.
|
||||
|
@ -564,9 +570,10 @@ public class HashMap extends AbstractMap
|
|||
*/
|
||||
public Set entrySet()
|
||||
{
|
||||
// Create an AbstractSet with custom implementations of those methods that
|
||||
// can be overridden easily and efficiently.
|
||||
return new AbstractSet()
|
||||
if (entries == null)
|
||||
// Create an AbstractSet with custom implementations of those methods
|
||||
// that can be overridden easily and efficiently.
|
||||
entries = new AbstractSet()
|
||||
{
|
||||
public int size()
|
||||
{
|
||||
|
@ -600,17 +607,25 @@ public class HashMap extends AbstractMap
|
|||
return false;
|
||||
}
|
||||
};
|
||||
return entries;
|
||||
}
|
||||
|
||||
/** Helper method that returns an index in the buckets array for `key;
|
||||
* based on its hashCode().
|
||||
/**
|
||||
* Helper method for put, that creates and adds a new Entry. This is
|
||||
* overridden in LinkedHashMap for bookkeeping purposes.
|
||||
*
|
||||
* @param key the key
|
||||
* @return the bucket number
|
||||
* @param key the key of the new Entry
|
||||
* @param value the value
|
||||
* @param idx the index in buckets where the new Entry belongs
|
||||
* @param callRemove whether to call the removeEldestEntry method
|
||||
* @see #put(Object, Object)
|
||||
*/
|
||||
int hash(Object key)
|
||||
void addEntry(Object key, Object value, int idx, boolean callRemove)
|
||||
{
|
||||
return (key == null) ? 0 : Math.abs(key.hashCode() % buckets.length);
|
||||
HashEntry e = new HashEntry(key, value);
|
||||
|
||||
e.next = buckets[idx];
|
||||
buckets[idx] = e;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -637,6 +652,52 @@ public class HashMap extends AbstractMap
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that returns an index in the buckets array for `key'
|
||||
* based on its hashCode(). Package visible for use by subclasses.
|
||||
*
|
||||
* @param key the key
|
||||
* @return the bucket number
|
||||
*/
|
||||
final int hash(Object key)
|
||||
{
|
||||
return key == null ? 0 : Math.abs(key.hashCode() % buckets.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a parameterized iterator. Must be overrideable, since
|
||||
* LinkedHashMap iterates in a different order.
|
||||
*
|
||||
* @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
|
||||
* @return the appropriate iterator
|
||||
*/
|
||||
Iterator iterator(int type)
|
||||
{
|
||||
return new HashIterator(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simplified, more efficient internal implementation of putAll(). The
|
||||
* Map constructor and clone() should not call putAll or put, in order to
|
||||
* be compatible with the JDK implementation with respect to subclasses.
|
||||
*
|
||||
* @param m the map to initialize this from
|
||||
*/
|
||||
void putAllInternal(Map m)
|
||||
{
|
||||
Iterator itr = m.entrySet().iterator();
|
||||
int msize = m.size();
|
||||
this.size = msize;
|
||||
|
||||
for (; msize > 0; msize--)
|
||||
{
|
||||
Map.Entry e = (Map.Entry) itr.next();
|
||||
Object key = e.getKey();
|
||||
int idx = hash(key);
|
||||
addEntry(key, e.getValue(), idx, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the size of the HashMap and rehashes all keys to new array
|
||||
* indices; this is called when the addition of a new value would cause
|
||||
|
@ -681,35 +742,6 @@ public class HashMap extends AbstractMap
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a parameterized iterator. Must be overrideable, since
|
||||
* LinkedHashMap iterates in a different order.
|
||||
* @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
|
||||
* @return the appropriate iterator
|
||||
*/
|
||||
Iterator iterator(int type)
|
||||
{
|
||||
return new HashIterator(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simplified, more efficient internal implementation of putAll(). The
|
||||
* Map constructor and clone() should not call putAll or put, in order to
|
||||
* be compatible with the JDK implementation with respect to subclasses.
|
||||
*/
|
||||
void putAllInternal(Map m)
|
||||
{
|
||||
Iterator itr = m.entrySet().iterator();
|
||||
|
||||
for (int msize = m.size(); msize > 0; msize--)
|
||||
{
|
||||
Map.Entry e = (Map.Entry) itr.next();
|
||||
Object key = e.getKey();
|
||||
int idx = hash(key);
|
||||
addEntry(key, e.getValue(), idx, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this object to the given stream.
|
||||
*
|
||||
|
@ -757,9 +789,6 @@ public class HashMap extends AbstractMap
|
|||
// Read and use capacity.
|
||||
buckets = new HashEntry[s.readInt()];
|
||||
int len = s.readInt();
|
||||
// Already happens automatically.
|
||||
// size = 0;
|
||||
// modCount = 0;
|
||||
|
||||
// Read and use key/value pairs.
|
||||
for ( ; len > 0; len--)
|
||||
|
@ -773,29 +802,29 @@ public class HashMap extends AbstractMap
|
|||
*
|
||||
* @author Jon Zeppieri
|
||||
*/
|
||||
class HashIterator implements Iterator
|
||||
private final class HashIterator implements Iterator
|
||||
{
|
||||
/**
|
||||
* The type of this Iterator: {@link #KEYS}, {@link #VALUES},
|
||||
* or {@link #ENTRIES}.
|
||||
*/
|
||||
final int type;
|
||||
private final int type;
|
||||
/**
|
||||
* The number of modifications to the backing HashMap that we know about.
|
||||
*/
|
||||
int knownMod = modCount;
|
||||
private int knownMod = modCount;
|
||||
/** The number of elements remaining to be returned by next(). */
|
||||
int count = size;
|
||||
private int count = size;
|
||||
/** Current index in the physical hash table. */
|
||||
int idx = buckets.length;
|
||||
private int idx = buckets.length;
|
||||
/** The last Entry returned by a next() call. */
|
||||
HashEntry last;
|
||||
private HashEntry last;
|
||||
/**
|
||||
* The next entry that should be returned by next(). It is set to something
|
||||
* if we're iterating through a bucket that contains multiple linked
|
||||
* entries. It is null if next() needs to find a new bucket.
|
||||
*/
|
||||
HashEntry next;
|
||||
private HashEntry next;
|
||||
|
||||
/**
|
||||
* Construct a new HashIterator with the supplied type.
|
||||
|
@ -840,14 +869,14 @@ public class HashMap extends AbstractMap
|
|||
last = e;
|
||||
if (type == VALUES)
|
||||
return e.value;
|
||||
else if (type == KEYS)
|
||||
if (type == KEYS)
|
||||
return e.key;
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from the backing HashMap the last element which was fetched
|
||||
* with the <pre>next()</pre> method.
|
||||
* with the <code>next()</code> method.
|
||||
* @throws ConcurrentModificationException if the HashMap was modified
|
||||
* @throws IllegalStateException if called when there is no last element
|
||||
*/
|
||||
|
@ -859,8 +888,8 @@ public class HashMap extends AbstractMap
|
|||
throw new IllegalStateException();
|
||||
|
||||
HashMap.this.remove(last.key);
|
||||
knownMod++;
|
||||
last = null;
|
||||
knownMod++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* HashSet.java -- a class providing a HashMap-backet Set
|
||||
Copyright (C) 1998, 1999 Free Software Foundation, Inc.
|
||||
/* HashSet.java -- a class providing a HashMap-backed Set
|
||||
Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -33,87 +33,115 @@ import java.io.ObjectInputStream;
|
|||
import java.io.ObjectOutputStream;
|
||||
|
||||
/**
|
||||
* This class provides a HashMap-backed implementation of the
|
||||
* Set interface.
|
||||
*
|
||||
* Each element in the Set is a key in the backing HashMap; each key
|
||||
* maps to a static token, denoting that the key does, in fact, exist.
|
||||
* This class provides a HashMap-backed implementation of the Set interface.
|
||||
* <p>
|
||||
*
|
||||
* Most operations are O(1), assuming no hash collisions. In the worst
|
||||
* case (where all hases collide), operations are O(n).
|
||||
* case (where all hashes collide), operations are O(n). Setting the
|
||||
* initial capacity too low will force many resizing operations, but
|
||||
* setting the initial capacity too high (or loadfactor too low) leads
|
||||
* to wasted memory and slower iteration.
|
||||
* <p>
|
||||
*
|
||||
* HashSet is a part of the JDK1.2 Collections API.
|
||||
* HashSet accepts the null key and null values. It is not synchronized,
|
||||
* so if you need multi-threaded access, consider using:<br>
|
||||
* <code>Set s = Collections.synchronizedSet(new HashSet(...));</code>
|
||||
* <p>
|
||||
*
|
||||
* The iterators are <i>fail-fast</i>, meaning that any structural
|
||||
* modification, except for <code>remove()</code> called on the iterator
|
||||
* itself, cause the iterator to throw a
|
||||
* {@link ConcurrentModificationException} rather than exhibit
|
||||
* non-deterministic behavior.
|
||||
*
|
||||
* @author Jon Zeppieri
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Collection
|
||||
* @see Set
|
||||
* @see TreeSet
|
||||
* @see Collections#synchronizedSet(Set)
|
||||
* @see HashMap
|
||||
* @see LinkedHashSet
|
||||
* @since 1.2
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class HashSet extends AbstractSet
|
||||
implements Set, Cloneable, Serializable
|
||||
{
|
||||
/** the HashMap which backs this Set */
|
||||
transient HashMap map;
|
||||
static final long serialVersionUID = -5024744406713321676L;
|
||||
/**
|
||||
* Compatible with JDK 1.2.
|
||||
*/
|
||||
private static final long serialVersionUID = -5024744406713321676L;
|
||||
|
||||
/**
|
||||
* construct a new, empty HashSet whose backing HashMap has the default
|
||||
* capacity and loadFacor
|
||||
* The HashMap which backs this Set.
|
||||
*/
|
||||
private transient HashMap map;
|
||||
|
||||
/**
|
||||
* Construct a new, empty HashSet whose backing HashMap has the default
|
||||
* capacity (11) and loadFacor (0.75).
|
||||
*/
|
||||
public HashSet()
|
||||
{
|
||||
map = new HashMap();
|
||||
this(HashMap.DEFAULT_CAPACITY, HashMap.DEFAULT_LOAD_FACTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* construct a new, empty HashSet whose backing HashMap has the supplied
|
||||
* capacity and the default load factor
|
||||
* Construct a new, empty HashSet whose backing HashMap has the supplied
|
||||
* capacity and the default load factor (0.75).
|
||||
*
|
||||
* @param initialCapacity the initial capacity of the backing
|
||||
* HashMap
|
||||
* @param initialCapacity the initial capacity of the backing HashMap
|
||||
* @throws IllegalArgumentException if the capacity is negative
|
||||
*/
|
||||
public HashSet(int initialCapacity)
|
||||
{
|
||||
map = new HashMap(initialCapacity);
|
||||
this(initialCapacity, HashMap.DEFAULT_LOAD_FACTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* construct a new, empty HashSet whose backing HashMap has the supplied
|
||||
* capacity and load factor
|
||||
* Construct a new, empty HashSet whose backing HashMap has the supplied
|
||||
* capacity and load factor.
|
||||
*
|
||||
* @param initialCapacity the initial capacity of the backing
|
||||
* HashMap
|
||||
* @param initialCapacity the initial capacity of the backing HashMap
|
||||
* @param loadFactor the load factor of the backing HashMap
|
||||
* @throws IllegalArgumentException if either argument is negative, or
|
||||
* if loadFactor is POSITIVE_INFINITY or NaN
|
||||
*/
|
||||
public HashSet(int initialCapacity, float loadFactor)
|
||||
{
|
||||
map = new HashMap(initialCapacity, loadFactor);
|
||||
map = init(initialCapacity, loadFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* construct a new HashSet with the same elements as are in the supplied
|
||||
* collection (eliminating any duplicates, of course; the backing HashMap
|
||||
* will have the default capacity and load factor
|
||||
* Construct a new HashSet with the same elements as are in the supplied
|
||||
* collection (eliminating any duplicates, of course). The backing storage
|
||||
* has twice the size of the collection, or the default size of 11,
|
||||
* whichever is greater; and the default load factor (0.75).
|
||||
*
|
||||
* @param c a collection containing the elements with
|
||||
* which this set will be initialized
|
||||
* @param c a collection of initial set elements
|
||||
* @throws NullPointerException if c is null
|
||||
*/
|
||||
public HashSet(Collection c)
|
||||
{
|
||||
map = new HashMap();
|
||||
this(Math.max(2 * c.size(), HashMap.DEFAULT_CAPACITY));
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds the given Object to the set if it is not already in the Set,
|
||||
* returns true if teh element was added, false otherwise
|
||||
* Adds the given Object to the set if it is not already in the Set.
|
||||
* This set permits a null element.
|
||||
*
|
||||
* @param o the Object to add to this Set
|
||||
* @return true if the set did not already contain o
|
||||
*/
|
||||
public boolean add(Object o)
|
||||
{
|
||||
return (map.put(o, Boolean.TRUE) == null);
|
||||
return map.put(o, "") == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* empties this Set of all elements; this is a fast operation [O(1)]
|
||||
* Empties this Set of all elements; this takes constant time.
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
|
@ -121,8 +149,10 @@ public class HashSet extends AbstractSet
|
|||
}
|
||||
|
||||
/**
|
||||
* returns a shallow copy of this Set (the Set itself is cloned; its
|
||||
* elements are not)
|
||||
* Returns a shallow copy of this Set. The Set itself is cloned; its
|
||||
* elements are not.
|
||||
*
|
||||
* @return a shallow clone of the set
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
|
@ -133,15 +163,17 @@ public class HashSet extends AbstractSet
|
|||
}
|
||||
catch (CloneNotSupportedException x)
|
||||
{
|
||||
// Impossible to get here.
|
||||
}
|
||||
copy.map = (HashMap) map.clone();
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the supplied element is in this Set, false otherwise
|
||||
* Returns true if the supplied element is in this Set.
|
||||
*
|
||||
* @param o the Object whose presence in this Set we are testing for
|
||||
* @param o the Object to look for
|
||||
* @return true if it is in the set
|
||||
*/
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
|
@ -149,25 +181,35 @@ public class HashSet extends AbstractSet
|
|||
}
|
||||
|
||||
/**
|
||||
* returns true if this set has no elements in it (size() == 0)
|
||||
* Returns true if this set has no elements in it.
|
||||
*
|
||||
* @return <code>size() == 0</code>.
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return map.isEmpty();
|
||||
return map.size == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns an Iterator over the elements of this Set; the Iterator allows
|
||||
* removal of elements
|
||||
* Returns an Iterator over the elements of this Set, which visits the
|
||||
* elements in no particular order. For this class, the Iterator allows
|
||||
* removal of elements. The iterator is fail-fast, and will throw a
|
||||
* ConcurrentModificationException if the set is modified externally.
|
||||
*
|
||||
* @return a set iterator
|
||||
* @see ConcurrentModificationException
|
||||
*/
|
||||
public Iterator iterator()
|
||||
{
|
||||
return map.keySet().iterator();
|
||||
// Avoid creating intermediate keySet() object by using non-public API.
|
||||
return map.iterator(HashMap.KEYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the supplied Object from this Set if it is in the Set; returns
|
||||
* true if an element was removed, false otherwise
|
||||
* Removes the supplied Object from this Set if it is in the Set.
|
||||
*
|
||||
* @param o the object to remove
|
||||
* @return true if an element was removed
|
||||
*/
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
|
@ -175,18 +217,42 @@ public class HashSet extends AbstractSet
|
|||
}
|
||||
|
||||
/**
|
||||
* returns the number of elements in this Set
|
||||
* Returns the number of elements in this Set (its cardinality).
|
||||
*
|
||||
* @return the size of the set
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return map.size();
|
||||
return map.size;
|
||||
}
|
||||
|
||||
/** Serialize this Object in a manner which is binary-compatible with the
|
||||
* JDK */
|
||||
/**
|
||||
* Helper method which initializes the backing Map. Overridden by
|
||||
* LinkedHashSet for correct semantics.
|
||||
*
|
||||
* @param capacity the initial capacity
|
||||
* @param load the initial load factor
|
||||
* @return the backing HashMap
|
||||
*/
|
||||
HashMap init(int capacity, float load)
|
||||
{
|
||||
return new HashMap(capacity, load);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this object to the given stream.
|
||||
*
|
||||
* @param s the stream to write to
|
||||
* @throws IOException if the underlying stream fails
|
||||
* @serialData the <i>capacity</i> (int) and <i>loadFactor</i> (float)
|
||||
* of the backing store, followed by the set size (int),
|
||||
* then a listing of its elements (Object) in no order
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream s) throws IOException
|
||||
{
|
||||
Iterator it = iterator();
|
||||
s.defaultWriteObject();
|
||||
// Avoid creating intermediate keySet() object by using non-public API.
|
||||
Iterator it = map.iterator(HashMap.KEYS);
|
||||
s.writeInt(map.buckets.length);
|
||||
s.writeFloat(map.loadFactor);
|
||||
s.writeInt(map.size);
|
||||
|
@ -194,25 +260,23 @@ public class HashSet extends AbstractSet
|
|||
s.writeObject(it.next());
|
||||
}
|
||||
|
||||
/** Deserialize this Object in a manner which is binary-compatible with
|
||||
* the JDK */
|
||||
private void readObject(ObjectInputStream s) throws IOException,
|
||||
ClassNotFoundException
|
||||
/**
|
||||
* Deserializes this object from the given stream.
|
||||
*
|
||||
* @param s the stream to read from
|
||||
* @throws ClassNotFoundException if the underlying stream fails
|
||||
* @throws IOException if the underlying stream fails
|
||||
* @serialData the <i>capacity</i> (int) and <i>loadFactor</i> (float)
|
||||
* of the backing store, followed by the set size (int),
|
||||
* then a listing of its elements (Object) in no order
|
||||
*/
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
int i, size, capacity;
|
||||
float loadFactor;
|
||||
Object element;
|
||||
s.defaultReadObject();
|
||||
|
||||
capacity = s.readInt();
|
||||
loadFactor = s.readFloat();
|
||||
size = s.readInt();
|
||||
|
||||
map = new HashMap(capacity, loadFactor);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
element = s.readObject();
|
||||
map.put(element, Boolean.TRUE);
|
||||
}
|
||||
map = init(s.readInt(), s.readFloat());
|
||||
for (int size = s.readInt(); size > 0; size--)
|
||||
map.put(s.readObject(), "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,9 @@ import java.io.ObjectOutputStream;
|
|||
* Unlike HashMap, Hashtable does not accept `null' as a key value. Also,
|
||||
* all accesses are synchronized: in a single thread environment, this is
|
||||
* expensive, but in a multi-thread environment, this saves you the effort
|
||||
* of extra synchronization.
|
||||
* of extra synchronization. However, the old-style enumerators are not
|
||||
* synchronized, because they can lead to unspecified behavior even if
|
||||
* they were synchronized. You have been warned.
|
||||
* <p>
|
||||
*
|
||||
* The iterators are <i>fail-fast</i>, meaning that any structural
|
||||
|
@ -84,6 +86,7 @@ import java.io.ObjectOutputStream;
|
|||
* @see IdentityHashMap
|
||||
* @see LinkedHashMap
|
||||
* @since 1.0
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class Hashtable extends Dictionary
|
||||
implements Map, Cloneable, Serializable
|
||||
|
@ -93,6 +96,12 @@ public class Hashtable extends Dictionary
|
|||
*/
|
||||
private static final int DEFAULT_CAPACITY = 11;
|
||||
|
||||
/** An "enum" of iterator types. */
|
||||
// Package visible for use by nested classes.
|
||||
static final int KEYS = 0,
|
||||
VALUES = 1,
|
||||
ENTRIES = 2;
|
||||
|
||||
/**
|
||||
* The default load factor; this is explicitly specified by the spec.
|
||||
*/
|
||||
|
@ -106,39 +115,57 @@ public class Hashtable extends Dictionary
|
|||
/**
|
||||
* The rounded product of the capacity and the load factor; when the number
|
||||
* of elements exceeds the threshold, the Hashtable calls
|
||||
* <pre>rehash()</pre>.
|
||||
* <code>rehash()</code>.
|
||||
* @serial
|
||||
*/
|
||||
int threshold;
|
||||
private int threshold;
|
||||
|
||||
/**
|
||||
* Load factor of this Hashtable: used in computing the threshold.
|
||||
* @serial
|
||||
*/
|
||||
final float loadFactor;
|
||||
private final float loadFactor;
|
||||
|
||||
/**
|
||||
* Array containing the actual key-value mappings.
|
||||
*/
|
||||
// Package visible for use by nested classes.
|
||||
transient HashEntry[] buckets;
|
||||
|
||||
/**
|
||||
* Counts the number of modifications this Hashtable has undergone, used
|
||||
* by Iterators to know when to throw ConcurrentModificationExceptions.
|
||||
*/
|
||||
// Package visible for use by nested classes.
|
||||
transient int modCount;
|
||||
|
||||
/**
|
||||
* The size of this Hashtable: denotes the number of key-value pairs.
|
||||
*/
|
||||
// Package visible for use by nested classes.
|
||||
transient int size;
|
||||
|
||||
/**
|
||||
* The cache for {@link #keySet()}.
|
||||
*/
|
||||
private transient Set keys;
|
||||
|
||||
/**
|
||||
* The cache for {@link #values()}.
|
||||
*/
|
||||
private transient Collection values;
|
||||
|
||||
/**
|
||||
* The cache for {@link #entrySet()}.
|
||||
*/
|
||||
private transient Set entries;
|
||||
|
||||
/**
|
||||
* Class to represent an entry in the hash table. Holds a single key-value
|
||||
* pair. A Hashtable Entry is identical to a HashMap Entry, except that
|
||||
* `null' is not allowed for keys and values.
|
||||
*/
|
||||
static class HashEntry extends BasicMapEntry
|
||||
private static final class HashEntry extends BasicMapEntry
|
||||
{
|
||||
/** The next entry in the linked list. */
|
||||
HashEntry next;
|
||||
|
@ -159,7 +186,7 @@ public class Hashtable extends Dictionary
|
|||
* @return the prior value
|
||||
* @throws NullPointerException if <code>newVal</code> is null
|
||||
*/
|
||||
public final Object setValue(Object newVal)
|
||||
public Object setValue(Object newVal)
|
||||
{
|
||||
if (newVal == null)
|
||||
throw new NullPointerException();
|
||||
|
@ -193,15 +220,15 @@ public class Hashtable extends Dictionary
|
|||
public Hashtable(Map m)
|
||||
{
|
||||
this(Math.max(m.size() * 2, DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR);
|
||||
putAll(m);
|
||||
putAllInternal(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new Hashtable with a specific inital capacity and
|
||||
* default load factor of 0.75.
|
||||
*
|
||||
* @param initialCapacity the initial capacity of this Hashtable (>=0)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0)
|
||||
* @param initialCapacity the initial capacity of this Hashtable (>= 0)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0)
|
||||
*/
|
||||
public Hashtable(int initialCapacity)
|
||||
{
|
||||
|
@ -212,10 +239,10 @@ public class Hashtable extends Dictionary
|
|||
* Construct a new Hashtable with a specific initial capacity and
|
||||
* load factor.
|
||||
*
|
||||
* @param initialCapacity the initial capacity (>=0)
|
||||
* @param loadFactor the load factor (>0, not NaN)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0) ||
|
||||
* ! (loadFactor > 0.0)
|
||||
* @param initialCapacity the initial capacity (>= 0)
|
||||
* @param loadFactor the load factor (> 0, not NaN)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0) ||
|
||||
* ! (loadFactor > 0.0)
|
||||
*/
|
||||
public Hashtable(int initialCapacity, float loadFactor)
|
||||
{
|
||||
|
@ -251,30 +278,36 @@ public class Hashtable extends Dictionary
|
|||
}
|
||||
|
||||
/**
|
||||
* Return an enumeration of the keys of this table.
|
||||
* Return an enumeration of the keys of this table. There's no point
|
||||
* in synchronizing this, as you have already been warned that the
|
||||
* enumeration is not specified to be thread-safe.
|
||||
*
|
||||
* @return the keys
|
||||
* @see #elements()
|
||||
* @see #keySet()
|
||||
*/
|
||||
public synchronized Enumeration keys()
|
||||
public Enumeration keys()
|
||||
{
|
||||
return new Enumerator(Enumerator.KEYS);
|
||||
return new Enumerator(KEYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an enumeration of the values of this table.
|
||||
* Return an enumeration of the values of this table. There's no point
|
||||
* in synchronizing this, as you have already been warned that the
|
||||
* enumeration is not specified to be thread-safe.
|
||||
*
|
||||
* @return the values
|
||||
* @see #keys()
|
||||
* @see #values()
|
||||
*/
|
||||
public synchronized Enumeration elements()
|
||||
public Enumeration elements()
|
||||
{
|
||||
return new Enumerator(Enumerator.VALUES);
|
||||
return new Enumerator(VALUES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Hashtable contains a value <pre>o</pre>,
|
||||
* such that <pre>o.equals(value)</pre>. This is the same as
|
||||
* Returns true if this Hashtable contains a value <code>o</code>,
|
||||
* such that <code>o.equals(value)</code>. This is the same as
|
||||
* <code>containsValue()</code>, and is O(n).
|
||||
* <p>
|
||||
*
|
||||
|
@ -284,22 +317,37 @@ public class Hashtable extends Dictionary
|
|||
*
|
||||
* @param value the value to search for in this Hashtable
|
||||
* @return true if at least one key maps to the value
|
||||
* @throws NullPointerException if <pre>value</pre> is null
|
||||
* @throws NullPointerException if <code>value</code> is null
|
||||
* @see #containsValue(Object)
|
||||
* @see #containsKey(Object)
|
||||
*/
|
||||
public synchronized boolean contains(Object value)
|
||||
{
|
||||
// Check if value is null in case Hashtable is empty.
|
||||
// Check if value is null.
|
||||
if (value == null)
|
||||
throw new NullPointerException();
|
||||
return containsValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Hashtable contains a value <code>o</code>, such that
|
||||
* <code>o.equals(value)</code>. This is the new API for the old
|
||||
* <code>contains()</code>, except that it is forgiving of null.
|
||||
*
|
||||
* @param value the value to search for in this Hashtable
|
||||
* @return true if at least one key maps to the value
|
||||
* @see #contains(Object)
|
||||
* @see #containsKey(Object)
|
||||
* @since 1.2
|
||||
*/
|
||||
public boolean containsValue(Object value)
|
||||
{
|
||||
for (int i = buckets.length - 1; i >= 0; i--)
|
||||
{
|
||||
HashEntry e = buckets[i];
|
||||
while (e != null)
|
||||
{
|
||||
if (value.equals(e.value))
|
||||
if (AbstractCollection.equals(value, e.value))
|
||||
return true;
|
||||
e = e.next;
|
||||
}
|
||||
|
@ -308,24 +356,7 @@ public class Hashtable extends Dictionary
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Hashtable contains a value <pre>o</pre>, such that
|
||||
* <pre>o.equals(value)</pre>. This is the new API for the old
|
||||
* <code>contains()</code>.
|
||||
*
|
||||
* @param value the value to search for in this Hashtable
|
||||
* @return true if at least one key maps to the value
|
||||
* @throws NullPointerException if <pre>value</pre> is null
|
||||
* @see #contains(Object)
|
||||
* @see #containsKey(Object)
|
||||
* @since 1.2
|
||||
*/
|
||||
public boolean containsValue(Object value)
|
||||
{
|
||||
return contains(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the supplied object <pre>equals()</pre> a key
|
||||
* Returns true if the supplied object <code>equals()</code> a key
|
||||
* in this Hashtable.
|
||||
*
|
||||
* @param key the key to search for in this Hashtable
|
||||
|
@ -348,7 +379,7 @@ public class Hashtable extends Dictionary
|
|||
|
||||
/**
|
||||
* Return the value in this Hashtable associated with the supplied key,
|
||||
* or <pre>null</pre> if the key maps to nothing.
|
||||
* or <code>null</code> if the key maps to nothing.
|
||||
*
|
||||
* @param key the key for which to fetch an associated value
|
||||
* @return what the key maps to, if present
|
||||
|
@ -383,7 +414,6 @@ public class Hashtable extends Dictionary
|
|||
*/
|
||||
public synchronized Object put(Object key, Object value)
|
||||
{
|
||||
modCount++;
|
||||
int idx = hash(key);
|
||||
HashEntry e = buckets[idx];
|
||||
|
||||
|
@ -407,6 +437,7 @@ public class Hashtable extends Dictionary
|
|||
}
|
||||
|
||||
// At this point, we know we need to add a new entry.
|
||||
modCount++;
|
||||
if (++size > threshold)
|
||||
{
|
||||
rehash();
|
||||
|
@ -425,15 +456,18 @@ public class Hashtable extends Dictionary
|
|||
/**
|
||||
* Removes from the table and returns the value which is mapped by the
|
||||
* supplied key. If the key maps to nothing, then the table remains
|
||||
* unchanged, and <pre>null</pre> is returned.
|
||||
* unchanged, and <code>null</code> is returned.
|
||||
* <b>NOTE:</b>Map.remove and Dictionary.remove disagree whether null
|
||||
* is a valid parameter; at the moment, this implementation obeys Map.remove,
|
||||
* and silently ignores null.
|
||||
*
|
||||
* @param key the key used to locate the value to remove
|
||||
* @return whatever the key mapped to, if present
|
||||
* @throws NullPointerException if key is null
|
||||
*/
|
||||
public synchronized Object remove(Object key)
|
||||
{
|
||||
modCount++;
|
||||
if (key == null)
|
||||
return null;
|
||||
int idx = hash(key);
|
||||
HashEntry e = buckets[idx];
|
||||
HashEntry last = null;
|
||||
|
@ -442,6 +476,7 @@ public class Hashtable extends Dictionary
|
|||
{
|
||||
if (key.equals(e.key))
|
||||
{
|
||||
modCount++;
|
||||
if (last == null)
|
||||
buckets[idx] = e.next;
|
||||
else
|
||||
|
@ -487,11 +522,14 @@ public class Hashtable extends Dictionary
|
|||
* Clears the hashtable so it has no keys. This is O(1).
|
||||
*/
|
||||
public synchronized void clear()
|
||||
{
|
||||
if (size > 0)
|
||||
{
|
||||
modCount++;
|
||||
Arrays.fill(buckets, null);
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a shallow clone of this Hashtable. The Map itself is cloned,
|
||||
|
@ -511,36 +549,18 @@ public class Hashtable extends Dictionary
|
|||
// This is impossible.
|
||||
}
|
||||
copy.buckets = new HashEntry[buckets.length];
|
||||
|
||||
for (int i = buckets.length - 1; i >= 0; i--)
|
||||
{
|
||||
HashEntry e = buckets[i];
|
||||
HashEntry last = null;
|
||||
|
||||
while (e != null)
|
||||
{
|
||||
if (last == null)
|
||||
{
|
||||
last = new HashEntry(e.key, e.value);
|
||||
copy.buckets[i] = last;
|
||||
}
|
||||
else
|
||||
{
|
||||
last.next = new HashEntry(e.key, e.value);
|
||||
last = last.next;
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
copy.putAllInternal(this);
|
||||
// Clear the caches.
|
||||
copy.keys = null;
|
||||
copy.values = null;
|
||||
copy.entries = null;
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this Hashtable to a String, surrounded by braces (<pre>'{'</pre>
|
||||
* and <pre>'}'</pre>), key/value pairs listed with an equals sign between,
|
||||
* (<pre>'='</pre>), and pairs separated by comma and space
|
||||
* (<pre>", "</pre>).
|
||||
* <p>
|
||||
* Converts this Hashtable to a String, surrounded by braces, and with
|
||||
* key/value pairs listed with an equals sign between, separated by a
|
||||
* comma and space. For example, <code>"{a=1, b=2}"</code>.<p>
|
||||
*
|
||||
* NOTE: if the <code>toString()</code> method of any key or value
|
||||
* throws an exception, this will fail for the same reason.
|
||||
|
@ -552,7 +572,7 @@ public class Hashtable extends Dictionary
|
|||
// Since we are already synchronized, and entrySet().iterator()
|
||||
// would repeatedly re-lock/release the monitor, we directly use the
|
||||
// unsynchronized HashIterator instead.
|
||||
Iterator entries = new HashIterator(HashIterator.ENTRIES);
|
||||
Iterator entries = new HashIterator(ENTRIES);
|
||||
StringBuffer r = new StringBuffer("{");
|
||||
for (int pos = size; pos > 0; pos--)
|
||||
{
|
||||
|
@ -568,9 +588,11 @@ public class Hashtable extends Dictionary
|
|||
* Returns a "set view" of this Hashtable's keys. The set is backed by
|
||||
* the hashtable, so changes in one show up in the other. The set supports
|
||||
* element removal, but not element addition. The set is properly
|
||||
* synchronized on the original hashtable. The set will throw a
|
||||
* {@link NullPointerException} if null is passed to <code>contains</code>,
|
||||
* <code>remove</code>, or related methods.
|
||||
* synchronized on the original hashtable. Sun has not documented the
|
||||
* proper interaction of null with this set, but has inconsistent behavior
|
||||
* in the JDK. Therefore, in this implementation, contains, remove,
|
||||
* containsAll, retainAll, removeAll, and equals just ignore a null key
|
||||
* rather than throwing a {@link NullPointerException}.
|
||||
*
|
||||
* @return a set view of the keys
|
||||
* @see #values()
|
||||
|
@ -579,8 +601,10 @@ public class Hashtable extends Dictionary
|
|||
*/
|
||||
public Set keySet()
|
||||
{
|
||||
// Create a synchronized AbstractSet with custom implementations of those
|
||||
// methods that can be overridden easily and efficiently.
|
||||
if (keys == null)
|
||||
{
|
||||
// Create a synchronized AbstractSet with custom implementations of
|
||||
// those methods that can be overridden easily and efficiently.
|
||||
Set r = new AbstractSet()
|
||||
{
|
||||
public int size()
|
||||
|
@ -590,7 +614,7 @@ public class Hashtable extends Dictionary
|
|||
|
||||
public Iterator iterator()
|
||||
{
|
||||
return new HashIterator(HashIterator.KEYS);
|
||||
return new HashIterator(KEYS);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
|
@ -600,29 +624,33 @@ public class Hashtable extends Dictionary
|
|||
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
return Hashtable.this.containsKey(o);
|
||||
if (o == null)
|
||||
return false;
|
||||
return containsKey(o);
|
||||
}
|
||||
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
return (Hashtable.this.remove(o) != null);
|
||||
return Hashtable.this.remove(o) != null;
|
||||
}
|
||||
};
|
||||
|
||||
// We must specify the correct object to synchronize upon, hence the
|
||||
// use of a non-public API
|
||||
return new Collections.SynchronizedSet(this, r);
|
||||
keys = new Collections.SynchronizedSet(this, r);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a "collection view" (or "bag view") of this Hashtable's values.
|
||||
* The collection is backed by the hashtable, so changes in one show up
|
||||
* in the other. The collection supports element removal, but not element
|
||||
* addition. The collection is properly synchronized on the original
|
||||
* hashtable. The collection will throw a {@link NullPointerException}
|
||||
* if null is passed to <code>contains</code> or related methods, but not
|
||||
* if passed to <code>remove</code> or related methods.
|
||||
* hashtable. Sun has not documented the proper interaction of null with
|
||||
* this set, but has inconsistent behavior in the JDK. Therefore, in this
|
||||
* implementation, contains, remove, containsAll, retainAll, removeAll, and
|
||||
* equals just ignore a null value rather than throwing a
|
||||
* {@link NullPointerException}.
|
||||
*
|
||||
* @return a bag view of the values
|
||||
* @see #keySet()
|
||||
|
@ -630,6 +658,8 @@ public class Hashtable extends Dictionary
|
|||
* @since 1.2
|
||||
*/
|
||||
public Collection values()
|
||||
{
|
||||
if (values == null)
|
||||
{
|
||||
// We don't bother overriding many of the optional methods, as doing so
|
||||
// wouldn't provide any significant performance advantage.
|
||||
|
@ -642,35 +672,32 @@ public class Hashtable extends Dictionary
|
|||
|
||||
public Iterator iterator()
|
||||
{
|
||||
return new HashIterator(HashIterator.VALUES);
|
||||
return new HashIterator(VALUES);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
Hashtable.this.clear();
|
||||
}
|
||||
|
||||
// Override this so that we check for null
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
return Hashtable.this.contains(o);
|
||||
}
|
||||
};
|
||||
|
||||
// We must specify the correct object to synchronize upon, hence the
|
||||
// use of a non-public API
|
||||
return new Collections.SynchronizedCollection(this, r);
|
||||
values = new Collections.SynchronizedCollection(this, r);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "set view" of this Hashtable's entries. The set is backed by
|
||||
* the hashtable, so changes in one show up in the other. The set supports
|
||||
* element removal, but not element addition. The set is properly
|
||||
* synchronized on the original hashtable. The set will throw a
|
||||
* {@link NullPointerException} if the Map.Entry passed to
|
||||
* <code>contains</code>, <code>remove</code>, or related methods returns
|
||||
* null for <code>getKey</code>, but not if the Map.Entry is null or
|
||||
* returns null for <code>getValue</code>.
|
||||
* synchronized on the original hashtable. Sun has not documented the
|
||||
* proper interaction of null with this set, but has inconsistent behavior
|
||||
* in the JDK. Therefore, in this implementation, contains, remove,
|
||||
* containsAll, retainAll, removeAll, and equals just ignore a null entry,
|
||||
* or an entry with a null key or value, rather than throwing a
|
||||
* {@link NullPointerException}. However, calling entry.setValue(null)
|
||||
* will fail.
|
||||
* <p>
|
||||
*
|
||||
* Note that the iterators for all three views, from keySet(), entrySet(),
|
||||
|
@ -684,8 +711,10 @@ public class Hashtable extends Dictionary
|
|||
*/
|
||||
public Set entrySet()
|
||||
{
|
||||
// Create an AbstractSet with custom implementations of those methods that
|
||||
// can be overridden easily and efficiently.
|
||||
if (entries == null)
|
||||
{
|
||||
// Create an AbstractSet with custom implementations of those methods
|
||||
// that can be overridden easily and efficiently.
|
||||
Set r = new AbstractSet()
|
||||
{
|
||||
public int size()
|
||||
|
@ -695,7 +724,7 @@ public class Hashtable extends Dictionary
|
|||
|
||||
public Iterator iterator()
|
||||
{
|
||||
return new HashIterator(HashIterator.ENTRIES);
|
||||
return new HashIterator(ENTRIES);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
|
@ -719,14 +748,15 @@ public class Hashtable extends Dictionary
|
|||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// We must specify the correct object to synchronize upon, hence the
|
||||
// use of a non-public API
|
||||
return new Collections.SynchronizedSet(this, r);
|
||||
entries = new Collections.SynchronizedSet(this, r);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Hashtable equals the supplied Object <pre>o</pre>.
|
||||
* Returns true if this Hashtable equals the supplied Object <code>o</code>.
|
||||
* As specified by Map, this is:
|
||||
* <pre>
|
||||
* (o instanceof Map) && entrySet().equals(((Map) o).entrySet());
|
||||
|
@ -759,7 +789,7 @@ public class Hashtable extends Dictionary
|
|||
// Since we are already synchronized, and entrySet().iterator()
|
||||
// would repeatedly re-lock/release the monitor, we directly use the
|
||||
// unsynchronized HashIterator instead.
|
||||
Iterator itr = new HashIterator(HashIterator.ENTRIES);
|
||||
Iterator itr = new HashIterator(ENTRIES);
|
||||
int hashcode = 0;
|
||||
for (int pos = size; pos > 0; pos--)
|
||||
hashcode += itr.next().hashCode();
|
||||
|
@ -782,29 +812,55 @@ public class Hashtable extends Dictionary
|
|||
|
||||
/**
|
||||
* Helper method for entrySet(), which matches both key and value
|
||||
* simultaneously.
|
||||
* simultaneously. Ignores null, as mentioned in entrySet().
|
||||
*
|
||||
* @param o the entry to match
|
||||
* @return the matching entry, if found, or null
|
||||
* @throws NullPointerException if me.getKey() returns null
|
||||
* @see #entrySet()
|
||||
*/
|
||||
private HashEntry getEntry(Object o)
|
||||
{
|
||||
if (! (o instanceof Map.Entry))
|
||||
return null;
|
||||
Map.Entry me = (Map.Entry) o;
|
||||
int idx = hash(me.getKey());
|
||||
Object key = ((Map.Entry) o).getKey();
|
||||
if (key == null)
|
||||
return null;
|
||||
|
||||
int idx = hash(key);
|
||||
HashEntry e = buckets[idx];
|
||||
while (e != null)
|
||||
{
|
||||
if (e.equals(me))
|
||||
if (o.equals(e))
|
||||
return e;
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simplified, more efficient internal implementation of putAll(). The
|
||||
* Map constructor and clone() should not call putAll or put, in order to
|
||||
* be compatible with the JDK implementation with respect to subclasses.
|
||||
*
|
||||
* @param m the map to initialize this from
|
||||
*/
|
||||
void putAllInternal(Map m)
|
||||
{
|
||||
Iterator itr = m.entrySet().iterator();
|
||||
int msize = m.size();
|
||||
this.size = msize;
|
||||
|
||||
for (; msize > 0; msize--)
|
||||
{
|
||||
Map.Entry e = (Map.Entry) itr.next();
|
||||
Object key = e.getKey();
|
||||
int idx = hash(key);
|
||||
HashEntry he = new HashEntry(key, e.getValue());
|
||||
he.next = buckets[idx];
|
||||
buckets[idx] = he;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the size of the Hashtable and rehashes all keys to new array
|
||||
* indices; this is called when the addition of a new value would cause
|
||||
|
@ -813,7 +869,8 @@ public class Hashtable extends Dictionary
|
|||
* <p>
|
||||
*
|
||||
* This is not specified, but the new size is twice the current size plus
|
||||
* one; this number is not always prime, unfortunately.
|
||||
* one; this number is not always prime, unfortunately. This implementation
|
||||
* is not synchronized, as it is only invoked from synchronized methods.
|
||||
*/
|
||||
protected void rehash()
|
||||
{
|
||||
|
@ -870,7 +927,7 @@ public class Hashtable extends Dictionary
|
|||
// Since we are already synchronized, and entrySet().iterator()
|
||||
// would repeatedly re-lock/release the monitor, we directly use the
|
||||
// unsynchronized HashIterator instead.
|
||||
Iterator it = new HashIterator(HashIterator.ENTRIES);
|
||||
Iterator it = new HashIterator(ENTRIES);
|
||||
while (it.hasNext())
|
||||
{
|
||||
HashEntry entry = (HashEntry) it.next();
|
||||
|
@ -901,7 +958,8 @@ public class Hashtable extends Dictionary
|
|||
int len = s.readInt();
|
||||
|
||||
// Read and use key/value pairs.
|
||||
for ( ; len > 0; len--)
|
||||
// TODO: should we be defensive programmers, and check for illegal nulls?
|
||||
while (--len >= 0)
|
||||
put(s.readObject(), s.readObject());
|
||||
}
|
||||
|
||||
|
@ -916,13 +974,8 @@ public class Hashtable extends Dictionary
|
|||
*
|
||||
* @author Jon Zeppieri
|
||||
*/
|
||||
class HashIterator implements Iterator
|
||||
private final class HashIterator implements Iterator
|
||||
{
|
||||
/** "enum" of iterator types. */
|
||||
static final int KEYS = 0,
|
||||
VALUES = 1,
|
||||
ENTRIES = 2;
|
||||
|
||||
/**
|
||||
* The type of this Iterator: {@link #KEYS}, {@link #VALUES},
|
||||
* or {@link #ENTRIES}.
|
||||
|
@ -988,14 +1041,14 @@ public class Hashtable extends Dictionary
|
|||
last = e;
|
||||
if (type == VALUES)
|
||||
return e.value;
|
||||
else if (type == KEYS)
|
||||
if (type == KEYS)
|
||||
return e.key;
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from the backing Hashtable the last element which was fetched
|
||||
* with the <pre>next()</pre> method.
|
||||
* with the <code>next()</code> method.
|
||||
* @throws ConcurrentModificationException if the hashtable was modified
|
||||
* @throws IllegalStateException if called when there is no last element
|
||||
*/
|
||||
|
@ -1007,10 +1060,10 @@ public class Hashtable extends Dictionary
|
|||
throw new IllegalStateException();
|
||||
|
||||
Hashtable.this.remove(last.key);
|
||||
knownMod++;
|
||||
last = null;
|
||||
knownMod++;
|
||||
}
|
||||
}
|
||||
} // class HashIterator
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1027,21 +1080,21 @@ public class Hashtable extends Dictionary
|
|||
*
|
||||
* @author Jon Zeppieri
|
||||
*/
|
||||
class Enumerator implements Enumeration
|
||||
private final class Enumerator implements Enumeration
|
||||
{
|
||||
/** "enum" of iterator types. */
|
||||
static final int KEYS = 0,
|
||||
VALUES = 1;
|
||||
|
||||
/**
|
||||
* The type of this Iterator: {@link #KEYS} or {@link #VALUES}.
|
||||
*/
|
||||
int type;
|
||||
final int type;
|
||||
/** The number of elements remaining to be returned by next(). */
|
||||
int count = size;
|
||||
/** Current index in the physical hash table. */
|
||||
int idx;
|
||||
/** The last Entry returned by nextEntry(). */
|
||||
HashEntry last;
|
||||
/** Entry which will be returned by the next nextElement() call. */
|
||||
int idx = buckets.length;
|
||||
/**
|
||||
* Entry which will be returned by the next nextElement() call. It is
|
||||
* set if we are iterating through a bucket with multiple entries, or null
|
||||
* if we must look in the next bucket.
|
||||
*/
|
||||
HashEntry next;
|
||||
|
||||
/**
|
||||
|
@ -1051,25 +1104,6 @@ public class Hashtable extends Dictionary
|
|||
Enumerator(int type)
|
||||
{
|
||||
this.type = type;
|
||||
this.idx = buckets.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to find the next entry.
|
||||
* @return the next entry, or null
|
||||
*/
|
||||
private HashEntry nextEntry()
|
||||
{
|
||||
HashEntry e = null;
|
||||
|
||||
if (last != null)
|
||||
e = last.next;
|
||||
|
||||
while (e == null && idx > 0)
|
||||
e = buckets[--idx];
|
||||
|
||||
last = e;
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1078,10 +1112,7 @@ public class Hashtable extends Dictionary
|
|||
*/
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
if (next != null)
|
||||
return true;
|
||||
next = nextEntry();
|
||||
return next != null;
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1091,19 +1122,16 @@ public class Hashtable extends Dictionary
|
|||
*/
|
||||
public Object nextElement()
|
||||
{
|
||||
HashEntry e;
|
||||
if (next != null)
|
||||
{
|
||||
e = next;
|
||||
next = null;
|
||||
}
|
||||
else
|
||||
e = nextEntry();
|
||||
if (e == null)
|
||||
if (count == 0)
|
||||
throw new NoSuchElementException("Hashtable Enumerator");
|
||||
if (type == VALUES)
|
||||
return e.value;
|
||||
return e.key;
|
||||
}
|
||||
count--;
|
||||
HashEntry e = next;
|
||||
|
||||
while (e == null)
|
||||
e = buckets[--idx];
|
||||
|
||||
next = e.next;
|
||||
return type == VALUES ? e.value : e.key;
|
||||
}
|
||||
} // class Enumerator
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -28,11 +28,6 @@ executable file might be covered by the GNU General Public License. */
|
|||
|
||||
package java.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
|
||||
/**
|
||||
* This class provides a hashtable-backed implementation of the
|
||||
* Map interface, with predictable traversal order.
|
||||
|
@ -89,6 +84,7 @@ import java.io.ObjectOutputStream;
|
|||
* @see TreeMap
|
||||
* @see Hashtable
|
||||
* @since 1.4
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class LinkedHashMap extends HashMap
|
||||
{
|
||||
|
@ -218,8 +214,8 @@ public class LinkedHashMap extends HashMap
|
|||
* Construct a new insertion-ordered LinkedHashMap with a specific
|
||||
* inital capacity and default load factor of 0.75.
|
||||
*
|
||||
* @param initialCapacity the initial capacity of this HashMap (>=0)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0)
|
||||
* @param initialCapacity the initial capacity of this HashMap (>= 0)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0)
|
||||
*/
|
||||
public LinkedHashMap(int initialCapacity)
|
||||
{
|
||||
|
@ -231,10 +227,10 @@ public class LinkedHashMap extends HashMap
|
|||
* Construct a new insertion-orderd LinkedHashMap with a specific
|
||||
* inital capacity and load factor.
|
||||
*
|
||||
* @param initialCapacity the initial capacity (>=0)
|
||||
* @param loadFactor the load factor (>0, not NaN)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0) ||
|
||||
* ! (loadFactor > 0.0)
|
||||
* @param initialCapacity the initial capacity (>= 0)
|
||||
* @param loadFactor the load factor (> 0, not NaN)
|
||||
* @throws IllegalArgumentException if (initialCapacity < 0) ||
|
||||
* ! (loadFactor > 0.0)
|
||||
*/
|
||||
public LinkedHashMap(int initialCapacity, float loadFactor)
|
||||
{
|
||||
|
@ -281,7 +277,7 @@ public class LinkedHashMap extends HashMap
|
|||
LinkedHashEntry e = head;
|
||||
while (e != null)
|
||||
{
|
||||
if (value == null ? e.value == null : value.equals(e.value))
|
||||
if (equals(value, e.value))
|
||||
return true;
|
||||
e = e.succ;
|
||||
}
|
||||
|
@ -307,7 +303,7 @@ public class LinkedHashMap extends HashMap
|
|||
HashEntry e = buckets[idx];
|
||||
while (e != null)
|
||||
{
|
||||
if (key == null ? e.key == null : key.equals(e.key))
|
||||
if (equals(key, e.key))
|
||||
{
|
||||
if (accessOrder)
|
||||
{
|
||||
|
@ -376,13 +372,14 @@ public class LinkedHashMap extends HashMap
|
|||
return false;
|
||||
}
|
||||
|
||||
/** Helper method called by <code>put</code>, which creates and adds a
|
||||
/**
|
||||
* Helper method called by <code>put</code>, which creates and adds a
|
||||
* new Entry, followed by performing bookkeeping (like removeEldestEntry).
|
||||
*
|
||||
* @param key the key of the new Entry
|
||||
* @param value the value
|
||||
* @param idx the index in buckets where the new Entry belongs
|
||||
* @param callRemove Whether to call the removeEldestEntry method.
|
||||
* @param callRemove whether to call the removeEldestEntry method
|
||||
* @see #put(Object, Object)
|
||||
* @see #removeEldestEntry(Map.Entry)
|
||||
*/
|
||||
|
@ -397,6 +394,11 @@ public class LinkedHashMap extends HashMap
|
|||
remove(head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method, called by clone() to reset the doubly-linked list.
|
||||
* @param m the map to add entries from
|
||||
* @see #clone()
|
||||
*/
|
||||
void putAllInternal(Map m)
|
||||
{
|
||||
head = null;
|
||||
|
@ -466,8 +468,8 @@ public class LinkedHashMap extends HashMap
|
|||
throw new IllegalStateException();
|
||||
|
||||
LinkedHashMap.this.remove(last.key);
|
||||
knownMod++;
|
||||
last = null;
|
||||
knownMod++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
149
libjava/java/util/LinkedHashSet.java
Normal file
149
libjava/java/util/LinkedHashSet.java
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* LinkedHashSet.java -- a set backed by a LinkedHashMap, for linked
|
||||
list traversal.
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307 USA.
|
||||
|
||||
As a special exception, if you link this library with other files to
|
||||
produce an executable, this library does not by itself cause the
|
||||
resulting executable to be covered by the GNU General Public License.
|
||||
This exception does not however invalidate any other reasons why the
|
||||
executable file might be covered by the GNU General Public License. */
|
||||
|
||||
|
||||
package java.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* This class provides a hashtable-backed implementation of the
|
||||
* Set interface, with predictable traversal order.
|
||||
* <p>
|
||||
*
|
||||
* It uses a hash-bucket approach; that is, hash collisions are handled
|
||||
* by linking the new node off of the pre-existing node (or list of
|
||||
* nodes). In this manner, techniques such as linear probing (which
|
||||
* can cause primary clustering) and rehashing (which does not fit very
|
||||
* well with Java's method of precomputing hash codes) are avoided. In
|
||||
* addition, this maintains a doubly-linked list which tracks insertion
|
||||
* order. Note that the insertion order is not modified if an
|
||||
* <code>add</code> simply reinserts an element in the set.
|
||||
* <p>
|
||||
*
|
||||
* One of the nice features of tracking insertion order is that you can
|
||||
* copy a set, and regardless of the implementation of the original,
|
||||
* produce the same results when iterating over the copy. This is possible
|
||||
* without needing the overhead of <code>TreeSet</code>.
|
||||
* <p>
|
||||
*
|
||||
* Under ideal circumstances (no collisions), LinkedHashSet offers O(1)
|
||||
* performance on most operations. In the worst case (all elements map
|
||||
* to the same hash code -- very unlikely), most operations are O(n).
|
||||
* <p>
|
||||
*
|
||||
* LinkedHashSet accepts the null entry. It is not synchronized, so if
|
||||
* you need multi-threaded access, consider using:<br>
|
||||
* <code>Set s = Collections.synchronizedSet(new LinkedHashSet(...));</code>
|
||||
* <p>
|
||||
*
|
||||
* The iterators are <i>fail-fast</i>, meaning that any structural
|
||||
* modification, except for <code>remove()</code> called on the iterator
|
||||
* itself, cause the iterator to throw a
|
||||
* {@link ConcurrentModificationException} rather than exhibit
|
||||
* non-deterministic behavior.
|
||||
*
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Object#hashCode()
|
||||
* @see Collection
|
||||
* @see Set
|
||||
* @see HashSet
|
||||
* @see TreeSet
|
||||
* @see Collections#synchronizedSet(Set)
|
||||
* @since 1.4
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class LinkedHashSet extends HashSet
|
||||
implements Set, Cloneable, Serializable
|
||||
{
|
||||
/**
|
||||
* Compatible with JDK 1.4.
|
||||
*/
|
||||
private static final long serialVersionUID = -2851667679971038690L;
|
||||
|
||||
/**
|
||||
* Construct a new, empty HashSet whose backing HashMap has the default
|
||||
* capacity (11) and loadFacor (0.75).
|
||||
*/
|
||||
public LinkedHashSet()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new, empty HashSet whose backing HashMap has the supplied
|
||||
* capacity and the default load factor (0.75).
|
||||
*
|
||||
* @param initialCapacity the initial capacity of the backing HashMap
|
||||
* @throws IllegalArgumentException if the capacity is negative
|
||||
*/
|
||||
public LinkedHashSet(int initialCapacity)
|
||||
{
|
||||
super(initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new, empty HashSet whose backing HashMap has the supplied
|
||||
* capacity and load factor.
|
||||
*
|
||||
* @param initialCapacity the initial capacity of the backing HashMap
|
||||
* @param loadFactor the load factor of the backing HashMap
|
||||
* @throws IllegalArgumentException if either argument is negative, or
|
||||
* if loadFactor is POSITIVE_INFINITY or NaN
|
||||
*/
|
||||
public LinkedHashSet(int initialCapacity, float loadFactor)
|
||||
{
|
||||
super(initialCapacity, loadFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new HashSet with the same elements as are in the supplied
|
||||
* collection (eliminating any duplicates, of course). The backing storage
|
||||
* has twice the size of the collection, or the default size of 11,
|
||||
* whichever is greater; and the default load factor (0.75).
|
||||
*
|
||||
* @param c a collection of initial set elements
|
||||
* @throws NullPointerException if c is null
|
||||
*/
|
||||
public LinkedHashSet(Collection c)
|
||||
{
|
||||
super(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which initializes the backing Map.
|
||||
*
|
||||
* @param capacity the initial capacity
|
||||
* @param load the initial load factor
|
||||
* @return the backing HashMap
|
||||
*/
|
||||
HashMap init(int capacity, float load)
|
||||
{
|
||||
return new LinkedHashMap(capacity, load);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/* LinkedList.java -- Linked list implementation of the List interface
|
||||
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -32,25 +32,50 @@ import java.io.ObjectInputStream;
|
|||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
// TO DO:
|
||||
// ~ Doc comment for the class.
|
||||
// ~ Doc comments for the non-list methods.
|
||||
// ~ other general implementation notes.
|
||||
|
||||
/**
|
||||
* Linked list implementation of the List interface.
|
||||
* Linked list implementation of the List interface. In addition to the
|
||||
* methods of the List interface, this class provides access to the first
|
||||
* and last list elements in O(1) time for easy stack, queue, or double-ended
|
||||
* queue (deque) creation. The list is doubly-linked, with traversal to a
|
||||
* given index starting from the end closest to the element.<p>
|
||||
*
|
||||
* LinkedList is not synchronized, so if you need multi-threaded access,
|
||||
* consider using:<br>
|
||||
* <code>List l = Collections.synchronizedList(new LinkedList(...));</code>
|
||||
* <p>
|
||||
*
|
||||
* The iterators are <i>fail-fast</i>, meaning that any structural
|
||||
* modification, except for <code>remove()</code> called on the iterator
|
||||
* itself, cause the iterator to throw a
|
||||
* {@link ConcurrentModificationException} rather than exhibit
|
||||
* non-deterministic behavior.
|
||||
*
|
||||
* @author Original author unknown
|
||||
* @author Bryce McKinlay
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see List
|
||||
* @see ArrayList
|
||||
* @see Vector
|
||||
* @see Collections#synchronizedList(List)
|
||||
* @since 1.2
|
||||
* @status missing javadoc, but complete to 1.4
|
||||
*/
|
||||
public class LinkedList extends AbstractSequentialList
|
||||
implements List, Cloneable, Serializable
|
||||
{
|
||||
static final long serialVersionUID = 876323262645176354L;
|
||||
/**
|
||||
* Compatible with JDK 1.2.
|
||||
*/
|
||||
private static final long serialVersionUID = 876323262645176354L;
|
||||
|
||||
/**
|
||||
* An Entry containing the head (in the next field) and the tail (in the
|
||||
* previous field) of the list. The data field is null. If the list is empty,
|
||||
* both the head and the tail point to ends itself.
|
||||
* The first element in the list.
|
||||
*/
|
||||
transient Entry first;
|
||||
|
||||
/**
|
||||
* The last element in the list.
|
||||
*/
|
||||
transient Entry last;
|
||||
|
||||
/**
|
||||
|
@ -61,17 +86,26 @@ public class LinkedList extends AbstractSequentialList
|
|||
/**
|
||||
* Class to represent an entry in the list. Holds a single element.
|
||||
*/
|
||||
private static class Entry
|
||||
private static final class Entry
|
||||
{
|
||||
/** The element in the list. */
|
||||
Object data;
|
||||
|
||||
/** The next list entry, null if this is last. */
|
||||
Entry next;
|
||||
|
||||
/** The previous list entry, null if this is first. */
|
||||
Entry previous;
|
||||
|
||||
/**
|
||||
* Construct an entry.
|
||||
* @param data the list element
|
||||
*/
|
||||
Entry(Object data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
} // class Entry
|
||||
|
||||
/**
|
||||
* Obtain the Entry at a given position in a list. This method of course
|
||||
|
@ -82,7 +116,8 @@ public class LinkedList extends AbstractSequentialList
|
|||
* For speed and flexibility, range checking is not done in this method:
|
||||
* Incorrect values will be returned if (n < 0) or (n >= size).
|
||||
*
|
||||
* @param n the number of the entry to get.
|
||||
* @param n the number of the entry to get
|
||||
* @return the entry at position n
|
||||
*/
|
||||
private Entry getEntry(int n)
|
||||
{
|
||||
|
@ -92,28 +127,29 @@ public class LinkedList extends AbstractSequentialList
|
|||
e = first;
|
||||
// n less than size/2, iterate from start
|
||||
while (n-- > 0)
|
||||
{
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e = last;
|
||||
// n greater than size/2, iterate from end
|
||||
while (++n < size)
|
||||
{
|
||||
e = e.previous;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/** Remove an entry from the list. This will adjust size and deal with
|
||||
* `first' and `last' appropriatly. It does not effect modCount, that is
|
||||
* the responsibility of the caller. */
|
||||
/**
|
||||
* Remove an entry from the list. This will adjust size and deal with
|
||||
* `first' and `last' appropriatly.
|
||||
*
|
||||
* @param e the entry to remove
|
||||
*/
|
||||
private void removeEntry(Entry e)
|
||||
{
|
||||
if (size == 1)
|
||||
modCount++;
|
||||
size--;
|
||||
if (size == 0)
|
||||
first = last = null;
|
||||
else
|
||||
{
|
||||
|
@ -133,7 +169,32 @@ public class LinkedList extends AbstractSequentialList
|
|||
e.previous.next = e.next;
|
||||
}
|
||||
}
|
||||
size--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the index is in the range of possible elements (inclusive).
|
||||
*
|
||||
* @param index the index to check
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size
|
||||
*/
|
||||
private void checkBoundsInclusive(int index)
|
||||
{
|
||||
if (index < 0 || index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
|
||||
+ size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the index is in the range of existing elements (exclusive).
|
||||
*
|
||||
* @param index the index to check
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= size
|
||||
*/
|
||||
private void checkBoundsExclusive(int index)
|
||||
{
|
||||
if (index < 0 || index >= size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
|
||||
+ size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,24 +202,26 @@ public class LinkedList extends AbstractSequentialList
|
|||
*/
|
||||
public LinkedList()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a linked list containing the elements, in order, of a given
|
||||
* collection.
|
||||
*
|
||||
* @param c the collection to populate this list from.
|
||||
* @param c the collection to populate this list from
|
||||
* @throws NullPointerException if c is null
|
||||
*/
|
||||
public LinkedList(Collection c)
|
||||
{
|
||||
super();
|
||||
// Note: addAll could be made slightly faster, but not enough so to justify
|
||||
// re-implementing it from scratch. It is just a matter of a relatively
|
||||
// small constant factor.
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first element in the list.
|
||||
*
|
||||
* @return the first list element
|
||||
* @throws NoSuchElementException if the list is empty
|
||||
*/
|
||||
public Object getFirst()
|
||||
{
|
||||
if (size == 0)
|
||||
|
@ -166,6 +229,12 @@ public class LinkedList extends AbstractSequentialList
|
|||
return first.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element in the list.
|
||||
*
|
||||
* @return the last list element
|
||||
* @throws NoSuchElementException if the list is empty
|
||||
*/
|
||||
public Object getLast()
|
||||
{
|
||||
if (size == 0)
|
||||
|
@ -173,12 +242,18 @@ public class LinkedList extends AbstractSequentialList
|
|||
return last.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and return the first element in the list.
|
||||
*
|
||||
* @return the former first element in the list
|
||||
* @throws NoSuchElementException if the list is empty
|
||||
*/
|
||||
public Object removeFirst()
|
||||
{
|
||||
if (size == 0)
|
||||
throw new NoSuchElementException();
|
||||
size--;
|
||||
modCount++;
|
||||
size--;
|
||||
Object r = first.data;
|
||||
|
||||
if (first.next != null)
|
||||
|
@ -191,12 +266,18 @@ public class LinkedList extends AbstractSequentialList
|
|||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and return the last element in the list.
|
||||
*
|
||||
* @return the former last element in the list
|
||||
* @throws NoSuchElementException if the list is empty
|
||||
*/
|
||||
public Object removeLast()
|
||||
{
|
||||
if (size == 0)
|
||||
throw new NoSuchElementException();
|
||||
size--;
|
||||
modCount++;
|
||||
size--;
|
||||
Object r = last.data;
|
||||
|
||||
if (last.previous != null)
|
||||
|
@ -209,11 +290,16 @@ public class LinkedList extends AbstractSequentialList
|
|||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an element at the first of the list.
|
||||
*
|
||||
* @param o the element to insert
|
||||
*/
|
||||
public void addFirst(Object o)
|
||||
{
|
||||
modCount++;
|
||||
Entry e = new Entry(o);
|
||||
|
||||
modCount++;
|
||||
if (size == 0)
|
||||
first = last = e;
|
||||
else
|
||||
|
@ -225,14 +311,24 @@ public class LinkedList extends AbstractSequentialList
|
|||
size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an element at the last of the list.
|
||||
*
|
||||
* @param o the element to insert
|
||||
*/
|
||||
public void addLast(Object o)
|
||||
{
|
||||
modCount++;
|
||||
addLastEntry(new Entry(o));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an element at the end of the list.
|
||||
*
|
||||
* @param e the entry to add
|
||||
*/
|
||||
private void addLastEntry(Entry e)
|
||||
{
|
||||
modCount++;
|
||||
if (size == 0)
|
||||
first = last = e;
|
||||
else
|
||||
|
@ -244,37 +340,60 @@ public class LinkedList extends AbstractSequentialList
|
|||
size++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the list contains the given object. Comparison is done by
|
||||
* <code>o == null ? e = null : o.equals(e)</code>.
|
||||
*
|
||||
* @param o the element to look for
|
||||
* @return true if it is found
|
||||
*/
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
Entry e = first;
|
||||
while (e != null)
|
||||
{
|
||||
if (e.data == null ? o == null : o.equals(e.data))
|
||||
if (equals(o, e.data))
|
||||
return true;
|
||||
e = e.next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the list.
|
||||
*
|
||||
* @return the list size
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element to the end of the list.
|
||||
*
|
||||
* @param e the entry to add
|
||||
* @return true, as it always succeeds
|
||||
*/
|
||||
public boolean add(Object o)
|
||||
{
|
||||
modCount++;
|
||||
addLastEntry(new Entry(o));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the entry at the lowest index in the list that matches the given
|
||||
* object, comparing by <code>o == null ? e = null : o.equals(e)</code>.
|
||||
*
|
||||
* @param o the object to remove
|
||||
* @return true if an instance of the object was removed
|
||||
*/
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
modCount++;
|
||||
Entry e = first;
|
||||
while (e != null)
|
||||
{
|
||||
if (e.data == null ? o == null : o.equals(e.data))
|
||||
if (equals(o, e.data))
|
||||
{
|
||||
removeEntry(e);
|
||||
return true;
|
||||
|
@ -284,17 +403,33 @@ public class LinkedList extends AbstractSequentialList
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the elements of the collection in iteration order to the end of
|
||||
* this list. If this list is modified externally (for example, if this
|
||||
* list is the collection), behavior is unspecified.
|
||||
*
|
||||
* @param c the collection to append
|
||||
* @return true if the list was modified
|
||||
* @throws NullPointerException if c is null
|
||||
*/
|
||||
public boolean addAll(Collection c)
|
||||
{
|
||||
return addAll(size, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert the elements of the collection in iteration order at the given
|
||||
* index of this list. If this list is modified externally (for example,
|
||||
* if this list is the collection), behavior is unspecified.
|
||||
*
|
||||
* @param c the collection to append
|
||||
* @return true if the list was modified
|
||||
* @throws NullPointerException if c is null
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||||
*/
|
||||
public boolean addAll(int index, Collection c)
|
||||
{
|
||||
if (index < 0 || index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
modCount++;
|
||||
checkBoundsInclusive(index);
|
||||
int csize = c.size();
|
||||
|
||||
if (csize == 0)
|
||||
|
@ -303,8 +438,8 @@ public class LinkedList extends AbstractSequentialList
|
|||
Iterator itr = c.iterator();
|
||||
|
||||
// Get the entries just before and after index. If index is at the start
|
||||
// of the list, BEFORE is null. If index is at the end of thelist, AFTER is
|
||||
// null. If the list is empty, both are null.
|
||||
// of the list, BEFORE is null. If index is at the end of the list, AFTER
|
||||
// is null. If the list is empty, both are null.
|
||||
Entry after = null;
|
||||
Entry before = null;
|
||||
if (index != size)
|
||||
|
@ -332,7 +467,10 @@ public class LinkedList extends AbstractSequentialList
|
|||
prev.next = e;
|
||||
prev = e;
|
||||
}
|
||||
|
||||
// Link the new chain of entries into the list.
|
||||
modCount++;
|
||||
size += csize;
|
||||
prev.next = after;
|
||||
if (after != null)
|
||||
after.previous = e;
|
||||
|
@ -343,52 +481,68 @@ public class LinkedList extends AbstractSequentialList
|
|||
before.next = firstNew;
|
||||
else
|
||||
first = firstNew;
|
||||
|
||||
size += csize;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all elements from this list.
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
if (size > 0)
|
||||
{
|
||||
modCount++;
|
||||
first = null;
|
||||
last = null;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public Object get(int index)
|
||||
{
|
||||
if (index < 0 || index >= size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
Entry e = getEntry(index);
|
||||
return e.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the element at index.
|
||||
*
|
||||
* @param index the place to look
|
||||
* @return the element at index
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||||
*/
|
||||
public Object get(int index)
|
||||
{
|
||||
checkBoundsExclusive(index);
|
||||
return getEntry(index).data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the element at the given location in the list.
|
||||
*
|
||||
* @param index which index to change
|
||||
* @param o the new element
|
||||
* @return the prior element
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= size()
|
||||
*/
|
||||
public Object set(int index, Object o)
|
||||
{
|
||||
if (index < 0 || index >= size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
checkBoundsExclusive(index);
|
||||
Entry e = getEntry(index);
|
||||
Object old = e.data;
|
||||
e.data = o;
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an element in the given position in the list.
|
||||
*
|
||||
* @param index where to insert the element
|
||||
* @param o the element to insert
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||||
*/
|
||||
public void add(int index, Object o)
|
||||
{
|
||||
if (index < 0 || index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
modCount++;
|
||||
addEntry(index, new Entry(o));
|
||||
}
|
||||
checkBoundsInclusive(index);
|
||||
Entry e = new Entry(o);
|
||||
|
||||
private void addEntry(int index, Entry e)
|
||||
{
|
||||
if (index < size)
|
||||
{
|
||||
modCount++;
|
||||
Entry after = getEntry(index);
|
||||
e.next = after;
|
||||
e.previous = after.previous;
|
||||
|
@ -403,40 +557,56 @@ public class LinkedList extends AbstractSequentialList
|
|||
addLastEntry(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the element at the given position from the list.
|
||||
*
|
||||
* @param index the location of the element to remove
|
||||
* @return the removed element
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||||
*/
|
||||
public Object remove(int index)
|
||||
{
|
||||
if (index < 0 || index >= size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
modCount++;
|
||||
checkBoundsExclusive(index);
|
||||
Entry e = getEntry(index);
|
||||
removeEntry(e);
|
||||
return e.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first index where the element is located in the list, or -1.
|
||||
*
|
||||
* @param o the element to look for
|
||||
* @return its position, or -1 if not found
|
||||
*/
|
||||
public int indexOf(Object o)
|
||||
{
|
||||
int index = 0;
|
||||
Entry e = first;
|
||||
while (e != null)
|
||||
{
|
||||
if (e.data == null ? o == null : o.equals(e.data))
|
||||
if (equals(o, e.data))
|
||||
return index;
|
||||
++index;
|
||||
index++;
|
||||
e = e.next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last index where the element is located in the list, or -1.
|
||||
*
|
||||
* @param o the element to look for
|
||||
* @return its position, or -1 if not found
|
||||
*/
|
||||
public int lastIndexOf(Object o)
|
||||
{
|
||||
int index = size - 1;
|
||||
Entry e = last;
|
||||
while (e != null)
|
||||
{
|
||||
if (e.data == null ? o == null : o.equals(e.data))
|
||||
if (equals(o, e.data))
|
||||
return index;
|
||||
--index;
|
||||
index--;
|
||||
e = e.previous;
|
||||
}
|
||||
return -1;
|
||||
|
@ -448,21 +618,20 @@ public class LinkedList extends AbstractSequentialList
|
|||
* methods.
|
||||
*
|
||||
* @param index the index of the element to be returned by the first call to
|
||||
* next(), or size() to be initially positioned at the end of the list.
|
||||
* @exception IndexOutOfBoundsException if index < 0 || index > size().
|
||||
* next(), or size() to be initially positioned at the end of the list
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index > size()
|
||||
*/
|
||||
public ListIterator listIterator(int index)
|
||||
{
|
||||
if (index < 0 || index > size)
|
||||
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
|
||||
size);
|
||||
checkBoundsInclusive(index);
|
||||
return new LinkedListItr(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shallow copy of this LinkedList.
|
||||
* Create a shallow copy of this LinkedList (the elements are not cloned).
|
||||
*
|
||||
* @return an object of the same class as this object, containing the
|
||||
* same elements in the same order.
|
||||
* same elements in the same order
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
|
@ -479,6 +648,11 @@ public class LinkedList extends AbstractSequentialList
|
|||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array which contains the elements of the list in order.
|
||||
*
|
||||
* @return an array containing the list elements
|
||||
*/
|
||||
public Object[] toArray()
|
||||
{
|
||||
Object[] array = new Object[size];
|
||||
|
@ -491,59 +665,102 @@ public class LinkedList extends AbstractSequentialList
|
|||
return array;
|
||||
}
|
||||
|
||||
public Object[] toArray(Object[] array)
|
||||
/**
|
||||
* Returns an Array whose component type is the runtime component type of
|
||||
* the passed-in Array. The returned Array is populated with all of the
|
||||
* elements in this LinkedList. If the passed-in Array is not large enough
|
||||
* to store all of the elements in this List, a new Array will be created
|
||||
* and returned; if the passed-in Array is <i>larger</i> than the size
|
||||
* of this List, then size() index will be set to null.
|
||||
*
|
||||
* @param a the passed-in Array
|
||||
* @return an array representation of this list
|
||||
* @throws ArrayStoreException if the runtime type of a does not allow
|
||||
* an element in this list
|
||||
* @throws NullPointerException if a is null
|
||||
*/
|
||||
public Object[] toArray(Object[] a)
|
||||
{
|
||||
if (array.length < size)
|
||||
array = (Object[]) Array.newInstance(array.getClass().getComponentType(),
|
||||
size);
|
||||
else if (array.length > size)
|
||||
array[size] = null;
|
||||
if (a.length < size)
|
||||
a = (Object[]) Array.newInstance(a.getClass().getComponentType(), size);
|
||||
else if (a.length > size)
|
||||
a[size] = null;
|
||||
Entry e = first;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
array[i] = e.data;
|
||||
a[i] = e.data;
|
||||
e = e.next;
|
||||
}
|
||||
return array;
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize an object to a stream.
|
||||
* @serialdata the size of the list (int), followed by all the elements
|
||||
* (Object) in proper order.
|
||||
* Serializes this object to the given stream.
|
||||
*
|
||||
* @param s the stream to write to
|
||||
* @throws IOException if the underlying stream fails
|
||||
* @serialData the size of the list (int), followed by all the elements
|
||||
* (Object) in proper order
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream s) throws IOException
|
||||
{
|
||||
s.defaultWriteObject();
|
||||
s.writeInt(size);
|
||||
Iterator itr = iterator();
|
||||
for (int i = 0; i < size; i++)
|
||||
s.writeObject(itr.next());
|
||||
Entry e = first;
|
||||
while (e != null)
|
||||
{
|
||||
s.writeObject(e.data);
|
||||
e = e.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize an object from a stream.
|
||||
* @serialdata the size of the list (int), followed by all the elements
|
||||
* (Object) in proper order.
|
||||
* Deserializes this object from the given stream.
|
||||
*
|
||||
* @param s the stream to read from
|
||||
* @throws ClassNotFoundException if the underlying stream fails
|
||||
* @throws IOException if the underlying stream fails
|
||||
* @serialData the size of the list (int), followed by all the elements
|
||||
* (Object) in proper order
|
||||
*/
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
int serialSize = s.readInt();
|
||||
for (int i = 0; i < serialSize; i++)
|
||||
s.defaultReadObject();
|
||||
int i = s.readInt();
|
||||
while (--i >= 0)
|
||||
addLastEntry(new Entry(s.readObject()));
|
||||
}
|
||||
|
||||
/** A ListIterator over the list. This class keeps track of its
|
||||
/**
|
||||
* A ListIterator over the list. This class keeps track of its
|
||||
* position in the list and the two list entries it is between.
|
||||
*
|
||||
* @author Original author unknown
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
*/
|
||||
class LinkedListItr implements ListIterator
|
||||
private final class LinkedListItr implements ListIterator
|
||||
{
|
||||
int knownMod;
|
||||
Entry next; // entry that will be returned by next().
|
||||
Entry previous; // entry that will be returned by previous().
|
||||
Entry lastReturned; // entry that will be affected by remove() or set().
|
||||
int position; // index of `next'.
|
||||
/** Number of modifications we know about. */
|
||||
private int knownMod = modCount;
|
||||
|
||||
/** Entry that will be returned by next(). */
|
||||
private Entry next;
|
||||
|
||||
/** Entry that will be returned by previous(). */
|
||||
private Entry previous;
|
||||
|
||||
/** Entry that will be affected by remove() or set(). */
|
||||
private Entry lastReturned;
|
||||
|
||||
/** Index of `next'. */
|
||||
private int position;
|
||||
|
||||
/**
|
||||
* Initialize the iterator.
|
||||
*
|
||||
* @param index the initial index
|
||||
*/
|
||||
LinkedListItr(int index)
|
||||
{
|
||||
if (index == size)
|
||||
|
@ -557,39 +774,74 @@ public class LinkedList extends AbstractSequentialList
|
|||
previous = next.previous;
|
||||
}
|
||||
position = index;
|
||||
knownMod = modCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for iterator consistency.
|
||||
*
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
*/
|
||||
private void checkMod()
|
||||
{
|
||||
if (knownMod != modCount)
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the next element.
|
||||
*
|
||||
* @return the next index
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
*/
|
||||
public int nextIndex()
|
||||
{
|
||||
checkMod();
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the previous element.
|
||||
*
|
||||
* @return the previous index
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
*/
|
||||
public int previousIndex()
|
||||
{
|
||||
checkMod();
|
||||
return position - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if more elements exist via next.
|
||||
*
|
||||
* @return true if next will succeed
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
*/
|
||||
public boolean hasNext()
|
||||
{
|
||||
checkMod();
|
||||
return (next != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if more elements exist via previous.
|
||||
*
|
||||
* @return true if previous will succeed
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
*/
|
||||
public boolean hasPrevious()
|
||||
{
|
||||
checkMod();
|
||||
return (previous != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next element.
|
||||
*
|
||||
* @return the next element
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
* @throws NoSuchElementException if there is no next
|
||||
*/
|
||||
public Object next()
|
||||
{
|
||||
checkMod();
|
||||
|
@ -601,6 +853,13 @@ public class LinkedList extends AbstractSequentialList
|
|||
return lastReturned.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the previous element.
|
||||
*
|
||||
* @return the previous element
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
* @throws NoSuchElementException if there is no previous
|
||||
*/
|
||||
public Object previous()
|
||||
{
|
||||
checkMod();
|
||||
|
@ -612,6 +871,12 @@ public class LinkedList extends AbstractSequentialList
|
|||
return lastReturned.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the most recently returned element from the list.
|
||||
*
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
* @throws IllegalStateException if there was no last element
|
||||
*/
|
||||
public void remove()
|
||||
{
|
||||
checkMod();
|
||||
|
@ -625,18 +890,25 @@ public class LinkedList extends AbstractSequentialList
|
|||
|
||||
next = lastReturned.next;
|
||||
previous = lastReturned.previous;
|
||||
modCount++;
|
||||
knownMod++;
|
||||
removeEntry(lastReturned);
|
||||
knownMod++;
|
||||
|
||||
lastReturned = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element between the previous and next, and advance to the next.
|
||||
*
|
||||
* @param o the element to add
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
*/
|
||||
public void add(Object o)
|
||||
{
|
||||
checkMod();
|
||||
modCount++;
|
||||
knownMod++;
|
||||
size++;
|
||||
position++;
|
||||
Entry e = new Entry(o);
|
||||
e.previous = previous;
|
||||
e.next = next;
|
||||
|
@ -647,19 +919,21 @@ public class LinkedList extends AbstractSequentialList
|
|||
first = e;
|
||||
|
||||
if (next != null)
|
||||
{
|
||||
next.previous = e;
|
||||
next = next.next;
|
||||
}
|
||||
else
|
||||
last = e;
|
||||
|
||||
previous = e;
|
||||
size++;
|
||||
position++;
|
||||
lastReturned = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the contents of the element most recently returned.
|
||||
*
|
||||
* @param o the new element
|
||||
* @throws ConcurrentModificationException if the list was modified
|
||||
* @throws IllegalStateException if there was no last element
|
||||
*/
|
||||
public void set(Object o)
|
||||
{
|
||||
checkMod();
|
||||
|
|
|
@ -190,7 +190,7 @@ public interface List extends Collection
|
|||
* @see Object#equals(Object)
|
||||
* @see #hashCode()
|
||||
*/
|
||||
boolean equals(Object o);
|
||||
/* boolean equals(Object o);*/
|
||||
|
||||
/**
|
||||
* Get the element at a given index in this list.
|
||||
|
@ -288,7 +288,7 @@ public interface List extends Collection
|
|||
Object remove(int index);
|
||||
|
||||
/**
|
||||
* Remove the first occurrence of an object from this list (optional
|
||||
* Remove the first occurence of an object from this list (optional
|
||||
* operation). That is, remove the first element e such that
|
||||
* <code>o == null ? e == null : o.equals(e)</code>.
|
||||
*
|
||||
|
|
|
@ -32,24 +32,30 @@ package java.util;
|
|||
* "The Java Language Specification", ISBN 0-201-63451-1
|
||||
* plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
|
||||
* Status: Believed complete and correct
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stack provides a Last In First Out (LIFO) data type, commonly known
|
||||
* as a Stack.
|
||||
*
|
||||
* Stack itself extends Vector and provides the additional methods
|
||||
* for stack manipulation (push, pop, peek).
|
||||
* as a Stack. Stack itself extends Vector and provides the additional
|
||||
* methods for stack manipulation (push, pop, peek). You can also seek for
|
||||
* the 1-based position of an element on the stack.
|
||||
*
|
||||
* @author Warren Levy <warrenl@cygnus.com>
|
||||
* @date August 20, 1998.
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see List
|
||||
* @see AbstractList
|
||||
* @see LinkedList
|
||||
* @since 1.0
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class Stack extends Vector
|
||||
{
|
||||
// Could use Vector methods internally for the following methods
|
||||
// We could use Vector methods internally for the following methods,
|
||||
// but have used Vector fields directly for efficiency (i.e. this
|
||||
// often reduces out duplicate bounds checking).
|
||||
|
||||
/**
|
||||
* Compatible with JDK 1.0+.
|
||||
*/
|
||||
private static final long serialVersionUID = 1224463164541339165L;
|
||||
|
||||
/**
|
||||
|
@ -57,16 +63,15 @@ public class Stack extends Vector
|
|||
*/
|
||||
public Stack()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes an Object onto the top of the stack. This method is effectively
|
||||
* the same as addElement(item)
|
||||
* the same as addElement(item).
|
||||
*
|
||||
* @param item the Object to push onto the stack
|
||||
* @returns the Object pushed onto the stack
|
||||
* @see java.util.Vector#addElement(java.util.Object)
|
||||
* @return the Object pushed onto the stack
|
||||
* @see Vector#addElement(Object)
|
||||
*/
|
||||
public Object push(Object item)
|
||||
{
|
||||
|
@ -80,26 +85,29 @@ public class Stack extends Vector
|
|||
|
||||
/**
|
||||
* Pops an item from the stack and returns it. The item popped is
|
||||
* removed from the Stack
|
||||
* removed from the Stack.
|
||||
*
|
||||
* @returns the Object popped from the stack
|
||||
* @return the Object popped from the stack
|
||||
* @throws EmptyStackException if the stack is empty
|
||||
*/
|
||||
public synchronized Object pop()
|
||||
{
|
||||
if (elementCount == 0)
|
||||
throw new EmptyStackException();
|
||||
|
||||
modCount++;
|
||||
Object obj = elementData[--elementCount];
|
||||
|
||||
// Set topmost element to null to assist the gc in cleanup
|
||||
// Set topmost element to null to assist the gc in cleanup.
|
||||
elementData[elementCount] = null;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top Object on the stack without removing it
|
||||
* Returns the top Object on the stack without removing it.
|
||||
*
|
||||
* @returns the top Object on the stack
|
||||
* @return the top Object on the stack
|
||||
* @throws EmptyStackException if the stack is empty
|
||||
*/
|
||||
public synchronized Object peek()
|
||||
{
|
||||
|
@ -110,11 +118,11 @@ public class Stack extends Vector
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests if the stack is empty
|
||||
* Tests if the stack is empty.
|
||||
*
|
||||
* @returns true if the stack contains no items, false otherwise
|
||||
* @return true if the stack contains no items, false otherwise
|
||||
*/
|
||||
public boolean empty()
|
||||
public synchronized boolean empty()
|
||||
{
|
||||
return elementCount == 0;
|
||||
}
|
||||
|
@ -122,18 +130,18 @@ public class Stack extends Vector
|
|||
/**
|
||||
* Returns the position of an Object on the stack, with the top
|
||||
* most Object being at position 1, and each Object deeper in the
|
||||
* stack at depth + 1
|
||||
* stack at depth + 1.
|
||||
*
|
||||
* @param o The object to search for
|
||||
* @returns The 1 based depth of the Object, or -1 if the Object
|
||||
* is not on the stack.
|
||||
* @return The 1 based depth of the Object, or -1 if the Object
|
||||
* is not on the stack
|
||||
*/
|
||||
public synchronized int search(Object o)
|
||||
{
|
||||
for (int i = elementCount-1; i >=0; --i)
|
||||
if (elementData[i].equals(o))
|
||||
int i = elementCount;
|
||||
while (--i >= 0)
|
||||
if (equals(o, elementData[i]))
|
||||
return elementCount - i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
/* TreeSet.java -- a class providing a TreeMap-backet SortedSet
|
||||
/* TreeSet.java -- a class providing a TreeMap-backed SortedSet
|
||||
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
@ -33,30 +33,62 @@ import java.io.ObjectInputStream;
|
|||
import java.io.ObjectOutputStream;
|
||||
|
||||
/**
|
||||
* This class provides a TreeMap-backed implementation of the
|
||||
* SortedSet interface.
|
||||
* This class provides a TreeMap-backed implementation of the SortedSet
|
||||
* interface. The elements will be sorted according to their <i>natural
|
||||
* order</i>, or according to the provided <code>Comparator</code>.<p>
|
||||
*
|
||||
* Each element in the Set is a key in the backing TreeMap; each key
|
||||
* maps to a static token, denoting that the key does, in fact, exist.
|
||||
* Most operations are O(log n), but there is so much overhead that this
|
||||
* makes small sets expensive. Note that the ordering must be <i>consistent
|
||||
* with equals</i> to correctly implement the Set interface. If this
|
||||
* condition is violated, the set is still well-behaved, but you may have
|
||||
* suprising results when comparing it to other sets.<p>
|
||||
*
|
||||
* Most operations are O(log n).
|
||||
* This implementation is not synchronized. If you need to share this between
|
||||
* multiple threads, do something like:<br>
|
||||
* <code>SortedSet s
|
||||
* = Collections.synchronizedSortedSet(new TreeSet(...));</code><p>
|
||||
*
|
||||
* TreeSet is a part of the JDK1.2 Collections API.
|
||||
* The iterators are <i>fail-fast</i>, meaning that any structural
|
||||
* modification, except for <code>remove()</code> called on the iterator
|
||||
* itself, cause the iterator to throw a
|
||||
* <code>ConcurrentModificationException</code> rather than exhibit
|
||||
* non-deterministic behavior.
|
||||
*
|
||||
* @author Jon Zeppieri
|
||||
* @author Bryce McKinlay
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see Collection
|
||||
* @see Set
|
||||
* @see HashSet
|
||||
* @see LinkedHashSet
|
||||
* @see Comparable
|
||||
* @see Comparator
|
||||
* @see Collections#synchronizedSortedSet(SortedSet)
|
||||
* @see TreeMap
|
||||
* @since 1.2
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
|
||||
public class TreeSet extends AbstractSet
|
||||
implements SortedSet, Cloneable, Serializable
|
||||
{
|
||||
/** The TreeMap which backs this Set */
|
||||
transient SortedMap map;
|
||||
/**
|
||||
* Compatible with JDK 1.2.
|
||||
*/
|
||||
private static final long serialVersionUID = -2479143000061671589L;
|
||||
|
||||
static final long serialVersionUID = -2479143000061671589L;
|
||||
/**
|
||||
* The SortedMap which backs this Set.
|
||||
*/
|
||||
// Not final because of readObject. This will always be one of TreeMap or
|
||||
// TreeMap.SubMap, which both extend AbstractMap.
|
||||
private transient SortedMap map;
|
||||
|
||||
/**
|
||||
* Construct a new TreeSet whose backing TreeMap using the "natural"
|
||||
* ordering of keys.
|
||||
* ordering of keys. Elements that are not mutually comparable will cause
|
||||
* ClassCastExceptions down the road.
|
||||
*
|
||||
* @see Comparable
|
||||
*/
|
||||
public TreeSet()
|
||||
{
|
||||
|
@ -65,9 +97,10 @@ public class TreeSet extends AbstractSet
|
|||
|
||||
/**
|
||||
* Construct a new TreeSet whose backing TreeMap uses the supplied
|
||||
* Comparator.
|
||||
* Comparator. Elements that are not mutually comparable will cause
|
||||
* ClassCastExceptions down the road.
|
||||
*
|
||||
* @param oComparator the Comparator this Set will use
|
||||
* @param comparator the Comparator this Set will use
|
||||
*/
|
||||
public TreeSet(Comparator comparator)
|
||||
{
|
||||
|
@ -77,10 +110,14 @@ public class TreeSet extends AbstractSet
|
|||
/**
|
||||
* Construct a new TreeSet whose backing TreeMap uses the "natural"
|
||||
* orering of the keys and which contains all of the elements in the
|
||||
* supplied Collection.
|
||||
* supplied Collection. This runs in n*log(n) time.
|
||||
*
|
||||
* @param oCollection the new Set will be initialized with all
|
||||
* @param collection the new Set will be initialized with all
|
||||
* of the elements in this Collection
|
||||
* @throws ClassCastException if the elements of the collection are not
|
||||
* comparable
|
||||
* @throws NullPointerException if the collection is null
|
||||
* @see Comparable
|
||||
*/
|
||||
public TreeSet(Collection collection)
|
||||
{
|
||||
|
@ -93,54 +130,57 @@ public class TreeSet extends AbstractSet
|
|||
* SortedSet and containing all of the elements in the supplied SortedSet.
|
||||
* This constructor runs in linear time.
|
||||
*
|
||||
* @param sortedSet the new TreeSet will use this SortedSet's
|
||||
* comparator and will initialize itself
|
||||
* with all of the elements in this SortedSet
|
||||
* @param sortedSet the new TreeSet will use this SortedSet's comparator
|
||||
* and will initialize itself with all its elements
|
||||
* @throws NullPointerException if sortedSet is null
|
||||
*/
|
||||
public TreeSet(SortedSet sortedSet)
|
||||
{
|
||||
TreeMap map = new TreeMap(sortedSet.comparator());
|
||||
int i = 0;
|
||||
map = new TreeMap(sortedSet.comparator());
|
||||
Iterator itr = sortedSet.iterator();
|
||||
map.putKeysLinear(itr, sortedSet.size());
|
||||
this.map = map;
|
||||
((TreeMap) map).putKeysLinear(itr, sortedSet.size());
|
||||
}
|
||||
|
||||
/* This private constructor is used to implement the subSet() calls around
|
||||
a backing TreeMap.SubMap. */
|
||||
TreeSet(SortedMap backingMap)
|
||||
/**
|
||||
* This private constructor is used to implement the subSet() calls around
|
||||
* a backing TreeMap.SubMap.
|
||||
*
|
||||
* @param backingMap the submap
|
||||
*/
|
||||
private TreeSet(SortedMap backingMap)
|
||||
{
|
||||
map = backingMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the spplied Object to the Set if it is not already in the Set;
|
||||
* returns true if the element is added, false otherwise
|
||||
* returns true if the element is added, false otherwise.
|
||||
*
|
||||
* @param obj the Object to be added to this Set
|
||||
* @throws ClassCastException if the element cannot be compared with objects
|
||||
* already in the set
|
||||
*/
|
||||
public boolean add(Object obj)
|
||||
{
|
||||
return (map.put(obj, Boolean.TRUE) == null);
|
||||
return map.put(obj, "") == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all of the elements in the supplied Collection to this TreeSet.
|
||||
*
|
||||
* @param c All of the elements in this Collection
|
||||
* will be added to the Set.
|
||||
*
|
||||
* @param c The collection to add
|
||||
* @return true if the Set is altered, false otherwise
|
||||
* @throws NullPointerException if c is null
|
||||
* @throws ClassCastException if an element in c cannot be compared with
|
||||
* objects already in the set
|
||||
*/
|
||||
public boolean addAll(Collection c)
|
||||
{
|
||||
boolean result = false;
|
||||
int size = c.size();
|
||||
int pos = c.size();
|
||||
Iterator itr = c.iterator();
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
result |= (map.put(itr.next(), Boolean.TRUE) == null);
|
||||
|
||||
while (--pos >= 0)
|
||||
result |= (map.put(itr.next(), "") == null);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -152,94 +192,75 @@ public class TreeSet extends AbstractSet
|
|||
map.clear();
|
||||
}
|
||||
|
||||
/** Returns a shallow copy of this Set. */
|
||||
/**
|
||||
* Returns a shallow copy of this Set. The elements are not cloned.
|
||||
*
|
||||
* @return the cloned set
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
TreeSet copy = null;
|
||||
try
|
||||
{
|
||||
copy = (TreeSet) super.clone();
|
||||
// Map may be either TreeMap or TreeMap.SubMap, hence the ugly casts.
|
||||
copy.map = (SortedMap) ((AbstractMap) map).clone();
|
||||
}
|
||||
catch (CloneNotSupportedException x)
|
||||
{
|
||||
// Impossible result.
|
||||
}
|
||||
copy.map = (SortedMap) ((TreeMap) map).clone();
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Returns this Set's comparator */
|
||||
/**
|
||||
* Returns this Set's comparator.
|
||||
*
|
||||
* @return the comparator, or null if the set uses natural ordering
|
||||
*/
|
||||
public Comparator comparator()
|
||||
{
|
||||
return map.comparator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Set contains the supplied Object,
|
||||
* false otherwise
|
||||
* Returns true if this Set contains the supplied Object, false otherwise.
|
||||
*
|
||||
* @param oObject the Object whose existence in the Set is
|
||||
* being tested
|
||||
* @param obj the Object to check for
|
||||
* @return true if it is in the set
|
||||
* @throws ClassCastException if obj cannot be compared with objects
|
||||
* already in the set
|
||||
*/
|
||||
public boolean contains(Object obj)
|
||||
{
|
||||
return map.containsKey(obj);
|
||||
}
|
||||
|
||||
/** Returns true if this Set has size 0, false otherwise */
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
/** Returns the number of elements in this Set */
|
||||
public int size()
|
||||
{
|
||||
return map.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the supplied Object is in this Set, it is removed, and true is
|
||||
* returned; otherwise, false is returned.
|
||||
* Returns the first (by order) element in this Set.
|
||||
*
|
||||
* @param obj the Object we are attempting to remove
|
||||
* from this Set
|
||||
* @return the first element
|
||||
* @throws NoSuchElementException if the set is empty
|
||||
*/
|
||||
public boolean remove(Object obj)
|
||||
{
|
||||
return (map.remove(obj) != null);
|
||||
}
|
||||
|
||||
/** Returns the first (by order) element in this Set */
|
||||
public Object first()
|
||||
{
|
||||
return map.firstKey();
|
||||
}
|
||||
|
||||
/** Returns the last (by order) element in this Set */
|
||||
public Object last()
|
||||
{
|
||||
return map.lastKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this Set including all elements in the interval
|
||||
* [oFromElement, oToElement).
|
||||
* Returns a view of this Set including all elements less than
|
||||
* <code>to</code>. The returned set is backed by the original, so changes
|
||||
* in one appear in the other. The subset will throw an
|
||||
* {@link IllegalArgumentException} for any attempt to access or add an
|
||||
* element beyond the specified cutoff. The returned set does not include
|
||||
* the endpoint; if you want inclusion, pass the successor element.
|
||||
*
|
||||
* @param from the resultant view will contain all
|
||||
* elements greater than or equal to this element
|
||||
* @param to the resultant view will contain all
|
||||
* elements less than this element
|
||||
*/
|
||||
public SortedSet subSet(Object from, Object to)
|
||||
{
|
||||
return new TreeSet(map.subMap(from, to));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this Set including all elements less than oToElement
|
||||
*
|
||||
* @param toElement the resultant view will contain all
|
||||
* elements less than this element
|
||||
* @param to the (exclusive) cutoff point
|
||||
* @return a view of the set less than the cutoff
|
||||
* @throws ClassCastException if <code>to</code> is not compatible with
|
||||
* the comparator (or is not Comparable, for natural ordering)
|
||||
* @throws NullPointerException if to is null, but the comparator does not
|
||||
* tolerate null elements
|
||||
*/
|
||||
public SortedSet headSet(Object to)
|
||||
{
|
||||
|
@ -247,42 +268,138 @@ public class TreeSet extends AbstractSet
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this Set including all elements greater than or
|
||||
* equal to oFromElement.
|
||||
* Returns true if this Set has size 0, false otherwise.
|
||||
*
|
||||
* @param from the resultant view will contain all
|
||||
* elements greater than or equal to this element
|
||||
* @return true if the set is empty
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns in Iterator over the elements in this TreeSet, which traverses
|
||||
* in ascending order.
|
||||
*
|
||||
* @return an iterator
|
||||
*/
|
||||
public Iterator iterator()
|
||||
{
|
||||
return map.keySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last (by order) element in this Set.
|
||||
*
|
||||
* @return the last element
|
||||
* @throws NoSuchElementException if the set is empty
|
||||
*/
|
||||
public Object last()
|
||||
{
|
||||
return map.lastKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the supplied Object is in this Set, it is removed, and true is
|
||||
* returned; otherwise, false is returned.
|
||||
*
|
||||
* @param obj the Object to remove from this Set
|
||||
* @return true if the set was modified
|
||||
* @throws ClassCastException if obj cannot be compared to set elements
|
||||
*/
|
||||
public boolean remove(Object obj)
|
||||
{
|
||||
return map.remove(obj) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in this Set
|
||||
*
|
||||
* @return the set size
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return map.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this Set including all elements greater or equal to
|
||||
* <code>from</code> and less than <code>to</code> (a half-open interval).
|
||||
* The returned set is backed by the original, so changes in one appear in
|
||||
* the other. The subset will throw an {@link IllegalArgumentException}
|
||||
* for any attempt to access or add an element beyond the specified cutoffs.
|
||||
* The returned set includes the low endpoint but not the high; if you want
|
||||
* to reverse this behavior on either end, pass in the successor element.
|
||||
*
|
||||
* @param from the (inclusive) low cutoff point
|
||||
* @param to the (exclusive) high cutoff point
|
||||
* @return a view of the set between the cutoffs
|
||||
* @throws ClassCastException if either cutoff is not compatible with
|
||||
* the comparator (or is not Comparable, for natural ordering)
|
||||
* @throws NullPointerException if from or to is null, but the comparator
|
||||
* does not tolerate null elements
|
||||
* @throws IllegalArgumentException if from is greater than to
|
||||
*/
|
||||
public SortedSet subSet(Object from, Object to)
|
||||
{
|
||||
return new TreeSet(map.subMap(from, to));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this Set including all elements greater or equal to
|
||||
* <code>from</code>. The returned set is backed by the original, so
|
||||
* changes in one appear in the other. The subset will throw an
|
||||
* {@link IllegalArgumentException} for any attempt to access or add an
|
||||
* element beyond the specified cutoff. The returned set includes the
|
||||
* endpoint; if you want to exclude it, pass in the successor element.
|
||||
*
|
||||
* @param from the (inclusive) low cutoff point
|
||||
* @return a view of the set above the cutoff
|
||||
* @throws ClassCastException if <code>from</code> is not compatible with
|
||||
* the comparator (or is not Comparable, for natural ordering)
|
||||
* @throws NullPointerException if from is null, but the comparator
|
||||
* does not tolerate null elements
|
||||
*/
|
||||
public SortedSet tailSet(Object from)
|
||||
{
|
||||
return new TreeSet(map.tailMap(from));
|
||||
}
|
||||
|
||||
/** Returns in Iterator over the elements in this TreeSet */
|
||||
public Iterator iterator()
|
||||
{
|
||||
return map.keySet().iterator();
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out) throws IOException
|
||||
/**
|
||||
* Serializes this object to the given stream.
|
||||
*
|
||||
* @param s the stream to write to
|
||||
* @throws IOException if the underlying stream fails
|
||||
* @serialData the <i>comparator</i> (Object), followed by the set size
|
||||
* (int), the the elements in sorted order (Object)
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream s) throws IOException
|
||||
{
|
||||
s.defaultWriteObject();
|
||||
Iterator itr = map.keySet().iterator();
|
||||
int size = map.size();
|
||||
|
||||
out.writeObject(map.comparator());
|
||||
out.writeInt(size);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
out.writeObject(itr.next());
|
||||
int pos = map.size();
|
||||
s.writeObject(map.comparator());
|
||||
s.writeInt(pos);
|
||||
while (--pos >= 0)
|
||||
s.writeObject(itr.next());
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
/**
|
||||
* Deserializes this object from the given stream.
|
||||
*
|
||||
* @param s the stream to read from
|
||||
* @throws ClassNotFoundException if the underlying stream fails
|
||||
* @throws IOException if the underlying stream fails
|
||||
* @serialData the <i>comparator</i> (Object), followed by the set size
|
||||
* (int), the the elements in sorted order (Object)
|
||||
*/
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
Comparator comparator = (Comparator) in.readObject();
|
||||
int size = in.readInt();
|
||||
TreeMap map = new TreeMap(comparator);
|
||||
map.putFromObjStream(in, size, false);
|
||||
this.map = map;
|
||||
s.defaultReadObject();
|
||||
Comparator comparator = (Comparator) s.readObject();
|
||||
int size = s.readInt();
|
||||
map = new TreeMap(comparator);
|
||||
((TreeMap) map).putFromObjStream(s, size, false);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,6 @@
|
|||
/* java.util.WeakHashMap
|
||||
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
|
||||
/* java.util.WeakHashMap -- a hashtable that keeps only weak references
|
||||
to its keys, allowing the virtual machine to reclaim them
|
||||
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
|
@ -26,6 +27,7 @@ executable file might be covered by the GNU General Public License. */
|
|||
|
||||
|
||||
package java.util;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
|
||||
|
@ -51,22 +53,26 @@ import java.lang.ref.ReferenceQueue;
|
|||
* entry, that was in the set before, suddenly disappears. <br>
|
||||
*
|
||||
* A weak hash map is not meant for caches; use a normal map, with
|
||||
* soft references as values instead. <br>
|
||||
* soft references as values instead, or try {@link LinkedHashMap}. <br>
|
||||
*
|
||||
* The weak hash map supports null values and null keys. Null keys
|
||||
* are never deleted from the map (except explictly of course).
|
||||
* The weak hash map supports null values and null keys. The null key
|
||||
* is never deleted from the map (except explictly of course).
|
||||
* The performance of the methods are similar to that of a hash map. <br>
|
||||
*
|
||||
* The value object are strongly referenced by this table. So if a
|
||||
* The value objects are strongly referenced by this table. So if a
|
||||
* value object maintains a strong reference to the key (either direct
|
||||
* or indirect) the key will never be removed from this map. According
|
||||
* to Sun, this problem may be fixed in a future release. It is not
|
||||
* possible to do it with the jdk 1.2 reference model, though.
|
||||
*
|
||||
* @since jdk1.2
|
||||
* @author Jochen Hoenicke
|
||||
* @author Eric Blake <ebb9@email.byu.edu>
|
||||
* @see HashMap
|
||||
* @see WeakReference */
|
||||
* @see WeakReference
|
||||
* @see LinkedHashMap
|
||||
* @since 1.2
|
||||
* @status updated to 1.4
|
||||
*/
|
||||
public class WeakHashMap extends AbstractMap implements Map
|
||||
{
|
||||
/**
|
||||
|
@ -77,7 +83,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
private static final int DEFAULT_CAPACITY = 11;
|
||||
|
||||
/**
|
||||
* The default load factor of a HashMap
|
||||
* The default load factor of a HashMap.
|
||||
*/
|
||||
private static final float DEFAULT_LOAD_FACTOR = 0.75F;
|
||||
|
||||
|
@ -85,18 +91,41 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* This is used instead of the key value <i>null</i>. It is needed
|
||||
* to distinguish between an null key and a removed key.
|
||||
*/
|
||||
private static final Object NULL_KEY = new Object();
|
||||
// Package visible for use by nested classes.
|
||||
static final Object NULL_KEY = new Object()
|
||||
{
|
||||
/**
|
||||
* Sets the hashCode to 0, since that's what null would map to.
|
||||
* @return the hash code 0
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this key to the given object. Normally, an object should
|
||||
* NEVER compare equal to null, but since we don't publicize NULL_VALUE,
|
||||
* it saves bytecode to do so here.
|
||||
* @return true iff o is this or null
|
||||
*/
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
return null == o || this == o;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The reference queue where our buckets (which are WeakReferences) are
|
||||
* registered to.
|
||||
*/
|
||||
private ReferenceQueue queue;
|
||||
private final ReferenceQueue queue;
|
||||
|
||||
/**
|
||||
* The number of entries in this hash map.
|
||||
*/
|
||||
private int size;
|
||||
// Package visible for use by nested classes.
|
||||
int size;
|
||||
|
||||
/**
|
||||
* The load factor of this WeakHashMap. This is the maximum ratio of
|
||||
|
@ -119,17 +148,20 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* by the garbage collection. Instead the iterators must make
|
||||
* sure to have strong references to the entries they rely on.
|
||||
*/
|
||||
private int modCount;
|
||||
// Package visible for use by nested classes.
|
||||
int modCount;
|
||||
|
||||
/**
|
||||
* The entry set. There is only one instance per hashmap, namely
|
||||
* theEntrySet. Note that the entry set may silently shrink, just
|
||||
* like the WeakHashMap.
|
||||
*/
|
||||
private class WeakEntrySet extends AbstractSet
|
||||
private final class WeakEntrySet extends AbstractSet
|
||||
{
|
||||
/**
|
||||
* Returns the size of this set.
|
||||
*
|
||||
* @return the set size
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
|
@ -138,6 +170,8 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
|
||||
/**
|
||||
* Returns an iterator for all entries.
|
||||
*
|
||||
* @return an Entry iterator
|
||||
*/
|
||||
public Iterator iterator()
|
||||
{
|
||||
|
@ -155,7 +189,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* being removed under us, since the entry strongly refers
|
||||
* to the key.
|
||||
*/
|
||||
WeakBucket.Entry lastEntry;
|
||||
WeakBucket.WeakEntry lastEntry;
|
||||
|
||||
/**
|
||||
* The entry that will be returned by the next
|
||||
|
@ -166,11 +200,11 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* being removed under us, since the entry strongly refers
|
||||
* to the key.
|
||||
*/
|
||||
WeakBucket.Entry nextEntry = findNext(null);
|
||||
WeakBucket.WeakEntry nextEntry = findNext(null);
|
||||
|
||||
/**
|
||||
* The known number of modification to the list, if it differs
|
||||
* from the real number, we through an exception.
|
||||
* from the real number, we throw an exception.
|
||||
*/
|
||||
int knownMod = modCount;
|
||||
|
||||
|
@ -178,12 +212,13 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* Check the known number of modification to the number of
|
||||
* modifications of the table. If it differs from the real
|
||||
* number, we throw an exception.
|
||||
* @exception ConcurrentModificationException if the number
|
||||
* @throws ConcurrentModificationException if the number
|
||||
* of modifications doesn't match.
|
||||
*/
|
||||
private void checkMod()
|
||||
{
|
||||
/* This method will get inlined */
|
||||
// This method will get inlined.
|
||||
cleanQueue();
|
||||
if (knownMod != modCount)
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
|
@ -191,11 +226,11 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
/**
|
||||
* Get a strong reference to the next entry after
|
||||
* lastBucket.
|
||||
* @param lastBucket the previous bucket, or null if we should
|
||||
* @param lastEntry the previous bucket, or null if we should
|
||||
* get the first entry.
|
||||
* @return the next entry.
|
||||
*/
|
||||
private WeakBucket.Entry findNext(WeakBucket.Entry lastEntry)
|
||||
private WeakBucket.WeakEntry findNext(WeakBucket.WeakEntry lastEntry)
|
||||
{
|
||||
int slot;
|
||||
WeakBucket nextBucket;
|
||||
|
@ -214,48 +249,45 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
{
|
||||
while (nextBucket != null)
|
||||
{
|
||||
WeakBucket.Entry entry = nextBucket.getEntry();
|
||||
WeakBucket.WeakEntry entry = nextBucket.getEntry();
|
||||
if (entry != null)
|
||||
/* This is the next entry */
|
||||
// This is the next entry.
|
||||
return entry;
|
||||
|
||||
/* entry was cleared, try next */
|
||||
// Entry was cleared, try next.
|
||||
nextBucket = nextBucket.next;
|
||||
}
|
||||
|
||||
slot++;
|
||||
if (slot == buckets.length)
|
||||
/* No more buckets, we are through */
|
||||
// No more buckets, we are through.
|
||||
return null;
|
||||
|
||||
nextBucket = buckets[slot];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if there are more entries.
|
||||
* @return true, iff there are more elements.
|
||||
* @exception IllegalModificationException if the hash map was
|
||||
* @throws ConcurrentModificationException if the hash map was
|
||||
* modified.
|
||||
*/
|
||||
public boolean hasNext()
|
||||
{
|
||||
cleanQueue();
|
||||
checkMod();
|
||||
return (nextEntry != null);
|
||||
return nextEntry != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next entry.
|
||||
* @return the next entry.
|
||||
* @exception IllegalModificationException if the hash map was
|
||||
* @throws ConcurrentModificationException if the hash map was
|
||||
* modified.
|
||||
* @exception NoSuchElementException if there is no entry.
|
||||
* @throws NoSuchElementException if there is no entry.
|
||||
*/
|
||||
public Object next()
|
||||
{
|
||||
cleanQueue();
|
||||
checkMod();
|
||||
if (nextEntry == null)
|
||||
throw new NoSuchElementException();
|
||||
|
@ -267,21 +299,20 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
/**
|
||||
* Removes the last returned entry from this set. This will
|
||||
* also remove the bucket of the underlying weak hash map.
|
||||
* @exception IllegalModificationException if the hash map was
|
||||
* @throws ConcurrentModificationException if the hash map was
|
||||
* modified.
|
||||
* @exception IllegalStateException if <code>next()</code> was
|
||||
* @throws IllegalStateException if <code>next()</code> was
|
||||
* never called or the element was already removed.
|
||||
*/
|
||||
public void remove()
|
||||
{
|
||||
cleanQueue();
|
||||
checkMod();
|
||||
if (lastEntry == null)
|
||||
throw new IllegalStateException();
|
||||
modCount++;
|
||||
internalRemove(lastEntry.getBucket());
|
||||
lastEntry = null;
|
||||
modCount++;
|
||||
knownMod = modCount;
|
||||
knownMod++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -293,7 +324,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* number. <br>
|
||||
*
|
||||
* It would be cleaner to have a WeakReference as field, instead of
|
||||
* extending it, but if a weak reference get cleared, we only get
|
||||
* extending it, but if a weak reference gets cleared, we only get
|
||||
* the weak reference (by queue.poll) and wouldn't know where to
|
||||
* look for this reference in the hashtable, to remove that entry.
|
||||
*
|
||||
|
@ -329,6 +360,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* Creates a new bucket for the given key/value pair and the specified
|
||||
* slot.
|
||||
* @param key the key
|
||||
* @param queue the queue the weak reference belongs to
|
||||
* @param value the value
|
||||
* @param slot the slot. This must match the slot where this bucket
|
||||
* will be enqueued.
|
||||
|
@ -346,7 +378,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* current bucket. It also keeps a strong reference to the
|
||||
* key; bad things may happen otherwise.
|
||||
*/
|
||||
class Entry implements Map.Entry
|
||||
class WeakEntry implements Map.Entry
|
||||
{
|
||||
/**
|
||||
* The strong ref to the key.
|
||||
|
@ -355,14 +387,16 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
|
||||
/**
|
||||
* Creates a new entry for the key.
|
||||
* @param key the key
|
||||
*/
|
||||
public Entry(Object key)
|
||||
public WeakEntry(Object key)
|
||||
{
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying bucket.
|
||||
* @return the owning bucket
|
||||
*/
|
||||
public WeakBucket getBucket()
|
||||
{
|
||||
|
@ -371,6 +405,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
|
||||
/**
|
||||
* Returns the key.
|
||||
* @return the key
|
||||
*/
|
||||
public Object getKey()
|
||||
{
|
||||
|
@ -379,6 +414,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
|
||||
/**
|
||||
* Returns the value.
|
||||
* @return the value
|
||||
*/
|
||||
public Object getValue()
|
||||
{
|
||||
|
@ -388,6 +424,8 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
/**
|
||||
* This changes the value. This change takes place in
|
||||
* the underlying hash map.
|
||||
* @param newVal the new value
|
||||
* @return the old value
|
||||
*/
|
||||
public Object setValue(Object newVal)
|
||||
{
|
||||
|
@ -398,50 +436,56 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
|
||||
/**
|
||||
* The hashCode as specified in the Entry interface.
|
||||
* @return the hash code
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return (key == NULL_KEY ? 0 : key.hashCode())
|
||||
^ (value == null ? 0 : value.hashCode());
|
||||
return key.hashCode() ^ WeakHashMap.hashCode(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The equals method as specified in the Entry interface.
|
||||
* @param o the object to compare to
|
||||
* @return true iff o represents the same key/value pair
|
||||
*/
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o instanceof Map.Entry)
|
||||
{
|
||||
Map.Entry e = (Map.Entry) o;
|
||||
return (key == NULL_KEY
|
||||
? e.getKey() == null : key.equals(e.getKey()))
|
||||
&& (value == null
|
||||
? e.getValue() == null : value.equals(e.getValue()));
|
||||
return key.equals(e.getKey())
|
||||
&& WeakHashMap.equals(value, e.getValue());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return key + "=" + value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the entry stored in this bucket, or null, if the
|
||||
* bucket got cleared in the mean time.
|
||||
* @return the Entry for this bucket, if it exists
|
||||
*/
|
||||
Entry getEntry()
|
||||
WeakEntry getEntry()
|
||||
{
|
||||
final Object key = this.get();
|
||||
final Object key = get();
|
||||
if (key == null)
|
||||
return null;
|
||||
return new Entry(key);
|
||||
return new WeakEntry(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry set returned by <code>entrySet()</code>.
|
||||
*/
|
||||
private WeakEntrySet theEntrySet;
|
||||
private final WeakEntrySet theEntrySet;
|
||||
|
||||
/**
|
||||
* The hash buckets. This are linked lists.
|
||||
* The hash buckets. These are linked lists.
|
||||
*/
|
||||
private WeakBucket[] buckets;
|
||||
|
||||
|
@ -458,6 +502,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* Creates a new weak hash map with default load factor and the given
|
||||
* capacity.
|
||||
* @param initialCapacity the initial capacity
|
||||
* @throws IllegalArgumentException if initialCapacity is negative
|
||||
*/
|
||||
public WeakHashMap(int initialCapacity)
|
||||
{
|
||||
|
@ -469,10 +514,13 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* load factor.
|
||||
* @param initialCapacity the initial capacity.
|
||||
* @param loadFactor the load factor (see class description of HashMap).
|
||||
* @throws IllegalArgumentException if initialCapacity is negative, or
|
||||
* loadFactor is non-positive
|
||||
*/
|
||||
public WeakHashMap(int initialCapacity, float loadFactor)
|
||||
{
|
||||
if (initialCapacity < 0 || loadFactor <= 0 || loadFactor > 1)
|
||||
// Check loadFactor for NaN as well.
|
||||
if (initialCapacity < 0 || ! (loadFactor > 0))
|
||||
throw new IllegalArgumentException();
|
||||
this.loadFactor = loadFactor;
|
||||
threshold = (int) (initialCapacity * loadFactor);
|
||||
|
@ -482,7 +530,23 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
}
|
||||
|
||||
/**
|
||||
* simply hashes a non-null Object to its array index
|
||||
* Construct a new WeakHashMap with the same mappings as the given map.
|
||||
* The WeakHashMap has a default load factor of 0.75.
|
||||
*
|
||||
* @param m the map to copy
|
||||
* @throws NullPointerException if m is null
|
||||
* @since 1.3
|
||||
*/
|
||||
public WeakHashMap(Map m)
|
||||
{
|
||||
this(m.size(), DEFAULT_LOAD_FACTOR);
|
||||
putAll(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply hashes a non-null Object to its array index.
|
||||
* @param key the key to hash
|
||||
* @return its slot number
|
||||
*/
|
||||
private int hash(Object key)
|
||||
{
|
||||
|
@ -498,7 +562,8 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* Currently the iterator maintains a strong reference to the key, so
|
||||
* that is no problem.
|
||||
*/
|
||||
private void cleanQueue()
|
||||
// Package visible for use by nested classes.
|
||||
void cleanQueue()
|
||||
{
|
||||
Object bucket = queue.poll();
|
||||
while (bucket != null)
|
||||
|
@ -521,8 +586,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
threshold = (int) (newsize * loadFactor);
|
||||
buckets = new WeakBucket[newsize];
|
||||
|
||||
/* Now we have to insert the buckets again.
|
||||
*/
|
||||
// Now we have to insert the buckets again.
|
||||
for (int i = 0; i < oldBuckets.length; i++)
|
||||
{
|
||||
WeakBucket bucket = oldBuckets[i];
|
||||
|
@ -534,15 +598,15 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
Object key = bucket.get();
|
||||
if (key == null)
|
||||
{
|
||||
/* This bucket should be removed; it is probably
|
||||
* already on the reference queue. We don't insert it
|
||||
* at all, and mark it as cleared. */
|
||||
// This bucket should be removed; it is probably
|
||||
// already on the reference queue. We don't insert it
|
||||
// at all, and mark it as cleared.
|
||||
bucket.slot = -1;
|
||||
size--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* add this bucket to its new slot */
|
||||
// Add this bucket to its new slot.
|
||||
int slot = hash(key);
|
||||
bucket.slot = slot;
|
||||
bucket.next = buckets[slot];
|
||||
|
@ -556,10 +620,10 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
/**
|
||||
* Finds the entry corresponding to key. Since it returns an Entry
|
||||
* it will also prevent the key from being removed under us.
|
||||
* @param key the key. It may be null.
|
||||
* @return The WeakBucket.Entry or null, if the key wasn't found.
|
||||
* @param key the key, may be null
|
||||
* @return The WeakBucket.WeakEntry or null, if the key wasn't found.
|
||||
*/
|
||||
private WeakBucket.Entry internalGet(Object key)
|
||||
private WeakBucket.WeakEntry internalGet(Object key)
|
||||
{
|
||||
if (key == null)
|
||||
key = NULL_KEY;
|
||||
|
@ -567,7 +631,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
WeakBucket bucket = buckets[slot];
|
||||
while (bucket != null)
|
||||
{
|
||||
WeakBucket.Entry entry = bucket.getEntry();
|
||||
WeakBucket.WeakEntry entry = bucket.getEntry();
|
||||
if (entry != null && key.equals(entry.key))
|
||||
return entry;
|
||||
|
||||
|
@ -601,13 +665,12 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
{
|
||||
int slot = bucket.slot;
|
||||
if (slot == -1)
|
||||
/* this bucket was already removed. */
|
||||
// This bucket was already removed.
|
||||
return;
|
||||
|
||||
/* mark the bucket as removed. This is necessary, since the
|
||||
* bucket may be enqueued later by the garbage collection and
|
||||
* internalRemove, will be called a second time.
|
||||
*/
|
||||
// Mark the bucket as removed. This is necessary, since the
|
||||
// bucket may be enqueued later by the garbage collection, and
|
||||
// internalRemove will be called a second time.
|
||||
bucket.slot = -1;
|
||||
if (buckets[slot] == bucket)
|
||||
buckets[slot] = bucket.next;
|
||||
|
@ -629,7 +692,7 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
|
||||
/**
|
||||
* Returns the size of this hash map. Note that the size() may shrink
|
||||
* spontanously, if the some of the keys were only weakly reachable.
|
||||
* spontaneously, if the some of the keys were only weakly reachable.
|
||||
* @return the number of entries in this hash map.
|
||||
*/
|
||||
public int size()
|
||||
|
@ -651,8 +714,9 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
|
||||
/**
|
||||
* Tells if the map contains the given key. Note that the result
|
||||
* may change spontanously, if all the key was only weakly
|
||||
* may change spontanously, if the key was only weakly
|
||||
* reachable.
|
||||
* @param key the key to look for
|
||||
* @return true, iff the map contains an entry for the given key.
|
||||
*/
|
||||
public boolean containsKey(Object key)
|
||||
|
@ -662,38 +726,38 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the value the key will be mapped to.
|
||||
* Gets the value the key is mapped to.
|
||||
* @return the value the key was mapped to. It returns null if
|
||||
* the key wasn't in this map, or if the mapped value was explicitly
|
||||
* set to null.
|
||||
* the key wasn't in this map, or if the mapped value was
|
||||
* explicitly set to null.
|
||||
*/
|
||||
public Object get(Object key)
|
||||
{
|
||||
cleanQueue();
|
||||
WeakBucket.Entry entry = internalGet(key);
|
||||
WeakBucket.WeakEntry entry = internalGet(key);
|
||||
return entry == null ? null : entry.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new key/value mapping to this map.
|
||||
* @param key the key. This may be null.
|
||||
* @param value the value. This may be null.
|
||||
* @param key the key, may be null
|
||||
* @param value the value, may be null
|
||||
* @return the value the key was mapped to previously. It returns
|
||||
* null if the key wasn't in this map, or if the mapped value was
|
||||
* explicitly set to null.
|
||||
* null if the key wasn't in this map, or if the mapped value
|
||||
* was explicitly set to null.
|
||||
*/
|
||||
public Object put(Object key, Object value)
|
||||
{
|
||||
cleanQueue();
|
||||
WeakBucket.Entry entry = internalGet(key);
|
||||
WeakBucket.WeakEntry entry = internalGet(key);
|
||||
if (entry != null)
|
||||
return entry.setValue(value);
|
||||
|
||||
modCount++;
|
||||
if (size >= threshold)
|
||||
rehash();
|
||||
|
||||
internalAdd(key, value);
|
||||
modCount++;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -702,17 +766,17 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* @param key the key. This may be null.
|
||||
* @return the value the key was mapped to previously. It returns
|
||||
* null if the key wasn't in this map, or if the mapped value was
|
||||
* explicitly set to null. */
|
||||
* explicitly set to null.
|
||||
*/
|
||||
public Object remove(Object key)
|
||||
{
|
||||
cleanQueue();
|
||||
WeakBucket.Entry entry = internalGet(key);
|
||||
WeakBucket.WeakEntry entry = internalGet(key);
|
||||
if (entry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
internalRemove(entry.getBucket());
|
||||
|
||||
modCount++;
|
||||
internalRemove(entry.getBucket());
|
||||
return entry.getValue();
|
||||
}
|
||||
|
||||
|
@ -722,10 +786,70 @@ public class WeakHashMap extends AbstractMap implements Map
|
|||
* silently removed. The returned set has therefore the same
|
||||
* strange behaviour (shrinking size(), disappearing entries) as
|
||||
* this weak hash map.
|
||||
* @return a set representation of the entries. */
|
||||
* @return a set representation of the entries.
|
||||
*/
|
||||
public Set entrySet()
|
||||
{
|
||||
cleanQueue();
|
||||
return theEntrySet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all entries from this map.
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
super.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the map contains at least one key which points to
|
||||
* the specified object as a value. Note that the result
|
||||
* may change spontanously, if its key was only weakly reachable.
|
||||
* @param value the value to search for
|
||||
* @return true if it is found in the set.
|
||||
*/
|
||||
public boolean containsValue(Object value)
|
||||
{
|
||||
cleanQueue();
|
||||
return super.containsValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set representation of the keys in this map. This
|
||||
* set will not have strong references to the keys, so they can be
|
||||
* silently removed. The returned set has therefore the same
|
||||
* strange behaviour (shrinking size(), disappearing entries) as
|
||||
* this weak hash map.
|
||||
* @return a set representation of the keys.
|
||||
*/
|
||||
public Set keySet()
|
||||
{
|
||||
cleanQueue();
|
||||
return super.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts all of the mappings from the given map into this one. If the
|
||||
* key already exists in this map, its value is replaced.
|
||||
* @param m the map to copy in
|
||||
*/
|
||||
public void putAll(Map m)
|
||||
{
|
||||
super.putAll(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection representation of the values in this map. This
|
||||
* collection will not have strong references to the keys, so mappings
|
||||
* can be silently removed. The returned collection has therefore the same
|
||||
* strange behaviour (shrinking size(), disappearing entries) as
|
||||
* this weak hash map.
|
||||
* @return a collection representation of the values.
|
||||
*/
|
||||
public Collection values()
|
||||
{
|
||||
cleanQueue();
|
||||
return super.values();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue