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:
Bryce McKinlay 2001-12-15 07:47:03 +00:00
parent def9790d51
commit d9fd7154ec
27 changed files with 12307 additions and 6993 deletions

View file

@ -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> 2001-12-14 Hans Boehm <Hans_Boehm@hp.com>
* libjava/prims.cc: Some old cleanups. The collector now * libjava/prims.cc: Some old cleanups. The collector now
handles test for out of memory. handles test for out of memory.

View file

@ -1200,6 +1200,7 @@ java/util/IdentityHashMap.java \
java/util/Iterator.java \ java/util/Iterator.java \
java/util/LinkedList.java \ java/util/LinkedList.java \
java/util/LinkedHashMap.java \ java/util/LinkedHashMap.java \
java/util/LinkedHashSet.java \
java/util/List.java \ java/util/List.java \
java/util/ListIterator.java \ java/util/ListIterator.java \
java/util/ListResourceBundle.java \ java/util/ListResourceBundle.java \

View file

@ -123,19 +123,13 @@ libgcj_basedir = @libgcj_basedir@
mkinstalldirs = @mkinstalldirs@ mkinstalldirs = @mkinstalldirs@
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
@TESTSUBDIR_TRUE@SUBDIRS = \ @TESTSUBDIR_TRUE@SUBDIRS = @TESTSUBDIR_TRUE@$(DIRLTDL) testsuite gcj include
@TESTSUBDIR_TRUE@$(DIRLTDL) testsuite gcj include @TESTSUBDIR_FALSE@SUBDIRS = @TESTSUBDIR_FALSE@$(DIRLTDL) gcj include
@TESTSUBDIR_FALSE@SUBDIRS = \ @USE_LIBDIR_TRUE@toolexeclibdir = @USE_LIBDIR_TRUE@$(libdir)$(MULTISUBDIR)
@TESTSUBDIR_FALSE@$(DIRLTDL) gcj include @USE_LIBDIR_FALSE@toolexeclibdir = @USE_LIBDIR_FALSE@$(toolexecdir)/lib$(MULTISUBDIR)
@USE_LIBDIR_TRUE@toolexeclibdir = \ @USE_LIBDIR_FALSE@toolexecdir = @USE_LIBDIR_FALSE@$(exec_prefix)/$(target_alias)
@USE_LIBDIR_TRUE@$(libdir)$(MULTISUBDIR) @XLIB_AWT_TRUE@cond_x_ltlibrary = @XLIB_AWT_TRUE@libgcjx.la
@USE_LIBDIR_FALSE@toolexeclibdir = \ @XLIB_AWT_FALSE@cond_x_ltlibrary =
@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_LTLIBRARIES = libgcj.la $(cond_x_ltlibrary)
toolexeclib_DATA = libgcj.spec toolexeclib_DATA = libgcj.spec
@ -143,20 +137,14 @@ data_DATA = libgcj.jar
secdir = $(libdir)/security secdir = $(libdir)/security
@NATIVE_TRUE@bin_PROGRAMS = \ @NATIVE_TRUE@bin_PROGRAMS = @NATIVE_TRUE@jv-convert gij rmic rmiregistry
@NATIVE_TRUE@jv-convert gij rmic rmiregistry
bin_SCRIPTS = addr2name.awk bin_SCRIPTS = addr2name.awk
@CANADIAN_TRUE@@NULL_TARGET_TRUE@ZIP = \ @CANADIAN_TRUE@@NULL_TARGET_TRUE@ZIP = @CANADIAN_TRUE@@NULL_TARGET_TRUE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
@CANADIAN_TRUE@@NULL_TARGET_TRUE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT) @CANADIAN_TRUE@@NULL_TARGET_FALSE@ZIP = @CANADIAN_TRUE@@NULL_TARGET_FALSE@jar
@CANADIAN_TRUE@@NULL_TARGET_FALSE@ZIP = \ @CANADIAN_FALSE@ZIP = @CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/fastjar/jar$(EXEEXT)
@CANADIAN_TRUE@@NULL_TARGET_FALSE@jar @CANADIAN_TRUE@GCJH = @CANADIAN_TRUE@gcjh
@CANADIAN_FALSE@ZIP = \ @CANADIAN_FALSE@GCJH = @CANADIAN_FALSE@$(MULTIBUILDTOP)../$(COMPPATH)/gcc/gcjh$(EXEEXT)
@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 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 \ @LIBGCJ_CXXFLAGS@ @X_CFLAGS@ $(WARNINGS) -D_GNU_SOURCE \
-DPREFIX="\"$(prefix)\"" -DPREFIX="\"$(prefix)\""
@USING_GCC_TRUE@AM_CFLAGS = \ @USING_GCC_TRUE@AM_CFLAGS = @USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS)
@USING_GCC_TRUE@@LIBGCJ_CFLAGS@ $(WARNINGS) @USING_GCC_FALSE@AM_CFLAGS = @USING_GCC_FALSE@@LIBGCJ_CFLAGS@
@USING_GCC_FALSE@AM_CFLAGS = \
@USING_GCC_FALSE@@LIBGCJ_CFLAGS@
JCFLAGS = -g JCFLAGS = -g
JC1FLAGS = @LIBGCJ_JAVAFLAGS@ $(GCJFLAGS) JC1FLAGS = @LIBGCJ_JAVAFLAGS@ $(GCJFLAGS)
@ -252,8 +238,7 @@ extra_headers = java/lang/Object.h java/lang/Class.h
NM = nm NM = nm
@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = \ @NATIVE_TRUE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = @NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS
@NATIVE_TRUE@@MAINTAINER_MODE_TRUE@gen-from-JIS
CONVERT_DIR = gnu/gcj/convert CONVERT_DIR = gnu/gcj/convert
@ -950,6 +935,7 @@ java/util/IdentityHashMap.java \
java/util/Iterator.java \ java/util/Iterator.java \
java/util/LinkedList.java \ java/util/LinkedList.java \
java/util/LinkedHashMap.java \ java/util/LinkedHashMap.java \
java/util/LinkedHashSet.java \
java/util/List.java \ java/util/List.java \
java/util/ListIterator.java \ java/util/ListIterator.java \
java/util/ListResourceBundle.java \ java/util/ListResourceBundle.java \
@ -1585,7 +1571,7 @@ libgcj-test.spec.in libgcj.spec.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar TAR = gtar
GZIP_ENV = --best GZIP_ENV = --best
DIST_SUBDIRS = @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include DIST_SUBDIRS = @DIRLTDL@ testsuite gcj include @DIRLTDL@ gcj include
DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ 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/GregorianCalendar.P .deps/java/util/HashMap.P \
.deps/java/util/HashSet.P .deps/java/util/Hashtable.P \ .deps/java/util/HashSet.P .deps/java/util/Hashtable.P \
.deps/java/util/IdentityHashMap.P .deps/java/util/Iterator.P \ .deps/java/util/IdentityHashMap.P .deps/java/util/Iterator.P \
.deps/java/util/LinkedHashMap.P .deps/java/util/LinkedList.P \ .deps/java/util/LinkedHashMap.P .deps/java/util/LinkedHashSet.P \
.deps/java/util/List.P .deps/java/util/ListIterator.P \ .deps/java/util/LinkedList.P .deps/java/util/List.P \
.deps/java/util/ListResourceBundle.P .deps/java/util/Locale.P \ .deps/java/util/ListIterator.P .deps/java/util/ListResourceBundle.P \
.deps/java/util/Map.P .deps/java/util/MissingResourceException.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/NoSuchElementException.P .deps/java/util/Observable.P \
.deps/java/util/Observer.P .deps/java/util/Properties.P \ .deps/java/util/Observer.P .deps/java/util/Properties.P \
.deps/java/util/PropertyPermission.P \ .deps/java/util/PropertyPermission.P \
@ -2735,7 +2722,7 @@ distdir: $(DISTFILES)
@for file in $(DISTFILES); do \ @for file in $(DISTFILES); do \
d=$(srcdir); \ d=$(srcdir); \
if test -d $$d/$$file; then \ if test -d $$d/$$file; then \
cp -pr $$/$$file $(distdir)/$$file; \ cp -pr $$d/$$file $(distdir)/$$file; \
else \ else \
test -f $(distdir)/$$file \ test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \

View file

@ -1,5 +1,5 @@
/* AbstractCollection.java -- Abstract implementation of most of Collection /* 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. This file is part of GNU Classpath.
@ -42,77 +42,119 @@ import java.lang.reflect.Array;
* backing data structure allows for a more efficient implementation. The * backing data structure allows for a more efficient implementation. The
* precise implementation used by AbstractCollection is documented, so that * precise implementation used by AbstractCollection is documented, so that
* subclasses can tell which methods could be implemented more efficiently. * 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 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 * Return an Iterator over this collection. The iterator must provide the
* hasNext and next methods and should in addition provide remove if the * hasNext and next methods and should in addition provide remove if the
* collection is modifiable. * collection is modifiable.
*
* @return an iterator
*/ */
public abstract Iterator 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(); public abstract int size();
/** /**
* Add an object to the collection. This implementation always throws an * Add an object to the collection (optional operation). This implementation
* UnsupportedOperationException - it should be overridden if the collection * always throws an UnsupportedOperationException - it should be
* is to be modifiable. * 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 * @param o the object to add
* @return true if the add operation caused the Collection to change * @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 * 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) 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 * Add all the elements of a given collection to this collection (optional
* implementation obtains an Iterator over the given collection and iterates * operation). This implementation obtains an Iterator over the given
* over it, adding each element with the add(Object) method (thus this method * collection and iterates over it, adding each element with the
* will fail with an UnsupportedOperationException if the add method does). * 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 * @param c the collection to add the elements of to this collection
* @return true if the add operation caused the Collection to change * @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 * 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) public boolean addAll(Collection c)
{ {
Iterator itr = c.iterator(); Iterator itr = c.iterator();
int size = c.size();
boolean modified = false; boolean modified = false;
for (int pos = 0; pos < size; pos++) int pos = c.size();
{ while (--pos >= 0)
modified |= add(itr.next()); modified |= add(itr.next());
}
return modified; return modified;
} }
/** /**
* Remove all elements from the collection. This implementation obtains an * Remove all elements from the collection (optional operation). This
* iterator over the collection and calls next and remove on it repeatedly * implementation obtains an iterator over the collection and calls next
* (thus this method will fail with an UnsupportedOperationException if the * and remove on it repeatedly (thus this method will fail with an
* Iterator's remove method does) until there are no more elements to remove. * 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. * 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 * iterator does not provide an implementation of remove
* @see Iterator#remove()
*/ */
public void clear() public void clear()
{ {
Iterator itr = iterator(); Iterator itr = iterator();
int size = size(); int pos = size();
for (int pos = 0; pos < size; pos++) while (--pos >= 0)
{ {
itr.next(); itr.next();
itr.remove(); itr.remove();
} }
} }
@ -130,12 +172,10 @@ public abstract class AbstractCollection implements Collection
public boolean contains(Object o) public boolean contains(Object o)
{ {
Iterator itr = iterator(); Iterator itr = iterator();
int size = size(); int pos = size();
for (int pos = 0; pos < size; pos++) while (--pos >= 0)
{ if (equals(o, itr.next()))
if (o == null ? itr.next() == null : o.equals(itr.next())) return true;
return true;
}
return false; return false;
} }
@ -147,17 +187,17 @@ public abstract class AbstractCollection implements Collection
* *
* @param c the collection to test against * @param c the collection to test against
* @return true if this collection contains all the elements in the given * @return true if this collection contains all the elements in the given
* collection * collection
* @throws NullPointerException if the given collection is null
* @see #contains(Object)
*/ */
public boolean containsAll(Collection c) public boolean containsAll(Collection c)
{ {
Iterator itr = c.iterator(); Iterator itr = c.iterator();
int size = c.size(); int pos = c.size();
for (int pos = 0; pos < size; pos++) while (--pos >= 0)
{ if (!contains(itr.next()))
if (!contains(itr.next())) return false;
return false;
}
return true; return true;
} }
@ -166,6 +206,7 @@ public abstract class AbstractCollection implements Collection
* size() == 0. * size() == 0.
* *
* @return true if this collection is empty. * @return true if this collection is empty.
* @see #size()
*/ */
public boolean isEmpty() 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 a single instance of an object from this collection (optional
* remove one element e such that (o == null ? e == null : o.equals(e)), if * operation). That is, remove one element e such that
* such an element exists. This implementation obtains an iterator over the * <code>(o == null ? e == null : o.equals(e))</code>, if such an element
* collection and iterates over it, testing each element for equality with * exists. This implementation obtains an iterator over the collection
* the given object. If it is equal, it is removed by the iterator's remove * and iterates over it, testing each element for equality with the given
* method (thus this method will fail with an UnsupportedOperationException * object. If it is equal, it is removed by the iterator's remove method
* if the Iterator's remove method does). After the first element has been * (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 * removed, true is returned; if the end of the collection is reached, false
* is returned. * is returned.
* *
* @param o the object to remove from this collection * @param o the object to remove from this collection
* @return true if the remove operation caused the Collection to change, or * @return true if the remove operation caused the Collection to change, or
* equivalently if the collection did contain o. * 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 * does not support the remove method
* @see Iterator#remove()
*/ */
public boolean remove(Object o) public boolean remove(Object o)
{ {
Iterator itr = iterator(); Iterator itr = iterator();
int size = size(); int pos = size();
for (int pos = 0; pos < size; pos++) while (--pos >= 0)
{ if (equals(o, itr.next()))
if (o == null ? itr.next() == null : o.equals(itr.next())) {
{ itr.remove();
itr.remove(); return true;
return true; }
}
}
return false; return false;
} }
/** /**
* Remove from this collection all its elements that are contained in a given * Remove from this collection all its elements that are contained in a given
* collection. This implementation iterates over this collection, and for * collection (optional operation). This implementation iterates over this
* each element tests if it is contained in the given collection. If so, it * collection, and for each element tests if it is contained in the given
* is removed by the Iterator's remove method (thus this method will fail * collection. If so, it is removed by the Iterator's remove method (thus
* with an UnsupportedOperationException if the Iterator's remove method * this method will fail with an UnsupportedOperationException if the
* does). * Iterator's remove method does).
* *
* @param c the collection to remove the elements of * @param c the collection to remove the elements of
* @return true if the remove operation caused the Collection to change * @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 * does not support the remove method
* @see Iterator#remove()
*/ */
public boolean removeAll(Collection c) public boolean removeAll(Collection c)
{
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(); Iterator itr = iterator();
int size = size();
boolean modified = false; boolean modified = false;
for (int pos = 0; pos < size; pos++) int pos = size();
{ while (--pos >= 0)
if (c.contains(itr.next())) if (c.contains(itr.next()))
{ {
itr.remove(); itr.remove();
modified = true; modified = true;
} }
}
return modified; return modified;
} }
/** /**
* Remove from this collection all its elements that are not contained in a * Remove from this collection all its elements that are not contained in a
* given collection. This implementation iterates over this collection, and * given collection (optional operation). This implementation iterates over
* for each element tests if it is contained in the given collection. If not, * this collection, and for each element tests if it is contained in the
* it is removed by the Iterator's remove method (thus this method will fail * given collection. If not, it is removed by the Iterator's remove method
* with an UnsupportedOperationException if the Iterator's remove method * (thus this method will fail with an UnsupportedOperationException if
* does). * the Iterator's remove method does).
* *
* @param c the collection to retain the elements of * @param c the collection to retain the elements of
* @return true if the remove operation caused the Collection to change * @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 * does not support the remove method
* @see Iterator#remove()
*/ */
public boolean retainAll(Collection c) public boolean retainAll(Collection c)
{
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(); Iterator itr = iterator();
int size = size();
boolean modified = false; boolean modified = false;
for (int pos = 0; pos < size; pos++) int pos = size();
{ while (--pos >= 0)
if (!c.contains(itr.next())) if (!c.contains(itr.next()))
{ {
itr.remove(); itr.remove();
modified = true; modified = true;
} }
}
return modified; return modified;
} }
@ -266,18 +346,18 @@ public abstract class AbstractCollection implements Collection
* Return an array containing the elements of this collection. This * Return an array containing the elements of this collection. This
* implementation creates an Object array of size size() and then iterates * implementation creates an Object array of size size() and then iterates
* over the collection, setting each element of the array from the value * 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 * @return an array containing the elements of this collection
*/ */
public Object[] toArray() public Object[] toArray()
{ {
Iterator itr = iterator(); Iterator itr = iterator();
Object[]a = new Object[size()]; int size = size();
for (int pos = 0; pos < a.length; pos++) Object[] a = new Object[size];
{ for (int pos = 0; pos < size; pos++)
a[pos] = itr.next(); a[pos] = itr.next();
}
return a; 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 * 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 * 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. * 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 * @param a the array to copy into, or of the correct run-time type
* @return the array that was produced * @return the array that was produced
* @exception ClassCastException if the type of the array precludes holding * @throws NullPointerException if the given array is null
* one of the elements of the Collection * @throws ArrayStoreException if the type of the array precludes holding
* one of the elements of the Collection
*/ */
public Object[] toArray(Object[]a) public Object[] toArray(Object[] a)
{ {
int size = size(); int size = size();
if (a.length < size) if (a.length < size)
{ a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
a = (Object[])Array.newInstance(a.getClass().getComponentType(), size);
size); else if (a.length > size)
} a[size] = null;
Iterator itr = iterator(); Iterator itr = iterator();
for (int pos = 0; pos < size; pos++) for (int pos = 0; pos < size; pos++)
{ a[pos] = itr.next();
a[pos] = itr.next();
}
if (a.length > size)
{
a[size] = null;
}
return a; return a;
} }
@ -331,15 +411,41 @@ public abstract class AbstractCollection implements Collection
public String toString() public String toString()
{ {
Iterator itr = iterator(); Iterator itr = iterator();
int size = size();
StringBuffer r = new StringBuffer("["); StringBuffer r = new StringBuffer("[");
for (int pos = 0; pos < size; pos++) for (int pos = size(); pos > 0; pos--)
{ {
r.append(itr.next()); r.append(itr.next());
if (pos < size - 1) if (pos > 1)
r.append(", "); r.append(", ");
} }
r.append("]"); r.append("]");
return r.toString(); 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

View file

@ -1,5 +1,5 @@
/* AbstractMap.java -- Abstract implementation of most of Map /* 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. 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. */ executable file might be covered by the GNU General Public License. */
// TO DO:
// comments
// test suite
package java.util; 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 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 * The cache for {@link #keySet()}.
* entrySet().clear(). */
// 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 * @throws UnsupportedOperationException if <code>entrySet().clear()</code>
* @specnote The JCL book claims that this implementation always throws * does not support clearing.
* UnsupportedOperationException, while the online docs claim it * @see Set#clear()
* calls entrySet().clear(). We take the later to be correct.
*/ */
public void clear() public void clear()
{ {
@ -48,246 +97,414 @@ 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 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) public boolean containsKey(Object key)
{ {
Object k; Iterator entries = entrySet().iterator();
Set es = entrySet(); int pos = size();
Iterator entries = es.iterator(); while (--pos >= 0)
int size = size(); if (equals(key, ((Map.Entry) entries.next()).getKey()))
for (int pos = 0; pos < size; pos++) return true;
{
k = ((Map.Entry) entries.next()).getKey();
if (key == null ? k == null : key.equals(k))
return true;
}
return false; 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) public boolean containsValue(Object value)
{ {
Object v; Iterator entries = entrySet().iterator();
Set es = entrySet(); int pos = size();
Iterator entries = es.iterator(); while (--pos >= 0)
int size = size(); if (equals(value, ((Map.Entry) entries.next()).getValue()))
for (int pos = 0; pos < size; pos++) return true;
{
v = ((Map.Entry) entries.next()).getValue();
if (value == null ? v == null : value.equals(v))
return true;
}
return false; 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(); 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) public boolean equals(Object o)
{ {
if (o == this) return (o == this ||
return true; (o instanceof Map &&
if (!(o instanceof Map)) entrySet().equals(((Map) o).entrySet())));
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;
} }
/**
* 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) public Object get(Object key)
{ {
Set s = entrySet(); Iterator entries = entrySet().iterator();
Iterator entries = s.iterator(); int pos = size();
int size = size(); while (--pos >= 0)
for (int pos = 0; pos < size; pos++)
{ {
Map.Entry entry = (Map.Entry) entries.next(); Map.Entry entry = (Map.Entry) entries.next();
Object k = entry.getKey(); if (equals(key, entry.getKey()))
if (key == null ? k == null : key.equals(k)) return entry.getValue();
return entry.getValue();
} }
return null; 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() public int hashCode()
{ {
int hashcode = 0; return entrySet().hashCode();
Iterator itr = entrySet().iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
{
hashcode += itr.next().hashCode();
}
return 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() public boolean isEmpty()
{ {
return size() == 0; 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() public Set keySet()
{ {
if (this.keySet == null) if (keys == null)
keys = new AbstractSet()
{ {
this.keySet = new AbstractSet() public int size()
{ {
public int size() return AbstractMap.this.size();
{ }
return AbstractMap.this.size();
}
public boolean contains(Object key) public boolean contains(Object key)
{ {
return AbstractMap.this.containsKey(key); return containsKey(key);
} }
public Iterator iterator() public Iterator iterator()
{ {
return new Iterator() return new Iterator()
{ {
Iterator map_iterator = AbstractMap.this.entrySet().iterator(); private final Iterator map_iterator = entrySet().iterator();
public boolean hasNext() public boolean hasNext()
{ {
return map_iterator.hasNext(); return map_iterator.hasNext();
} }
public Object next() public Object next()
{ {
return ((Map.Entry) map_iterator.next()).getKey(); return ((Map.Entry) map_iterator.next()).getKey();
} }
public void remove() public void remove()
{ {
map_iterator.remove(); map_iterator.remove();
} }
}; };
} }
}; };
} 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) public Object put(Object key, Object value)
{ {
throw new UnsupportedOperationException(); 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) public void putAll(Map m)
{ {
Map.Entry entry;
Iterator entries = m.entrySet().iterator(); Iterator entries = m.entrySet().iterator();
int size = m.size(); int pos = size();
while (--pos >= 0)
for (int pos = 0; pos < size; pos++)
{ {
entry = (Map.Entry) entries.next(); Map.Entry entry = (Map.Entry) entries.next();
put(entry.getKey(), entry.getValue()); 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) public Object remove(Object key)
{ {
Iterator entries = entrySet().iterator(); Iterator entries = entrySet().iterator();
int size = size(); int pos = size();
while (--pos >= 0)
for (int pos = 0; pos < size; pos++)
{ {
Map.Entry entry = (Map.Entry) entries.next(); Map.Entry entry = (Map.Entry) entries.next();
Object k = entry.getKey(); if (equals(key, entry.getKey()))
if (key == null ? k == null : key.equals(k)) {
{ // Must get the value before we remove it from iterator.
Object value = entry.getValue(); Object r = entry.getValue();
entries.remove(); entries.remove();
return value; return r;
} }
} }
return null; 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() public int size()
{ {
return entrySet().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() public String toString()
{ {
Iterator entries = entrySet().iterator(); Iterator entries = entrySet().iterator();
int size = size();
StringBuffer r = new StringBuffer("{"); 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 // Append the toString value of the entries rather than calling
// getKey/getValue. This is more efficient and it matches the JDK // getKey/getValue. This is more efficient and it matches the JDK
// behaviour. // behaviour.
r.append(entries.next()); r.append(entries.next());
if (pos < size - 1) if (pos > 1)
r.append(", "); r.append(", ");
} }
r.append("}"); r.append("}");
return r.toString(); 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() public Collection values()
{ {
if (this.valueCollection == null) if (values == null)
values = new AbstractCollection()
{ {
this.valueCollection = new AbstractCollection() public int size()
{ {
public int size() return AbstractMap.this.size();
{ }
return AbstractMap.this.size();
}
public Iterator iterator() public Iterator iterator()
{ {
return new Iterator() return new Iterator()
{ {
Iterator map_iterator = AbstractMap.this.entrySet().iterator(); private final Iterator map_iterator = entrySet().iterator();
public boolean hasNext() public boolean hasNext()
{ {
return map_iterator.hasNext(); return map_iterator.hasNext();
} }
public Object next() public Object next()
{ {
return ((Map.Entry) map_iterator.next()).getValue(); return ((Map.Entry) map_iterator.next()).getValue();
} }
public void remove() public void remove()
{ {
map_iterator.remove(); map_iterator.remove();
} }
}; };
} }
}; };
} return values;
return this.valueCollection;
} }
private Collection valueCollection = null; /**
private Set keySet = null; * 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();
}
} }

View file

@ -1,5 +1,5 @@
/* AbstractSequentialList.java -- List implementation for sequential access /* 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. 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. */ 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; package java.util;
/** /**
* Abstract superclass to make it easier to implement the List interface when * 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 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. * Returns a ListIterator over the list, starting from position index.
* Subclasses must provide an implementation of this method. * 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 &lt; 0 || index &gt; size()
*/ */
public abstract ListIterator listIterator(int index); public abstract ListIterator listIterator(int index);
/** /**
* Add an element to the list at a given index. This implementation obtains a * Insert an element into the list at a given position (optional operation).
* ListIterator positioned at the specified index, and then adds the element * This shifts all existing elements from that position to the end one
* using the ListIterator's add method. * 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 index the location to insert the item
* @param o the element to insert * @param o the object to insert
* @exception IndexOutOfBoundsException if index < 0 || index > size() * @throws UnsupportedOperationException if this list does not support the
* @exception UnsupportedOperationException if the iterator returned by * add operation
* listIterator(index) does not support the add method. * @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; 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) public void add(int index, Object o)
{ {
ListIterator i = listIterator(index); listIterator(index).add(o);
i.add(o);
} }
/** /**
* @specnote The spec in the JDK1.3 online docs is wrong. The implementation * Insert the contents of a collection into the list at a given position
* should not call next() to skip over new elements as they are * (optional operation). Shift all elements at that position to the right
* added, because iterator.add() should add new elements BEFORE * by the number of elements inserted. This operation is undefined if
* the cursor. * 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 &lt; 0 || index &gt; 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) public boolean addAll(int index, Collection c)
{ {
boolean modified = false;
Iterator ci = c.iterator(); Iterator ci = c.iterator();
int size = c.size(); int size = c.size();
ListIterator i = listIterator(index); ListIterator i = listIterator(index);
for (int pos = 0; pos < size; pos++) for (int pos = size; pos > 0; pos--)
{ i.add(ci.next());
i.add(ci.next()); return size > 0;
}
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 an Iterator over this List. This implementation returns * Get the element at a given index in this list. This implementation
* listIterator(). * 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 &lt; 0 || index &gt;= 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() public Iterator iterator()
{ {
return listIterator(); 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 &lt; 0 || index &gt;= size()
*/
public Object remove(int index) 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); ListIterator i = listIterator(index);
if (index < 0 || index > size())
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
Object removed = i.next(); Object removed = i.next();
i.remove(); i.remove();
return removed; 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 &lt; 0 || index &gt;= 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) 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); ListIterator i = listIterator(index);
if (index < 0 || index > size())
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
Object old = i.next(); Object old = i.next();
i.set(o); i.set(o);
return old; return old;

View file

@ -1,5 +1,5 @@
/* AbstractSet.java -- Abstract implementation of most of Set /* 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. 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 * on them - specifically, no element may be in the set more than once). This
* class simply provides implementations of equals() and hashCode() to fulfil * class simply provides implementations of equals() and hashCode() to fulfil
* the requirements placed on them by the Set interface. * 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 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 * 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 * 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) public boolean equals(Object o)
{ {
if (o == this) return (o == this ||
return true; (o instanceof Set && ((Set) o).size() == size()
else if (o instanceof Set && ((Set) o).size() == size()) && containsAll((Collection) o)));
return containsAll((Collection) o);
else
return false;
} }
/** /**
@ -69,14 +84,45 @@ public abstract class AbstractSet extends AbstractCollection implements Set
public int hashCode() public int hashCode()
{ {
Iterator itr = iterator(); Iterator itr = iterator();
int size = size();
int hash = 0; int hash = 0;
for (int pos = 0; pos < size; pos++) int pos = size();
{ while (--pos >= 0)
Object obj = itr.next(); hash += hashCode(itr.next());
if (obj != null)
hash += obj.hashCode();
}
return hash; 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();
}
} }

View file

@ -1,6 +1,6 @@
/* ArrayList.java -- JDK1.2's answer to Vector; this is an array-backed /* ArrayList.java -- JDK1.2's answer to Vector; this is an array-backed
implementation of the List interface 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. This file is part of GNU Classpath.
@ -35,112 +35,143 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
/** /**
* An array-backed implementation of the List interface. ArrayList * An array-backed implementation of the List interface. This implements
* performs well on simple tasks: random access into a list, appending * all optional list operations, and permits null elements, so that it is
* to or removing from the end of a list, checking the size, &c. * 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>
* *
* @author Jon A. Zeppieri * Each list has a capacity, and as the array reaches that capacity it
* @see java.util.AbstractList * is automatically transferred to a larger array. You also have access to
* @see java.util.List * 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
* @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 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; 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. * 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) public ArrayList(int capacity)
{ {
// Must explicitly check, to get correct exception.
if (capacity < 0)
throw new IllegalArgumentException();
data = new Object[capacity]; data = new Object[capacity];
} }
/** /**
* Construct a new ArrayList with the default capcity * Construct a new ArrayList with the default capcity (16).
*/ */
public ArrayList() public ArrayList()
{ {
this(DEFAULT_CAPACITY); this(DEFAULT_CAPACITY);
} }
/** /**
* Construct a new ArrayList, and initialize it with the elements * Construct a new ArrayList, and initialize it with the elements
* in the supplied Collection; Sun specs say that the initial * in the supplied Collection. The initial capacity is 110% of the
* capacity is 110% of the Collection's size. * Collection's size.
* *
* @param c the collection whose elements will initialize this list * @param c the collection whose elements will initialize this list
* @throws NullPointerException if c is null
*/ */
public ArrayList(Collection c) public ArrayList(Collection c)
{ {
this((int) (c.size() * 1.1)); this((int) (c.size() * 1.1f));
addAll(c); addAll(c);
} }
/** /**
* Guarantees that this list will have at least enough capacity to * Trims the capacity of this List to be equal to its size;
* hold minCapacity elements. * a memory saver.
*
* @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
*/ */
public void ensureCapacity(int minCapacity) public void trimToSize()
{ {
Object[] newData; // Not a structural change from the perspective of iterators on this list,
int current = data.length; // so don't update modCount.
if (size != data.length)
if (minCapacity > current)
{ {
newData = new Object[Math.max((current * 2), minCapacity)]; Object[] newData = new Object[size];
System.arraycopy(data, 0, newData, 0, size); System.arraycopy(data, 0, newData, 0, size);
data = newData; 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++; int current = data.length;
if (size == data.length)
ensureCapacity(size + 1); if (minCapacity > current)
data[size++] = e; {
return true; 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 * @return the list size
* @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
*/ */
public int size() public int size()
{ {
@ -148,202 +179,81 @@ 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 true if there are no elements
* @return the removed Object
* @throws IndexOutOfBoundsException (iIndex < 0) || (iIndex >= size())
*/ */
public Object remove(int index) public boolean isEmpty()
{ {
modCount++; return size == 0;
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;
} }
/** /**
* 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 e the element whose inclusion in the List is being tested
* @param toIndex one greater than the last index which will be * @return true if the list contains e
* removed
*/ */
protected void removeRange(int fromIndex, int toIndex) public boolean contains(Object e)
{ {
modCount++; return indexOf(e) != -1;
if (fromIndex != toIndex)
{
System.arraycopy(data, toIndex, data, fromIndex, size - toIndex);
size -= (toIndex - fromIndex);
}
} }
/** /**
* Adds the supplied element at the specified index, shifting all * Returns the lowest index at which element appears in this List, or
* elements currently at that index or higher one to the right. * -1 if it does not appear.
* *
* @param index the index at which the element is being added * @param e the element whose inclusion in the List is being tested
* @param e the item being added * @return the index where e was found
*/ */
public void add(int index, Object e) public int indexOf(Object e)
{ {
modCount++; for (int i = 0; i < size; i++)
if (index < 0 || index > size) if (equals(e, data[i]))
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" + return i;
size); return -1;
if (size == data.length)
ensureCapacity(size + 1);
if (index != size)
System.arraycopy(data, index, data, index + 1, size - index);
data[index] = e;
size++;
}
/**
* Add each element in the supplied Collection to this List.
*
* @param c a Collection containing elements to be
* added to this List
*/
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
*/
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 * Returns the highest index at which element appears in this List, or
* -1 if it does not appear.
*
* @param e the element whose inclusion in the List is being tested
* @return the index where e was found
*/
public int lastIndexOf(Object e)
{
for (int i = size - 1; i >= 0; i--)
if (equals(e, data[i]))
return i;
return -1;
}
/**
* Creates a shallow copy of this ArrayList (elements are not cloned).
*
* @return the cloned object
*/ */
public Object clone() public Object clone()
{ {
ArrayList clone = null; ArrayList clone = null;
try try
{ {
clone = (ArrayList) super.clone(); clone = (ArrayList) super.clone();
clone.data = new Object[data.length]; clone.data = (Object[]) data.clone();
System.arraycopy(data, 0, clone.data, 0, size); }
catch (CloneNotSupportedException e)
{
// Impossible to get here.
} }
catch (CloneNotSupportedException e) {}
return clone; 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 * @return an array representation of this list
* 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
*/ */
public Object[] toArray() public Object[] toArray()
{ {
@ -356,62 +266,304 @@ public class ArrayList extends AbstractList
* Returns an Array whose component type is the runtime component type of * 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 * the passed-in Array. The returned Array is populated with all of the
* elements in this ArrayList. If the passed-in Array is not large enough * elements in this ArrayList. If the passed-in Array is not large enough
* to store all of the elements in this List, a new Array will be created * 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 * 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. * 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) if (a.length < size)
array = (Object[]) Array.newInstance(array.getClass().getComponentType(), a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
size); size);
else if (array.length > size) else if (a.length > size)
array[size] = null; a[size] = null;
System.arraycopy(data, 0, array, 0, size); System.arraycopy(data, 0, a, 0, size);
return array; return a;
} }
/** /**
* Trims the capacity of this List to be equal to its size; * Retrieves the element at the user-supplied index.
* a memory saver. *
* @param index the index of the element we are fetching
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
*/ */
public void trimToSize() public Object get(int index)
{ {
// not a structural change from the perspective of iterators on this list, checkBoundExclusive(index);
// so don't update modCount return data[index];
Object[] newData = new Object[size];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
} }
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 &lt; 0 || index &gt;= 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 &lt; 0 || index &gt; 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 &lt; 0 || index &gt;= 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 &lt; 0 || index &gt; 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 &gt; 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 &gt;= 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 i;
int j;
for (i = 0; i < size; i++)
if (c.contains(data[i]))
break;
if (i == size)
return false;
// The 'size' field. modCount++;
out.defaultWriteObject(); for (j = i++; i < size; i++)
if (! c.contains(data[i]))
// FIXME: Do we really want to serialize unused list entries?? data[j++] = data[i];
out.writeInt(data.length); size -= i - j;
for (i = 0; i < data.length; i++) return true;
out.writeObject(data[i]);
} }
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 throws IOException, ClassNotFoundException
{ {
int i;
int capacity;
// the `size' field. // the `size' field.
in.defaultReadObject(); s.defaultReadObject();
int capacity = s.readInt();
capacity = in.readInt();
data = new Object[capacity]; data = new Object[capacity];
for (int i = 0; i < capacity; i++)
for (i = 0; i < capacity; i++) data[i] = s.readObject();
data[i] = in.readObject();
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* BasicMapEntry.java -- a class providing a plain-vanilla implementation of /* BasicMapEntry.java -- a class providing a plain-vanilla implementation of
the Map.Entry interface; could be used anywhere in java.util 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. 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; package java.util;
/** /**
* A class which implements Map.Entry. It is shared by HashMap, TreeMap, and * A class which implements Map.Entry. It is shared by HashMap, TreeMap,
* Hashtable. * Hashtable, and Collections. It is not specified by the JDK, but makes
* life much easier.
* *
* @author Jon Zeppieri * @author Jon Zeppieri
* @author Eric Blake <ebb9@email.byu.edu>
*/ */
class BasicMapEntry implements Map.Entry class BasicMapEntry implements Map.Entry
{ {
/**
* The key. Package visible for direct manipulation.
*/
Object key; Object key;
/**
* The value. Package visible for direct manipulation.
*/
Object value; Object value;
/**
* Basic constructor initializes the fields.
* @param newKey the key
* @param newValue the value
*/
BasicMapEntry(Object newKey, Object newValue) BasicMapEntry(Object newKey, Object newValue)
{ {
key = newKey; key = newKey;
value = newValue; 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) public final boolean equals(Object o)
{ {
if (!(o instanceof Map.Entry)) if (! (o instanceof Map.Entry))
return false; 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; Map.Entry e = (Map.Entry) o;
return (key == null ? e.getKey() == null : key.equals(e.getKey()) return (AbstractCollection.equals(key, e.getKey())
&& value == null ? e.getValue() == null && AbstractCollection.equals(value, e.getValue()));
: value.equals(e.getValue()));
} }
/**
* Get the key corresponding to this entry.
*
* @return the key
*/
public final Object getKey() public final Object getKey()
{ {
return key; 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() public final Object getValue()
{ {
return value; 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() public final int hashCode()
{ {
int kc = (key == null ? 0 : key.hashCode()); return (AbstractCollection.hashCode(key)
int vc = (value == null ? 0 : value.hashCode()); ^ AbstractCollection.hashCode(value));
return kc ^ vc;
} }
/** /**
* sets the value of this Map.Entry. Note that this is overriden by * Replaces the value with the specified object. This writes through
* Hashtable.Entry, which does not permit a null value. * 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) public Object setValue(Object newVal)
{ {
@ -83,6 +144,12 @@ class BasicMapEntry implements Map.Entry
return r; 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() public final String toString()
{ {
return key + "=" + value; return key + "=" + value;

View file

@ -1,6 +1,5 @@
// BitSet - A vector of bits. /* BitSet.java -- A vector of bits.
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
This file is part of GNU Classpath. 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 * while another thread is simultaneously modifying it, the results are
* undefined. * 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 Jochen Hoenicke
* @author Tom Tromey <tromey@cygnus.com> * @author Tom Tromey <tromey@cygnus.com>
* @date October 23, 1998. * @author Eric Blake <ebb9@email.byu.edu>
* @status API complete to JDK 1.3. * @status updated to 1.4
*/ */
public class BitSet implements Cloneable, Serializable 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() public BitSet()
{ {
@ -75,18 +84,15 @@ public class BitSet implements Cloneable, Serializable
/** /**
* Create a new empty bit set, with a given size. This * Create a new empty bit set, with a given size. This
* constructor reserves enough space to represent the integers * constructor reserves enough space to represent the integers
* from <code>0</code> to <code>nbits-1</code>. * from <code>0</code> to <code>nbits-1</code>.
* @param nbits the initial size of the bit set. *
* @throws NegativeArraySizeException if the specified initial * @param nbits the initial size of the bit set
* size is negative. * @throws NegativeArraySizeException if nbits &lt; 0
* @require nbits >= 0
*/ */
public BitSet(int nbits) public BitSet(int nbits)
{ {
if (nbits < 0) int length = nbits >>> 6;
throw new NegativeArraySizeException(); if ((nbits & LONG_MASK) != 0)
int length = nbits / 64;
if (nbits % 64 != 0)
++length; ++length;
bits = new long[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 * Performs the logical AND operation on this bit set and the
* given <code>set</code>. This means it builds the intersection * given <code>set</code>. This means it builds the intersection
* of the two sets. The result is stored into this bit set. * 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) public void and(BitSet bs)
{ {
@ -104,63 +111,143 @@ public class BitSet implements Cloneable, Serializable
int i; int i;
for (i = 0; i < max; ++i) for (i = 0; i < max; ++i)
bits[i] &= bs.bits[i]; bits[i] &= bs.bits[i];
for (; i < bits.length; ++i) while (i < bits.length)
bits[i] = 0; bits[i++] = 0;
} }
/** /**
* Performs the logical AND operation on this bit set and the * Performs the logical AND operation on this bit set and the
* complement of the given <code>set</code>. This means it * complement of the given <code>set</code>. This means it
* selects every element in the first set, that isn't in the * selects every element in the first set, that isn't in the
* second set. The result is stored into this bit set. * second set. The result is stored into this bit set.
* @param set the second bit set. *
* @require set != null * @param set the second bit set
* @since JDK1.2 * @throws NullPointerException if set is null
* @since 1.2
*/ */
public void andNot(BitSet bs) public void andNot(BitSet bs)
{ {
int max = Math.min(bits.length, bs.bits.length); int i = Math.min(bits.length, bs.bits.length);
int i; while (--i >= 0)
for (i = 0; i < max; ++i)
bits[i] &= ~bs.bits[i]; 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 * Removes the integer <code>bitIndex</code> from this set. That is
* the corresponding bit is cleared. If the index is not in the set, * the corresponding bit is cleared. If the index is not in the set,
* this method does nothing. * this method does nothing.
* @param bitIndex a non-negative integer. *
* @exception ArrayIndexOutOfBoundsException if the specified bit index * @param bitIndex a non-negative integer
* is negative. * @throws IndexOutOfBoundsException if bitIndex &lt; 0
* @require bitIndex >= 0
*/ */
public void clear(int pos) public void clear(int pos)
{ {
if (pos < 0) int offset = pos >>> 6;
throw new IndexOutOfBoundsException();
int bit = pos % 64;
int offset = pos / 64;
ensure(offset); 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 &lt; 0 || from &gt; 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 * 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 * class and contains the same elements. But it doesn't change when
* this bit set changes. * this bit set changes.
*
* @return the clone of this object. * @return the clone of this object.
*/ */
public Object clone() public Object clone()
{ {
BitSet bs = new BitSet(bits.length * 64); try
System.arraycopy(bits, 0, bs.bits, 0, bits.length); {
return bs; 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 * Returns true if the <code>obj</code> is a bit set that contains
* exactly the same elements as this bit set, otherwise false. * 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) public boolean equals(Object obj)
{ {
@ -171,42 +258,124 @@ public class BitSet implements Cloneable, Serializable
int i; int i;
for (i = 0; i < max; ++i) for (i = 0; i < max; ++i)
if (bits[i] != bs.bits[i]) if (bits[i] != bs.bits[i])
return false; return false;
// If one is larger, check to make sure all extra bits are 0. // If one is larger, check to make sure all extra bits are 0.
for (int j = i; j < bits.length; ++j) for (int j = i; j < bits.length; ++j)
if (bits[j] != 0) if (bits[j] != 0)
return false; return false;
for (int j = i; j < bs.bits.length; ++j) for (int j = i; j < bs.bits.length; ++j)
if (bs.bits[j] != 0) if (bs.bits[j] != 0)
return false; return false;
return true; 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 &gt; to || from &lt; 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 * Returns true if the integer <code>bitIndex</code> is in this bit
* set, otherwise false. * set, otherwise false.
* @param bitIndex a non-negative integer *
* @return the value of the bit at the specified index. * @param pos a non-negative integer
* @exception ArrayIndexOutOfBoundsException if the specified bit index * @return the value of the bit at the specified index
* is negative. * @throws IndexOutOfBoundsException if the index is negative
* @require bitIndex >= 0
*/ */
public boolean get(int pos) public boolean get(int pos)
{ {
if (pos < 0) int offset = pos >>> 6;
throw new IndexOutOfBoundsException();
int bit = pos % 64;
int offset = pos / 64;
if (offset >= bits.length) if (offset >= bits.length)
return false; return false;
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
return (bits[offset] & (1L << bit)) == 0 ? false : true; // so we'll just let that be our exception.
return (bits[offset] & (1L << pos)) != 0;
} }
/** /**
* Returns a hash code value for this bit set. The hash code of * 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 &gt; to || from &lt; 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;
}
/**
* Returns a hash code value for this bit set. The hash code of
* two bit sets containing the same integers is identical. The algorithm * two bit sets containing the same integers is identical. The algorithm
* used to compute it is as follows: * used to compute it is as follows:
* *
@ -233,21 +402,55 @@ public class BitSet implements Cloneable, Serializable
* </pre> * </pre>
* *
* Note that the hash code values changes, if the set is changed. * Note that the hash code values changes, if the set is changed.
*
* @return the hash code value for this bit set. * @return the hash code value for this bit set.
*/ */
public int hashCode() public int hashCode()
{ {
long h = 1234; long h = 1234;
for (int i = bits.length - 1; i >= 0; --i) for (int i = bits.length; i > 0; )
h ^= bits[i] * (i + 1); h ^= i * bits[--i];
return (int) ((h >> 32) ^ h); 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 * Returns the logical number of bits actually used by this bit
* set. It returns the index of the highest set bit plus one. * set. It returns the index of the highest set bit plus one.
* Note that this method doesn't return the number of set bits. * Note that this method doesn't return the number of set bits.
* @return the index of the highest set bit plus one. *
* @return the index of the highest set bit plus one.
*/ */
public int length() public int length()
{ {
@ -266,54 +469,186 @@ public class BitSet implements Cloneable, Serializable
// b >= 0 checks if the highest bit is zero. // b >= 0 checks if the highest bit is zero.
while (b >= 0) while (b >= 0)
{ {
--len; --len;
b <<= 1; b <<= 1;
} }
return len; 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 * Performs the logical OR operation on this bit set and the
* given <code>set</code>. This means it builds the union * given <code>set</code>. This means it builds the union
* of the two sets. The result is stored into this bit set, which * of the two sets. The result is stored into this bit set, which
* grows as necessary. * grows as necessary.
* @param set the second bit set. *
* @exception OutOfMemoryError if the current set can't grow. * @param bs the second bit set
* @require set != null * @throws NullPointerException if bs is null
*/ */
public void or(BitSet bs) public void or(BitSet bs)
{ {
ensure(bs.bits.length - 1); ensure(bs.bits.length - 1);
int i; for (int i = bs.bits.length - 1; i >= 0; i--)
for (i = 0; i < bs.bits.length; ++i)
bits[i] |= bs.bits[i]; bits[i] |= bs.bits[i];
} }
/** /**
* Add the integer <code>bitIndex</code> to this set. That is * Add the integer <code>bitIndex</code> to this set. That is
* the corresponding bit is set to true. If the index was already in * the corresponding bit is set to true. If the index was already in
* the set, this method does nothing. The size of this structure * the set, this method does nothing. The size of this structure
* is automatically increased as necessary. * is automatically increased as necessary.
* @param bitIndex a non-negative integer. *
* @exception ArrayIndexOutOfBoundsException if the specified bit index * @param pos a non-negative integer.
* is negative. * @throws IndexOutOfBoundsException if pos is negative
* @require bitIndex >= 0
*/ */
public void set(int pos) public void set(int pos)
{ {
if (pos < 0) int offset = pos >>> 6;
throw new IndexOutOfBoundsException();
int bit = pos % 64;
int offset = pos / 64;
ensure(offset); 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 &lt; 0 || from &gt; 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 &lt; 0 || from &gt; 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 * Returns the number of bits actually used by this bit set. Note
* that this method doesn't return the number of set bits. * that this method doesn't return the number of set bits, and that
* @returns the number of bits currently used. * future requests for larger bits will make this automatically grow.
*
* @return the number of bits currently used.
*/ */
public int size() public int size()
{ {
@ -324,32 +659,32 @@ public class BitSet implements Cloneable, Serializable
* Returns the string representation of this bit set. This * Returns the string representation of this bit set. This
* consists of a comma separated list of the integers in this set * consists of a comma separated list of the integers in this set
* surrounded by curly braces. There is a space after each comma. * surrounded by curly braces. There is a space after each comma.
* A sample string is thus "{1, 3, 53}".
* @return the string representation. * @return the string representation.
*/ */
public String toString() public String toString()
{ {
String r = "{"; StringBuffer r = new StringBuffer("{");
boolean first = true; boolean first = true;
for (int i = 0; i < bits.length; ++i) for (int i = 0; i < bits.length; ++i)
{ {
long bit = 1; long bit = 1;
long word = bits[i]; long word = bits[i];
if (word == 0) if (word == 0)
continue; continue;
for (int j = 0; j < 64; ++j) for (int j = 0; j < 64; ++j)
{ {
if ((word & bit) != 0) if ((word & bit) != 0)
{ {
if (!first) if (! first)
r += ", "; r.append(", ");
r += Integer.toString(64 * i + j); r.append(64 * i + j);
first = false; first = false;
} }
bit <<= 1; bit <<= 1;
} }
} }
return r.append("}").toString();
return r += "}";
} }
/** /**
@ -357,32 +692,30 @@ public class BitSet implements Cloneable, Serializable
* given <code>set</code>. This means it builds the symmetric * given <code>set</code>. This means it builds the symmetric
* remainder of the two sets (the elements that are in one set, * 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, * but not in the other). The result is stored into this bit set,
* which grows as necessary. * which grows as necessary.
* @param set the second bit set. *
* @exception OutOfMemoryError if the current set can't grow. * @param bs the second bit set
* @require set != null * @throws NullPointerException if bs is null
*/ */
public void xor(BitSet bs) public void xor(BitSet bs)
{ {
ensure(bs.bits.length - 1); ensure(bs.bits.length - 1);
int i; for (int i = bs.bits.length - 1; i >= 0; i--)
for (i = 0; i < bs.bits.length; ++i)
bits[i] ^= bs.bits[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) private final void ensure(int lastElt)
{ {
if (lastElt + 1 > bits.length) if (lastElt >= bits.length)
{ {
long[] nd = new long[lastElt + 1]; long[] nd = new long[lastElt + 1];
System.arraycopy(bits, 0, nd, 0, bits.length); System.arraycopy(bits, 0, nd, 0, bits.length);
bits = nd; bits = nd;
} }
} }
// The actual bits.
long[] bits;
private static final long serialVersionUID = 7997698588986878753L;
} }

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* Dictionary.java -- an abstract (and essentially worthless) /* Dictionary.java -- an abstract (and essentially worthless)
class which is Hashtable's superclass 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. 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. * This is an abstract class which has really gone by the wayside.
* People at Javasoft are probably embarrassed by it. At this point, * 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 * 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 * At any rate, this was what came before the <pre>Map</pre> interface
* in the Collections framework. * in the Collections framework.
* *
* @author Jon Zeppieri * @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 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(); public abstract Enumeration elements();
/** /**
* returns the value associated with the supplied key, or null * Returns the value associated with the supplied key, or null
* if no such value exists * 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 * @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); 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(); 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(); public abstract Enumeration keys();
/** /**
* inserts a new value into this Dictionary, located by the * Inserts a new value into this Dictionary, located by the
* supllied key; note: Dictionary's subclasses (all 1 of them) * supplied key. Dictionary does not support null keys or values, so
* do not support null keys or values (I can only assume this * a null return can safely be interpreted as adding a new key.
* would have been more general)
* *
* @param key the key which locates the value * @param key the key which locates the value
* @param value the value to put into the Dictionary * @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); 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 * @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); 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(); public abstract int size();
} }

View file

@ -53,14 +53,16 @@ import java.io.ObjectOutputStream;
* <p> * <p>
* *
* Under ideal circumstances (no collisions), HashMap offers O(1) * 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 * of course, O(n)). In the worst case (all keys map to the same
* hash code -- very unlikely), most operations are O(n). * hash code -- very unlikely), most operations are O(n).
* <p> * <p>
* *
* HashMap is part of the JDK1.2 Collections API. It differs from * 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 * 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> * <p>
* *
* The iterators are <i>fail-fast</i>, meaning that any structural * The iterators are <i>fail-fast</i>, meaning that any structural
@ -81,6 +83,7 @@ import java.io.ObjectOutputStream;
* @see IdentityHashMap * @see IdentityHashMap
* @see Hashtable * @see Hashtable
* @since 1.2 * @since 1.2
* @status updated to 1.4
*/ */
public class HashMap extends AbstractMap public class HashMap extends AbstractMap
implements Map, Cloneable, Serializable 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 * Default number of buckets. This is the value the JDK 1.3 uses. Some
* early documentation specified this value as 101. That is incorrect. * early documentation specified this value as 101. That is incorrect.
* Package visible for use by HashSet.
*/ */
static final int DEFAULT_CAPACITY = 11; static final int DEFAULT_CAPACITY = 11;
/** /**
* The default load factor; this is explicitly specified by the spec. * 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; 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. * 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 * The rounded product of the capacity and the load factor; when the number
* of elements exceeds the threshold, the HashMap calls <pre>rehash()</pre>. * of elements exceeds the threshold, the HashMap calls
* @serial * <code>rehash()</code>.
* @serial the threshold for rehashing
*/ */
int threshold; private int threshold;
/** /**
* Load factor of this HashMap: used in computing the 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; final float loadFactor;
/** /**
* Array containing the actual key-value mappings. * Array containing the actual key-value mappings.
* Package visible for use by nested and subclasses.
*/ */
transient HashEntry[] buckets; transient HashEntry[] buckets;
/** /**
* Counts the number of modifications this HashMap has undergone, used * Counts the number of modifications this HashMap has undergone, used
* by Iterators to know when to throw ConcurrentModificationExceptions. * by Iterators to know when to throw ConcurrentModificationExceptions.
* Package visible for use by nested and subclasses.
*/ */
transient int modCount; transient int modCount;
/** /**
* The size of this HashMap: denotes the number of key-value pairs. * The size of this HashMap: denotes the number of key-value pairs.
* Package visible for use by nested and subclasses.
*/ */
transient int size; transient int size;
/** /**
* Class to represent an entry in the hash table. Holds a single key-value * The cache for {@link #entrySet()}.
* pair. This is extended again in LinkedHashMap. See {@link clone()}
* for why this must be Cloneable.
*/ */
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; HashEntry next;
/** /**
@ -158,7 +171,8 @@ public class HashMap extends AbstractMap
/** /**
* Called when this entry is removed from the map. This version simply * Called when this entry is removed from the map. This version simply
* returns the value, but in LinkedHashMap, it must also do bookkeeping. * 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() Object cleanup()
{ {
@ -182,9 +196,8 @@ public class HashMap extends AbstractMap
* *
* Every element in Map m will be put into this new HashMap. * Every element in Map m will be put into this new HashMap.
* *
* @param m a Map whose key / value pairs will be put into * @param m a Map whose key / value pairs will be put into the new HashMap.
* the new HashMap. <b>NOTE: key / value pairs * <b>NOTE: key / value pairs are not cloned in this constructor.</b>
* are not cloned in this constructor.</b>
* @throws NullPointerException if m is null * @throws NullPointerException if m is null
*/ */
public HashMap(Map m) public HashMap(Map m)
@ -197,8 +210,8 @@ public class HashMap extends AbstractMap
* Construct a new HashMap with a specific inital capacity and * Construct a new HashMap with a specific inital capacity and
* default load factor of 0.75. * default load factor of 0.75.
* *
* @param initialCapacity the initial capacity of this HashMap (>=0) * @param initialCapacity the initial capacity of this HashMap (&gt;=0)
* @throws IllegalArgumentException if (initialCapacity < 0) * @throws IllegalArgumentException if (initialCapacity &lt; 0)
*/ */
public HashMap(int initialCapacity) 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. * Construct a new HashMap with a specific inital capacity and load factor.
* *
* @param initialCapacity the initial capacity (>=0) * @param initialCapacity the initial capacity (&gt;=0)
* @param loadFactor the load factor (>0, not NaN) * @param loadFactor the load factor (&gt; 0, not NaN)
* @throws IllegalArgumentException if (initialCapacity < 0) || * @throws IllegalArgumentException if (initialCapacity &lt; 0) ||
* ! (loadFactor > 0.0) * ! (loadFactor &gt; 0.0)
*/ */
public HashMap(int initialCapacity, float loadFactor) 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 * @return the size
*/ */
public int 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> * @return <code>size() == 0</code>
*/ */
public boolean isEmpty() public boolean isEmpty()
@ -246,52 +261,9 @@ public class HashMap extends AbstractMap
return size == 0; 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, * 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 * could also be null, you must use containsKey to see if this key
* actually maps to something. * actually maps to something.
* *
@ -306,13 +278,34 @@ public class HashMap extends AbstractMap
HashEntry e = buckets[idx]; HashEntry e = buckets[idx];
while (e != null) while (e != null)
{ {
if (key == null ? e.key == null : key.equals(e.key)) if (equals(key, e.key))
return e.value; return e.value;
e = e.next; e = e.next;
} }
return null; 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. * Puts the supplied value into the Map, mapped by the supplied key.
* The value may be retrieved by any object which <code>equals()</code> * 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) public Object put(Object key, Object value)
{ {
modCount++;
int idx = hash(key); int idx = hash(key);
HashEntry e = buckets[idx]; HashEntry e = buckets[idx];
while (e != null) 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. // Must use this method for necessary bookkeeping in LinkedHashMap.
return e.setValue(value); return e.setValue(value);
else else
@ -342,6 +334,7 @@ public class HashMap extends AbstractMap
} }
// At this point, we know we need to add a new entry. // At this point, we know we need to add a new entry.
modCount++;
if (++size > threshold) if (++size > threshold)
{ {
rehash(); rehash();
@ -354,59 +347,6 @@ public class HashMap extends AbstractMap
return null; 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 * 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 * already has a mapping for a key, the new mapping replaces the current
@ -434,14 +374,75 @@ 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). * Clears the Map so it has no keys. This is O(1).
*/ */
public void clear() public void clear()
{ {
modCount++; if (size != 0)
Arrays.fill(buckets, null); {
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;
} }
/** /**
@ -463,6 +464,8 @@ public class HashMap extends AbstractMap
} }
copy.buckets = new HashEntry[buckets.length]; copy.buckets = new HashEntry[buckets.length];
copy.putAllInternal(this); copy.putAllInternal(this);
// Clear the entry cache. AbstractMap.clone() does the others.
copy.entries = null;
return copy; return copy;
} }
@ -477,41 +480,43 @@ public class HashMap extends AbstractMap
*/ */
public Set keySet() public Set keySet()
{ {
// Create an AbstractSet with custom implementations of those methods that if (keys == null)
// can be overridden easily and efficiently. // Create an AbstractSet with custom implementations of those methods
return new AbstractSet() // that can be overridden easily and efficiently.
{ keys = new AbstractSet()
public int size()
{ {
return size; public int size()
} {
return size;
}
public Iterator iterator() public Iterator iterator()
{ {
// Cannot create the iterator directly, because of LinkedHashMap. // Cannot create the iterator directly, because of LinkedHashMap.
return HashMap.this.iterator(KEYS); return HashMap.this.iterator(KEYS);
} }
public void clear() public void clear()
{ {
HashMap.this.clear(); HashMap.this.clear();
} }
public boolean contains(Object o) public boolean contains(Object o)
{ {
return HashMap.this.containsKey(o); return containsKey(o);
} }
public boolean remove(Object o) public boolean remove(Object o)
{ {
// Test against the size of the HashMap to determine if anything // Test against the size of the HashMap to determine if anything
// really got removed. This is necessary because the return value of // really got removed. This is neccessary because the return value
// HashMap.remove() is ambiguous in the null case. // of HashMap.remove() is ambiguous in the null case.
int oldsize = size; int oldsize = size;
HashMap.this.remove(o); HashMap.this.remove(o);
return (oldsize != size); return oldsize != size;
} }
}; };
return keys;
} }
/** /**
@ -526,33 +531,34 @@ public class HashMap extends AbstractMap
*/ */
public Collection values() public Collection values()
{ {
// We don't bother overriding many of the optional methods, as doing so if (values == null)
// wouldn't provide any significant performance advantage. // We don't bother overriding many of the optional methods, as doing so
return new AbstractCollection() // wouldn't provide any significant performance advantage.
{ values = new AbstractCollection()
public int size()
{ {
return size; public int size()
} {
return size;
}
public Iterator iterator() public Iterator iterator()
{ {
// Cannot create the iterator directly, because of LinkedHashMap. // Cannot create the iterator directly, because of LinkedHashMap.
return HashMap.this.iterator(VALUES); return HashMap.this.iterator(VALUES);
} }
public void clear() public void clear()
{ {
HashMap.this.clear(); HashMap.this.clear();
} }
}; };
return values;
} }
/** /**
* Returns a "set view" of this HashMap's entries. The set is backed by * 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 * the HashMap, so changes in one show up in the other. The set supports
* element removal, but not element addition. * element removal, but not element addition.<p>
* <p>
* *
* Note that the iterators for all three views, from keySet(), entrySet(), * Note that the iterators for all three views, from keySet(), entrySet(),
* and values(), traverse the HashMap in the same sequence. * and values(), traverse the HashMap in the same sequence.
@ -564,53 +570,62 @@ public class HashMap extends AbstractMap
*/ */
public Set entrySet() public Set entrySet()
{ {
// Create an AbstractSet with custom implementations of those methods that if (entries == null)
// can be overridden easily and efficiently. // Create an AbstractSet with custom implementations of those methods
return new AbstractSet() // that can be overridden easily and efficiently.
{ entries = new AbstractSet()
public int size()
{ {
return size; public int size()
} {
return size;
}
public Iterator iterator() public Iterator iterator()
{ {
// Cannot create the iterator directly, because of LinkedHashMap. // Cannot create the iterator directly, because of LinkedHashMap.
return HashMap.this.iterator(ENTRIES); return HashMap.this.iterator(ENTRIES);
} }
public void clear() public void clear()
{ {
HashMap.this.clear(); HashMap.this.clear();
} }
public boolean contains(Object o) public boolean contains(Object o)
{ {
return getEntry(o) != null; return getEntry(o) != null;
} }
public boolean remove(Object o) public boolean remove(Object o)
{ {
HashEntry e = getEntry(o); HashEntry e = getEntry(o);
if (e != null) if (e != null)
{ {
HashMap.this.remove(e.key); HashMap.this.remove(e.key);
return true; return true;
} }
return false; 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 * @param key the key of the new Entry
* @return the bucket number * @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; 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 * 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 * 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. * Serializes this object to the given stream.
* *
@ -757,9 +789,6 @@ public class HashMap extends AbstractMap
// Read and use capacity. // Read and use capacity.
buckets = new HashEntry[s.readInt()]; buckets = new HashEntry[s.readInt()];
int len = s.readInt(); int len = s.readInt();
// Already happens automatically.
// size = 0;
// modCount = 0;
// Read and use key/value pairs. // Read and use key/value pairs.
for ( ; len > 0; len--) for ( ; len > 0; len--)
@ -773,29 +802,29 @@ public class HashMap extends AbstractMap
* *
* @author Jon Zeppieri * @author Jon Zeppieri
*/ */
class HashIterator implements Iterator private final class HashIterator implements Iterator
{ {
/** /**
* The type of this Iterator: {@link #KEYS}, {@link #VALUES}, * The type of this Iterator: {@link #KEYS}, {@link #VALUES},
* or {@link #ENTRIES}. * or {@link #ENTRIES}.
*/ */
final int type; private final int type;
/** /**
* The number of modifications to the backing HashMap that we know about. * 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(). */ /** The number of elements remaining to be returned by next(). */
int count = size; private int count = size;
/** Current index in the physical hash table. */ /** Current index in the physical hash table. */
int idx = buckets.length; private int idx = buckets.length;
/** The last Entry returned by a next() call. */ /** 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 * 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 * if we're iterating through a bucket that contains multiple linked
* entries. It is null if next() needs to find a new bucket. * 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. * Construct a new HashIterator with the supplied type.
@ -840,14 +869,14 @@ public class HashMap extends AbstractMap
last = e; last = e;
if (type == VALUES) if (type == VALUES)
return e.value; return e.value;
else if (type == KEYS) if (type == KEYS)
return e.key; return e.key;
return e; return e;
} }
/** /**
* Removes from the backing HashMap the last element which was fetched * 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 ConcurrentModificationException if the HashMap was modified
* @throws IllegalStateException if called when there is no last element * @throws IllegalStateException if called when there is no last element
*/ */
@ -859,8 +888,8 @@ public class HashMap extends AbstractMap
throw new IllegalStateException(); throw new IllegalStateException();
HashMap.this.remove(last.key); HashMap.this.remove(last.key);
knownMod++;
last = null; last = null;
knownMod++;
} }
} }
} }

View file

@ -1,5 +1,5 @@
/* HashSet.java -- a class providing a HashMap-backet Set /* HashSet.java -- a class providing a HashMap-backed Set
Copyright (C) 1998, 1999 Free Software Foundation, Inc. Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -33,87 +33,115 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
/** /**
* This class provides a HashMap-backed implementation of the * This class provides a HashMap-backed implementation of the Set interface.
* Set interface. * <p>
*
* 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.
* *
* Most operations are O(1), assuming no hash collisions. In the worst * 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>
* *
* @author Jon Zeppieri * 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 public class HashSet extends AbstractSet
implements Set, Cloneable, Serializable implements Set, Cloneable, Serializable
{ {
/** the HashMap which backs this Set */ /**
transient HashMap map; * Compatible with JDK 1.2.
static final long serialVersionUID = -5024744406713321676L; */
private static final long serialVersionUID = -5024744406713321676L;
/** /**
* construct a new, empty HashSet whose backing HashMap has the default * The HashMap which backs this Set.
* capacity and loadFacor */
private transient HashMap map;
/**
* Construct a new, empty HashSet whose backing HashMap has the default
* capacity (11) and loadFacor (0.75).
*/ */
public HashSet() public HashSet()
{ {
map = new HashMap(); this(HashMap.DEFAULT_CAPACITY, HashMap.DEFAULT_LOAD_FACTOR);
} }
/** /**
* construct a new, empty HashSet whose backing HashMap has the supplied * Construct a new, empty HashSet whose backing HashMap has the supplied
* capacity and the default load factor * capacity and the default load factor (0.75).
* *
* @param initialCapacity the initial capacity of the backing * @param initialCapacity the initial capacity of the backing HashMap
* HashMap * @throws IllegalArgumentException if the capacity is negative
*/ */
public HashSet(int initialCapacity) 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 * Construct a new, empty HashSet whose backing HashMap has the supplied
* capacity and load factor * capacity and load factor.
* *
* @param initialCapacity the initial capacity of the backing * @param initialCapacity the initial capacity of the backing HashMap
* HashMap * @param loadFactor the load factor 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) 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 * Construct a new HashSet with the same elements as are in the supplied
* collection (eliminating any duplicates, of course; the backing HashMap * collection (eliminating any duplicates, of course). The backing storage
* will have the default capacity and load factor * 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 * @param c a collection of initial set elements
* which this set will be initialized * @throws NullPointerException if c is null
*/ */
public HashSet(Collection c) public HashSet(Collection c)
{ {
map = new HashMap(); this(Math.max(2 * c.size(), HashMap.DEFAULT_CAPACITY));
addAll(c); addAll(c);
} }
/** /**
* adds the given Object to the set if it is not already in the Set, * Adds the given Object to the set if it is not already in the Set.
* returns true if teh element was added, false otherwise * This set permits a null element.
* *
* @param o the Object to add to this Set * @param o the Object to add to this Set
* @return true if the set did not already contain o
*/ */
public boolean add(Object 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() public void clear()
{ {
@ -121,53 +149,67 @@ public class HashSet extends AbstractSet
} }
/** /**
* returns a shallow copy of this Set (the Set itself is cloned; its * Returns a shallow copy of this Set. The Set itself is cloned; its
* elements are not) * elements are not.
*
* @return a shallow clone of the set
*/ */
public Object clone() public Object clone()
{ {
HashSet copy = null; HashSet copy = null;
try try
{ {
copy = (HashSet) super.clone(); copy = (HashSet) super.clone();
} }
catch (CloneNotSupportedException x) catch (CloneNotSupportedException x)
{ {
// Impossible to get here.
} }
copy.map = (HashMap) map.clone(); copy.map = (HashMap) map.clone();
return copy; 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) public boolean contains(Object o)
{ {
return map.containsKey(o); return map.containsKey(o);
} }
/** /**
* 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() public boolean isEmpty()
{ {
return map.isEmpty(); return map.size == 0;
} }
/** /**
* returns an Iterator over the elements of this Set; the Iterator allows * Returns an Iterator over the elements of this Set, which visits the
* removal of elements * 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() 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 * Removes the supplied Object from this Set if it is in the Set.
* true if an element was removed, false otherwise *
* @param o the object to remove
* @return true if an element was removed
*/ */
public boolean remove(Object o) 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() 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 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.writeInt(map.buckets.length);
s.writeFloat(map.loadFactor); s.writeFloat(map.loadFactor);
s.writeInt(map.size); s.writeInt(map.size);
@ -194,25 +260,23 @@ public class HashSet extends AbstractSet
s.writeObject(it.next()); s.writeObject(it.next());
} }
/** Deserialize this Object in a manner which is binary-compatible with /**
* the JDK */ * Deserializes this object from the given stream.
private void readObject(ObjectInputStream s) throws IOException, *
ClassNotFoundException * @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; s.defaultReadObject();
float loadFactor;
Object element;
capacity = s.readInt(); map = init(s.readInt(), s.readFloat());
loadFactor = s.readFloat(); for (int size = s.readInt(); size > 0; size--)
size = s.readInt(); map.put(s.readObject(), "");
map = new HashMap(capacity, loadFactor);
for (i = 0; i < size; i++)
{
element = s.readObject();
map.put(element, Boolean.TRUE);
}
} }
} }

View file

@ -66,7 +66,9 @@ import java.io.ObjectOutputStream;
* Unlike HashMap, Hashtable does not accept `null' as a key value. Also, * Unlike HashMap, Hashtable does not accept `null' as a key value. Also,
* all accesses are synchronized: in a single thread environment, this is * all accesses are synchronized: in a single thread environment, this is
* expensive, but in a multi-thread environment, this saves you the effort * 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> * <p>
* *
* The iterators are <i>fail-fast</i>, meaning that any structural * The iterators are <i>fail-fast</i>, meaning that any structural
@ -84,6 +86,7 @@ import java.io.ObjectOutputStream;
* @see IdentityHashMap * @see IdentityHashMap
* @see LinkedHashMap * @see LinkedHashMap
* @since 1.0 * @since 1.0
* @status updated to 1.4
*/ */
public class Hashtable extends Dictionary public class Hashtable extends Dictionary
implements Map, Cloneable, Serializable implements Map, Cloneable, Serializable
@ -93,6 +96,12 @@ public class Hashtable extends Dictionary
*/ */
private static final int DEFAULT_CAPACITY = 11; 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. * 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 * The rounded product of the capacity and the load factor; when the number
* of elements exceeds the threshold, the Hashtable calls * of elements exceeds the threshold, the Hashtable calls
* <pre>rehash()</pre>. * <code>rehash()</code>.
* @serial * @serial
*/ */
int threshold; private int threshold;
/** /**
* Load factor of this Hashtable: used in computing the threshold. * Load factor of this Hashtable: used in computing the threshold.
* @serial * @serial
*/ */
final float loadFactor; private final float loadFactor;
/** /**
* Array containing the actual key-value mappings. * Array containing the actual key-value mappings.
*/ */
// Package visible for use by nested classes.
transient HashEntry[] buckets; transient HashEntry[] buckets;
/** /**
* Counts the number of modifications this Hashtable has undergone, used * Counts the number of modifications this Hashtable has undergone, used
* by Iterators to know when to throw ConcurrentModificationExceptions. * by Iterators to know when to throw ConcurrentModificationExceptions.
*/ */
// Package visible for use by nested classes.
transient int modCount; transient int modCount;
/** /**
* The size of this Hashtable: denotes the number of key-value pairs. * The size of this Hashtable: denotes the number of key-value pairs.
*/ */
// Package visible for use by nested classes.
transient int size; 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 * 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 * pair. A Hashtable Entry is identical to a HashMap Entry, except that
* `null' is not allowed for keys and values. * `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. */ /** The next entry in the linked list. */
HashEntry next; HashEntry next;
@ -159,7 +186,7 @@ public class Hashtable extends Dictionary
* @return the prior value * @return the prior value
* @throws NullPointerException if <code>newVal</code> is null * @throws NullPointerException if <code>newVal</code> is null
*/ */
public final Object setValue(Object newVal) public Object setValue(Object newVal)
{ {
if (newVal == null) if (newVal == null)
throw new NullPointerException(); throw new NullPointerException();
@ -193,15 +220,15 @@ public class Hashtable extends Dictionary
public Hashtable(Map m) public Hashtable(Map m)
{ {
this(Math.max(m.size() * 2, DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR); 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 * Construct a new Hashtable with a specific inital capacity and
* default load factor of 0.75. * default load factor of 0.75.
* *
* @param initialCapacity the initial capacity of this Hashtable (>=0) * @param initialCapacity the initial capacity of this Hashtable (&gt;= 0)
* @throws IllegalArgumentException if (initialCapacity < 0) * @throws IllegalArgumentException if (initialCapacity &lt; 0)
*/ */
public Hashtable(int initialCapacity) public Hashtable(int initialCapacity)
{ {
@ -212,10 +239,10 @@ public class Hashtable extends Dictionary
* Construct a new Hashtable with a specific initial capacity and * Construct a new Hashtable with a specific initial capacity and
* load factor. * load factor.
* *
* @param initialCapacity the initial capacity (>=0) * @param initialCapacity the initial capacity (&gt;= 0)
* @param loadFactor the load factor (>0, not NaN) * @param loadFactor the load factor (&gt; 0, not NaN)
* @throws IllegalArgumentException if (initialCapacity < 0) || * @throws IllegalArgumentException if (initialCapacity &lt; 0) ||
* ! (loadFactor > 0.0) * ! (loadFactor &gt; 0.0)
*/ */
public Hashtable(int initialCapacity, float loadFactor) 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 * @return the keys
* @see #elements() * @see #elements()
* @see #keySet() * @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 * @return the values
* @see #keys() * @see #keys()
* @see #values() * @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>, * Returns true if this Hashtable contains a value <code>o</code>,
* such that <pre>o.equals(value)</pre>. This is the same as * such that <code>o.equals(value)</code>. This is the same as
* <code>containsValue()</code>, and is O(n). * <code>containsValue()</code>, and is O(n).
* <p> * <p>
* *
@ -284,22 +317,37 @@ public class Hashtable extends Dictionary
* *
* @param value the value to search for in this Hashtable * @param value the value to search for in this Hashtable
* @return true if at least one key maps to the value * @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 #containsValue(Object)
* @see #containsKey(Object) * @see #containsKey(Object)
*/ */
public synchronized boolean contains(Object value) public synchronized boolean contains(Object value)
{ {
// Check if value is null in case Hashtable is empty. // Check if value is null.
if (value == null) if (value == null)
throw new NullPointerException(); 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--) for (int i = buckets.length - 1; i >= 0; i--)
{ {
HashEntry e = buckets[i]; HashEntry e = buckets[i];
while (e != null) while (e != null)
{ {
if (value.equals(e.value)) if (AbstractCollection.equals(value, e.value))
return true; return true;
e = e.next; 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 * Returns true if the supplied object <code>equals()</code> a key
* <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
* in this Hashtable. * in this Hashtable.
* *
* @param key the key to search for 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, * 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 * @param key the key for which to fetch an associated value
* @return what the key maps to, if present * @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) public synchronized Object put(Object key, Object value)
{ {
modCount++;
int idx = hash(key); int idx = hash(key);
HashEntry e = buckets[idx]; 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. // At this point, we know we need to add a new entry.
modCount++;
if (++size > threshold) if (++size > threshold)
{ {
rehash(); rehash();
@ -425,15 +456,18 @@ public class Hashtable extends Dictionary
/** /**
* Removes from the table and returns the value which is mapped by the * 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 * 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 * @param key the key used to locate the value to remove
* @return whatever the key mapped to, if present * @return whatever the key mapped to, if present
* @throws NullPointerException if key is null
*/ */
public synchronized Object remove(Object key) public synchronized Object remove(Object key)
{ {
modCount++; if (key == null)
return null;
int idx = hash(key); int idx = hash(key);
HashEntry e = buckets[idx]; HashEntry e = buckets[idx];
HashEntry last = null; HashEntry last = null;
@ -442,6 +476,7 @@ public class Hashtable extends Dictionary
{ {
if (key.equals(e.key)) if (key.equals(e.key))
{ {
modCount++;
if (last == null) if (last == null)
buckets[idx] = e.next; buckets[idx] = e.next;
else else
@ -488,9 +523,12 @@ public class Hashtable extends Dictionary
*/ */
public synchronized void clear() public synchronized void clear()
{ {
modCount++; if (size > 0)
Arrays.fill(buckets, null); {
size = 0; modCount++;
Arrays.fill(buckets, null);
size = 0;
}
} }
/** /**
@ -511,36 +549,18 @@ public class Hashtable extends Dictionary
// This is impossible. // This is impossible.
} }
copy.buckets = new HashEntry[buckets.length]; copy.buckets = new HashEntry[buckets.length];
copy.putAllInternal(this);
for (int i = buckets.length - 1; i >= 0; i--) // Clear the caches.
{ copy.keys = null;
HashEntry e = buckets[i]; copy.values = null;
HashEntry last = null; copy.entries = 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;
}
}
return copy; return copy;
} }
/** /**
* Converts this Hashtable to a String, surrounded by braces (<pre>'{'</pre> * Converts this Hashtable to a String, surrounded by braces, and with
* and <pre>'}'</pre>), key/value pairs listed with an equals sign between, * key/value pairs listed with an equals sign between, separated by a
* (<pre>'='</pre>), and pairs separated by comma and space * comma and space. For example, <code>"{a=1, b=2}"</code>.<p>
* (<pre>", "</pre>).
* <p>
* *
* NOTE: if the <code>toString()</code> method of any key or value * NOTE: if the <code>toString()</code> method of any key or value
* throws an exception, this will fail for the same reason. * 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() // Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the // would repeatedly re-lock/release the monitor, we directly use the
// unsynchronized HashIterator instead. // unsynchronized HashIterator instead.
Iterator entries = new HashIterator(HashIterator.ENTRIES); Iterator entries = new HashIterator(ENTRIES);
StringBuffer r = new StringBuffer("{"); StringBuffer r = new StringBuffer("{");
for (int pos = size; pos > 0; pos--) 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 * 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 * the hashtable, so changes in one show up in the other. The set supports
* element removal, but not element addition. The set is properly * element removal, but not element addition. The set is properly
* synchronized on the original hashtable. The set will throw a * synchronized on the original hashtable. Sun has not documented the
* {@link NullPointerException} if null is passed to <code>contains</code>, * proper interaction of null with this set, but has inconsistent behavior
* <code>remove</code>, or related methods. * 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 * @return a set view of the keys
* @see #values() * @see #values()
@ -579,50 +601,56 @@ public class Hashtable extends Dictionary
*/ */
public Set keySet() public Set keySet()
{ {
// Create a synchronized AbstractSet with custom implementations of those if (keys == null)
// methods that can be overridden easily and efficiently.
Set r = new AbstractSet()
{
public int size()
{ {
return size; // Create a synchronized AbstractSet with custom implementations of
} // those methods that can be overridden easily and efficiently.
Set r = new AbstractSet()
{
public int size()
{
return size;
}
public Iterator iterator() public Iterator iterator()
{ {
return new HashIterator(HashIterator.KEYS); return new HashIterator(KEYS);
} }
public void clear() public void clear()
{ {
Hashtable.this.clear(); Hashtable.this.clear();
} }
public boolean contains(Object o) public boolean contains(Object o)
{ {
return Hashtable.this.containsKey(o); if (o == null)
} return false;
return containsKey(o);
}
public boolean remove(Object 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
keys = new Collections.SynchronizedSet(this, r);
} }
}; return keys;
// We must specify the correct object to synchronize upon, hence the
// use of a non-public API
return new Collections.SynchronizedSet(this, r);
} }
/** /**
* Returns a "collection view" (or "bag view") of this Hashtable's values. * 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 * The collection is backed by the hashtable, so changes in one show up
* in the other. The collection supports element removal, but not element * in the other. The collection supports element removal, but not element
* addition. The collection is properly synchronized on the original * addition. The collection is properly synchronized on the original
* hashtable. The collection will throw a {@link NullPointerException} * hashtable. Sun has not documented the proper interaction of null with
* if null is passed to <code>contains</code> or related methods, but not * this set, but has inconsistent behavior in the JDK. Therefore, in this
* if passed to <code>remove</code> or related methods. * 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 * @return a bag view of the values
* @see #keySet() * @see #keySet()
@ -631,46 +659,45 @@ public class Hashtable extends Dictionary
*/ */
public Collection values() public Collection values()
{ {
// We don't bother overriding many of the optional methods, as doing so if (values == null)
// wouldn't provide any significant performance advantage.
Collection r = new AbstractCollection()
{
public int size()
{ {
return size; // We don't bother overriding many of the optional methods, as doing so
} // wouldn't provide any significant performance advantage.
Collection r = new AbstractCollection()
{
public int size()
{
return size;
}
public Iterator iterator() public Iterator iterator()
{ {
return new HashIterator(HashIterator.VALUES); return new HashIterator(VALUES);
} }
public void clear() public void clear()
{ {
Hashtable.this.clear(); Hashtable.this.clear();
}
};
// We must specify the correct object to synchronize upon, hence the
// use of a non-public API
values = new Collections.SynchronizedCollection(this, r);
} }
return values;
// 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);
} }
/** /**
* Returns a "set view" of this Hashtable's entries. The set is backed by * 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 * the hashtable, so changes in one show up in the other. The set supports
* element removal, but not element addition. The set is properly * element removal, but not element addition. The set is properly
* synchronized on the original hashtable. The set will throw a * synchronized on the original hashtable. Sun has not documented the
* {@link NullPointerException} if the Map.Entry passed to * proper interaction of null with this set, but has inconsistent behavior
* <code>contains</code>, <code>remove</code>, or related methods returns * in the JDK. Therefore, in this implementation, contains, remove,
* null for <code>getKey</code>, but not if the Map.Entry is null or * containsAll, retainAll, removeAll, and equals just ignore a null entry,
* returns null for <code>getValue</code>. * or an entry with a null key or value, rather than throwing a
* {@link NullPointerException}. However, calling entry.setValue(null)
* will fail.
* <p> * <p>
* *
* Note that the iterators for all three views, from keySet(), entrySet(), * Note that the iterators for all three views, from keySet(), entrySet(),
@ -684,49 +711,52 @@ public class Hashtable extends Dictionary
*/ */
public Set entrySet() public Set entrySet()
{ {
// Create an AbstractSet with custom implementations of those methods that if (entries == null)
// can be overridden easily and efficiently.
Set r = new AbstractSet()
{
public int size()
{ {
return size; // Create an AbstractSet with custom implementations of those methods
} // that can be overridden easily and efficiently.
Set r = new AbstractSet()
public Iterator iterator() {
{ public int size()
return new HashIterator(HashIterator.ENTRIES);
}
public void clear()
{
Hashtable.this.clear();
}
public boolean contains(Object o)
{
return getEntry(o) != null;
}
public boolean remove(Object o)
{
HashEntry e = getEntry(o);
if (e != null)
{ {
Hashtable.this.remove(e.key); return size;
return true;
} }
return false;
}
};
// We must specify the correct object to synchronize upon, hence the public Iterator iterator()
// use of a non-public API {
return new Collections.SynchronizedSet(this, r); return new HashIterator(ENTRIES);
}
public void clear()
{
Hashtable.this.clear();
}
public boolean contains(Object o)
{
return getEntry(o) != null;
}
public boolean remove(Object o)
{
HashEntry e = getEntry(o);
if (e != null)
{
Hashtable.this.remove(e.key);
return true;
}
return false;
}
};
// We must specify the correct object to synchronize upon, hence the
// use of a non-public API
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: * As specified by Map, this is:
* <pre> * <pre>
* (o instanceof Map) && entrySet().equals(((Map) o).entrySet()); * (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() // Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the // would repeatedly re-lock/release the monitor, we directly use the
// unsynchronized HashIterator instead. // unsynchronized HashIterator instead.
Iterator itr = new HashIterator(HashIterator.ENTRIES); Iterator itr = new HashIterator(ENTRIES);
int hashcode = 0; int hashcode = 0;
for (int pos = size; pos > 0; pos--) for (int pos = size; pos > 0; pos--)
hashcode += itr.next().hashCode(); hashcode += itr.next().hashCode();
@ -782,29 +812,55 @@ public class Hashtable extends Dictionary
/** /**
* Helper method for entrySet(), which matches both key and value * Helper method for entrySet(), which matches both key and value
* simultaneously. * simultaneously. Ignores null, as mentioned in entrySet().
* *
* @param o the entry to match * @param o the entry to match
* @return the matching entry, if found, or null * @return the matching entry, if found, or null
* @throws NullPointerException if me.getKey() returns null
* @see #entrySet() * @see #entrySet()
*/ */
private HashEntry getEntry(Object o) private HashEntry getEntry(Object o)
{ {
if (!(o instanceof Map.Entry)) if (! (o instanceof Map.Entry))
return null; return null;
Map.Entry me = (Map.Entry) o; Object key = ((Map.Entry) o).getKey();
int idx = hash(me.getKey()); if (key == null)
return null;
int idx = hash(key);
HashEntry e = buckets[idx]; HashEntry e = buckets[idx];
while (e != null) while (e != null)
{ {
if (e.equals(me)) if (o.equals(e))
return e; return e;
e = e.next; e = e.next;
} }
return null; 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 * 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 * indices; this is called when the addition of a new value would cause
@ -813,7 +869,8 @@ public class Hashtable extends Dictionary
* <p> * <p>
* *
* This is not specified, but the new size is twice the current size plus * 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() protected void rehash()
{ {
@ -854,8 +911,8 @@ public class Hashtable extends Dictionary
* *
* @param s the stream to write to * @param s the stream to write to
* @throws IOException if the underlying stream fails * @throws IOException if the underlying stream fails
* @serialData the <i>capacity</i>(int) that is the length of the * @serialData the <i>capacity</i> (int) that is the length of the
* bucket array, the <i>size</i>(int) of the hash map * bucket array, the <i>size</i> (int) of the hash map
* are emitted first. They are followed by size entries, * are emitted first. They are followed by size entries,
* each consisting of a key (Object) and a value (Object). * each consisting of a key (Object) and a value (Object).
*/ */
@ -870,7 +927,7 @@ public class Hashtable extends Dictionary
// Since we are already synchronized, and entrySet().iterator() // Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the // would repeatedly re-lock/release the monitor, we directly use the
// unsynchronized HashIterator instead. // unsynchronized HashIterator instead.
Iterator it = new HashIterator(HashIterator.ENTRIES); Iterator it = new HashIterator(ENTRIES);
while (it.hasNext()) while (it.hasNext())
{ {
HashEntry entry = (HashEntry) it.next(); HashEntry entry = (HashEntry) it.next();
@ -885,8 +942,8 @@ public class Hashtable extends Dictionary
* @param s the stream to read from * @param s the stream to read from
* @throws ClassNotFoundException if the underlying stream fails * @throws ClassNotFoundException if the underlying stream fails
* @throws IOException if the underlying stream fails * @throws IOException if the underlying stream fails
* @serialData the <i>capacity</i>(int) that is the length of the * @serialData the <i>capacity</i> (int) that is the length of the
* bucket array, the <i>size</i>(int) of the hash map * bucket array, the <i>size</i> (int) of the hash map
* are emitted first. They are followed by size entries, * are emitted first. They are followed by size entries,
* each consisting of a key (Object) and a value (Object). * each consisting of a key (Object) and a value (Object).
*/ */
@ -901,7 +958,8 @@ public class Hashtable extends Dictionary
int len = s.readInt(); int len = s.readInt();
// Read and use key/value pairs. // 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()); put(s.readObject(), s.readObject());
} }
@ -916,13 +974,8 @@ public class Hashtable extends Dictionary
* *
* @author Jon Zeppieri * @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}, * The type of this Iterator: {@link #KEYS}, {@link #VALUES},
* or {@link #ENTRIES}. * or {@link #ENTRIES}.
@ -988,14 +1041,14 @@ public class Hashtable extends Dictionary
last = e; last = e;
if (type == VALUES) if (type == VALUES)
return e.value; return e.value;
else if (type == KEYS) if (type == KEYS)
return e.key; return e.key;
return e; return e;
} }
/** /**
* Removes from the backing Hashtable the last element which was fetched * 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 ConcurrentModificationException if the hashtable was modified
* @throws IllegalStateException if called when there is no last element * @throws IllegalStateException if called when there is no last element
*/ */
@ -1007,10 +1060,10 @@ public class Hashtable extends Dictionary
throw new IllegalStateException(); throw new IllegalStateException();
Hashtable.this.remove(last.key); Hashtable.this.remove(last.key);
knownMod++;
last = null; last = null;
knownMod++;
} }
} } // class HashIterator
/** /**
@ -1027,21 +1080,21 @@ public class Hashtable extends Dictionary
* *
* @author Jon Zeppieri * @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}. * 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. */ /** Current index in the physical hash table. */
int idx; int idx = buckets.length;
/** The last Entry returned by nextEntry(). */ /**
HashEntry last; * Entry which will be returned by the next nextElement() call. It is
/** Entry which will be returned by the next nextElement() call. */ * set if we are iterating through a bucket with multiple entries, or null
* if we must look in the next bucket.
*/
HashEntry next; HashEntry next;
/** /**
@ -1051,25 +1104,6 @@ public class Hashtable extends Dictionary
Enumerator(int type) Enumerator(int type)
{ {
this.type = 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() public boolean hasMoreElements()
{ {
if (next != null) return count > 0;
return true;
next = nextEntry();
return next != null;
} }
/** /**
@ -1091,19 +1122,16 @@ public class Hashtable extends Dictionary
*/ */
public Object nextElement() public Object nextElement()
{ {
HashEntry e; if (count == 0)
if (next != null)
{
e = next;
next = null;
}
else
e = nextEntry();
if (e == null)
throw new NoSuchElementException("Hashtable Enumerator"); throw new NoSuchElementException("Hashtable Enumerator");
if (type == VALUES) count--;
return e.value; HashEntry e = next;
return e.key;
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

View file

@ -28,11 +28,6 @@ executable file might be covered by the GNU General Public License. */
package java.util; 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 * This class provides a hashtable-backed implementation of the
* Map interface, with predictable traversal order. * Map interface, with predictable traversal order.
@ -89,6 +84,7 @@ import java.io.ObjectOutputStream;
* @see TreeMap * @see TreeMap
* @see Hashtable * @see Hashtable
* @since 1.4 * @since 1.4
* @status updated to 1.4
*/ */
public class LinkedHashMap extends HashMap public class LinkedHashMap extends HashMap
{ {
@ -218,8 +214,8 @@ public class LinkedHashMap extends HashMap
* Construct a new insertion-ordered LinkedHashMap with a specific * Construct a new insertion-ordered LinkedHashMap with a specific
* inital capacity and default load factor of 0.75. * inital capacity and default load factor of 0.75.
* *
* @param initialCapacity the initial capacity of this HashMap (>=0) * @param initialCapacity the initial capacity of this HashMap (&gt;= 0)
* @throws IllegalArgumentException if (initialCapacity < 0) * @throws IllegalArgumentException if (initialCapacity &lt; 0)
*/ */
public LinkedHashMap(int initialCapacity) public LinkedHashMap(int initialCapacity)
{ {
@ -231,10 +227,10 @@ public class LinkedHashMap extends HashMap
* Construct a new insertion-orderd LinkedHashMap with a specific * Construct a new insertion-orderd LinkedHashMap with a specific
* inital capacity and load factor. * inital capacity and load factor.
* *
* @param initialCapacity the initial capacity (>=0) * @param initialCapacity the initial capacity (&gt;= 0)
* @param loadFactor the load factor (>0, not NaN) * @param loadFactor the load factor (&gt; 0, not NaN)
* @throws IllegalArgumentException if (initialCapacity < 0) || * @throws IllegalArgumentException if (initialCapacity &lt; 0) ||
* ! (loadFactor > 0.0) * ! (loadFactor &gt; 0.0)
*/ */
public LinkedHashMap(int initialCapacity, float loadFactor) public LinkedHashMap(int initialCapacity, float loadFactor)
{ {
@ -281,7 +277,7 @@ public class LinkedHashMap extends HashMap
LinkedHashEntry e = head; LinkedHashEntry e = head;
while (e != null) while (e != null)
{ {
if (value == null ? e.value == null : value.equals(e.value)) if (equals(value, e.value))
return true; return true;
e = e.succ; e = e.succ;
} }
@ -307,7 +303,7 @@ public class LinkedHashMap extends HashMap
HashEntry e = buckets[idx]; HashEntry e = buckets[idx];
while (e != null) while (e != null)
{ {
if (key == null ? e.key == null : key.equals(e.key)) if (equals(key, e.key))
{ {
if (accessOrder) if (accessOrder)
{ {
@ -376,13 +372,14 @@ public class LinkedHashMap extends HashMap
return false; 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). * new Entry, followed by performing bookkeeping (like removeEldestEntry).
* *
* @param key the key of the new Entry * @param key the key of the new Entry
* @param value the value * @param value the value
* @param idx the index in buckets where the new Entry belongs * @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 #put(Object, Object)
* @see #removeEldestEntry(Map.Entry) * @see #removeEldestEntry(Map.Entry)
*/ */
@ -397,6 +394,11 @@ public class LinkedHashMap extends HashMap
remove(head); 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) void putAllInternal(Map m)
{ {
head = null; head = null;
@ -466,8 +468,8 @@ public class LinkedHashMap extends HashMap
throw new IllegalStateException(); throw new IllegalStateException();
LinkedHashMap.this.remove(last.key); LinkedHashMap.this.remove(last.key);
knownMod++;
last = null; last = null;
knownMod++;
} }
}; };
} }

View 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);
}
}

File diff suppressed because it is too large Load diff

View file

@ -190,7 +190,7 @@ public interface List extends Collection
* @see Object#equals(Object) * @see Object#equals(Object)
* @see #hashCode() * @see #hashCode()
*/ */
boolean equals(Object o); /* boolean equals(Object o);*/
/** /**
* Get the element at a given index in this list. * Get the element at a given index in this list.
@ -288,7 +288,7 @@ public interface List extends Collection
Object remove(int index); 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 * operation). That is, remove the first element e such that
* <code>o == null ? e == null : o.equals(e)</code>. * <code>o == null ? e == null : o.equals(e)</code>.
* *

View file

@ -32,24 +32,30 @@ package java.util;
* "The Java Language Specification", ISBN 0-201-63451-1 * "The Java Language Specification", ISBN 0-201-63451-1
* plus online API docs for JDK 1.2 beta from http://www.javasoft.com. * plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
* Status: Believed complete and correct * Status: Believed complete and correct
*/
/** /**
* Stack provides a Last In First Out (LIFO) data type, commonly known * Stack provides a Last In First Out (LIFO) data type, commonly known
* as a Stack. * as a Stack. Stack itself extends Vector and provides the additional
* * methods for stack manipulation (push, pop, peek). You can also seek for
* Stack itself extends Vector and provides the additional methods * the 1-based position of an element on the stack.
* for stack manipulation (push, pop, peek).
* *
* @author Warren Levy <warrenl@cygnus.com> * @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 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 // but have used Vector fields directly for efficiency (i.e. this
// often reduces out duplicate bounds checking). // often reduces out duplicate bounds checking).
/**
* Compatible with JDK 1.0+.
*/
private static final long serialVersionUID = 1224463164541339165L; private static final long serialVersionUID = 1224463164541339165L;
/** /**
@ -57,16 +63,15 @@ public class Stack extends Vector
*/ */
public Stack() public Stack()
{ {
super();
} }
/** /**
* Pushes an Object onto the top of the stack. This method is effectively * 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 * @param item the Object to push onto the stack
* @returns the Object pushed onto the stack * @return the Object pushed onto the stack
* @see java.util.Vector#addElement(java.util.Object) * @see Vector#addElement(Object)
*/ */
public Object push(Object item) 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 * 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() public synchronized Object pop()
{ {
if (elementCount == 0) if (elementCount == 0)
throw new EmptyStackException(); throw new EmptyStackException();
modCount++;
Object obj = elementData[--elementCount]; 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; elementData[elementCount] = null;
return obj; 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() 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; return elementCount == 0;
} }
@ -122,18 +130,18 @@ public class Stack extends Vector
/** /**
* Returns the position of an Object on the stack, with the top * Returns the position of an Object on the stack, with the top
* most Object being at position 1, and each Object deeper in the * 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 * @param o The object to search for
* @returns The 1 based depth of the Object, or -1 if the Object * @return The 1 based depth of the Object, or -1 if the Object
* is not on the stack. * is not on the stack
*/ */
public synchronized int search(Object o) public synchronized int search(Object o)
{ {
for (int i = elementCount-1; i >=0; --i) int i = elementCount;
if (elementData[i].equals(o)) while (--i >= 0)
if (equals(o, elementData[i]))
return elementCount - i; return elementCount - i;
return -1; return -1;
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -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. Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath. This file is part of GNU Classpath.
@ -33,54 +33,91 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
/** /**
* This class provides a TreeMap-backed implementation of the * This class provides a TreeMap-backed implementation of the SortedSet
* SortedSet interface. * 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 * Most operations are O(log n), but there is so much overhead that this
* maps to a static token, denoting that the key does, in fact, exist. * 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 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 public class TreeSet extends AbstractSet
implements SortedSet, Cloneable, Serializable implements SortedSet, Cloneable, Serializable
{ {
/** The TreeMap which backs this Set */ /**
transient SortedMap map; * Compatible with JDK 1.2.
*/
static final long serialVersionUID = -2479143000061671589L; private static final long serialVersionUID = -2479143000061671589L;
/** /**
* Construct a new TreeSet whose backing TreeMap using the "natural" * The SortedMap which backs this Set.
* ordering of keys. */
// 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. Elements that are not mutually comparable will cause
* ClassCastExceptions down the road.
*
* @see Comparable
*/ */
public TreeSet() public TreeSet()
{ {
map = new TreeMap(); map = new TreeMap();
} }
/** /**
* Construct a new TreeSet whose backing TreeMap uses the supplied * 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) public TreeSet(Comparator comparator)
{ {
map = new TreeMap(comparator); map = new TreeMap(comparator);
} }
/** /**
* Construct a new TreeSet whose backing TreeMap uses the "natural" * Construct a new TreeSet whose backing TreeMap uses the "natural"
* orering of the keys and which contains all of the elements in the * 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 * 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) public TreeSet(Collection collection)
{ {
@ -93,54 +130,57 @@ public class TreeSet extends AbstractSet
* SortedSet and containing all of the elements in the supplied SortedSet. * SortedSet and containing all of the elements in the supplied SortedSet.
* This constructor runs in linear time. * This constructor runs in linear time.
* *
* @param sortedSet the new TreeSet will use this SortedSet's * @param sortedSet the new TreeSet will use this SortedSet's comparator
* comparator and will initialize itself * and will initialize itself with all its elements
* with all of the elements in this SortedSet * @throws NullPointerException if sortedSet is null
*/ */
public TreeSet(SortedSet sortedSet) public TreeSet(SortedSet sortedSet)
{ {
TreeMap map = new TreeMap(sortedSet.comparator()); map = new TreeMap(sortedSet.comparator());
int i = 0;
Iterator itr = sortedSet.iterator(); Iterator itr = sortedSet.iterator();
map.putKeysLinear(itr, sortedSet.size()); ((TreeMap) map).putKeysLinear(itr, sortedSet.size());
this.map = map;
} }
/* This private constructor is used to implement the subSet() calls around /**
a backing TreeMap.SubMap. */ * This private constructor is used to implement the subSet() calls around
TreeSet(SortedMap backingMap) * a backing TreeMap.SubMap.
*
* @param backingMap the submap
*/
private TreeSet(SortedMap backingMap)
{ {
map = backingMap; map = backingMap;
} }
/** /**
* Adds the spplied Object to the Set if it is not already in the Set; * 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 * @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) 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. * Adds all of the elements in the supplied Collection to this TreeSet.
* *
* @param c All of the elements in this Collection * @param c The collection to add
* will be added to the Set. * @return true if the Set is altered, false otherwise
* * @throws NullPointerException if c is null
* @return true if the Set is altered, false otherwise * @throws ClassCastException if an element in c cannot be compared with
* objects already in the set
*/ */
public boolean addAll(Collection c) public boolean addAll(Collection c)
{ {
boolean result = false; boolean result = false;
int size = c.size(); int pos = c.size();
Iterator itr = c.iterator(); Iterator itr = c.iterator();
while (--pos >= 0)
for (int i = 0; i < size; i++) result |= (map.put(itr.next(), "") == null);
result |= (map.put(itr.next(), Boolean.TRUE) == null);
return result; return result;
} }
@ -152,94 +192,75 @@ public class TreeSet extends AbstractSet
map.clear(); 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() public Object clone()
{ {
TreeSet copy = null; TreeSet copy = null;
try try
{ {
copy = (TreeSet) super.clone(); 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) catch (CloneNotSupportedException x)
{ {
// Impossible result.
} }
copy.map = (SortedMap) ((TreeMap) map).clone();
return copy; 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() public Comparator comparator()
{ {
return map.comparator(); return map.comparator();
} }
/** /**
* Returns true if this Set contains the supplied Object, * Returns true if this Set contains the supplied Object, false otherwise.
* false otherwise
* *
* @param oObject the Object whose existence in the Set is * @param obj the Object to check for
* being tested * @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) public boolean contains(Object obj)
{ {
return map.containsKey(obj); return map.containsKey(obj);
} }
/** Returns true if this Set has size 0, false otherwise */ /**
public boolean isEmpty() * Returns the first (by order) element in this Set.
{
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.
* *
* @param obj the Object we are attempting to remove * @return the first element
* from this Set * @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() public Object first()
{ {
return map.firstKey(); 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 * Returns a view of this Set including all elements less than
* [oFromElement, oToElement). * <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 * @param to the (exclusive) cutoff point
* elements greater than or equal to this element * @return a view of the set less than the cutoff
* @param to the resultant view will contain all * @throws ClassCastException if <code>to</code> is not compatible with
* elements less than this element * the comparator (or is not Comparable, for natural ordering)
*/ * @throws NullPointerException if to is null, but the comparator does not
public SortedSet subSet(Object from, Object to) * tolerate null elements
{
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
*/ */
public SortedSet headSet(Object to) 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 * Returns true if this Set has size 0, false otherwise.
* equal to oFromElement.
* *
* @param from the resultant view will contain all * @return true if the set is empty
* elements greater than or equal to this element */
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) public SortedSet tailSet(Object from)
{ {
return new TreeSet(map.tailMap(from)); return new TreeSet(map.tailMap(from));
} }
/** Returns in Iterator over the elements in this TreeSet */ /**
public Iterator iterator() * Serializes this object to the given stream.
{ *
return map.keySet().iterator(); * @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
private void writeObject(ObjectOutputStream out) throws IOException * (int), the the elements in sorted order (Object)
*/
private void writeObject(ObjectOutputStream s) throws IOException
{ {
s.defaultWriteObject();
Iterator itr = map.keySet().iterator(); Iterator itr = map.keySet().iterator();
int size = map.size(); int pos = map.size();
s.writeObject(map.comparator());
out.writeObject(map.comparator()); s.writeInt(pos);
out.writeInt(size); while (--pos >= 0)
s.writeObject(itr.next());
for (int i = 0; i < size; i++)
out.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 throws IOException, ClassNotFoundException
{ {
Comparator comparator = (Comparator) in.readObject(); s.defaultReadObject();
int size = in.readInt(); Comparator comparator = (Comparator) s.readObject();
TreeMap map = new TreeMap(comparator); int size = s.readInt();
map.putFromObjStream(in, size, false); map = new TreeMap(comparator);
this.map = map; ((TreeMap) map).putFromObjStream(s, size, false);
} }
} }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff