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>
* libjava/prims.cc: Some old cleanups. The collector now
handles test for out of memory.

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* AbstractCollection.java -- Abstract implementation of most of Collection
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -42,74 +42,116 @@ import java.lang.reflect.Array;
* backing data structure allows for a more efficient implementation. The
* precise implementation used by AbstractCollection is documented, so that
* subclasses can tell which methods could be implemented more efficiently.
* <p>
*
* The programmer should provide a no-argument constructor, and one that
* accepts another Collection, as recommended by the Collection interface.
* Unfortunately, there is no way to enforce this in Java.
*
* @author Original author unknown
* @author Bryce McKinlay
* @author Eric Blake <ebb9@email.byu.edu>
* @see Collection
* @see AbstractSet
* @see AbstractList
* @since 1.2
* @status updated to 1.4
*/
public abstract class AbstractCollection implements Collection
{
/**
* The main constructor, for use by subclasses.
*/
protected AbstractCollection()
{
}
/**
* Return an Iterator over this collection. The iterator must provide the
* hasNext and next methods and should in addition provide remove if the
* collection is modifiable.
*
* @return an iterator
*/
public abstract Iterator iterator();
/**
* Return the number of elements in this collection.
* Return the number of elements in this collection. If there are more than
* Integer.MAX_VALUE elements, return Integer.MAX_VALUE.
*
* @return the size
*/
public abstract int size();
/**
* Add an object to the collection. This implementation always throws an
* UnsupportedOperationException - it should be overridden if the collection
* is to be modifiable.
* Add an object to the collection (optional operation). This implementation
* always throws an UnsupportedOperationException - it should be
* overridden if the collection is to be modifiable. If the collection
* does not accept duplicates, simply return false. Collections may specify
* limitations on what may be added.
*
* @param o the object to add
* @return true if the add operation caused the Collection to change
* @exception UnsupportedOperationException if the add operation is not
* @throws UnsupportedOperationException if the add operation is not
* supported on this collection
* @throws NullPointerException if the collection does not support null
* @throws ClassCastException if the object is of the wrong type
* @throws IllegalArgumentException if some aspect of the object prevents
* it from being added
*/
public boolean add(Object o)
{
throw new java.lang.UnsupportedOperationException();
throw new UnsupportedOperationException();
}
/**
* Add all the elements of a given collection to this collection. This
* implementation obtains an Iterator over the given collection and iterates
* over it, adding each element with the add(Object) method (thus this method
* will fail with an UnsupportedOperationException if the add method does).
* Add all the elements of a given collection to this collection (optional
* operation). This implementation obtains an Iterator over the given
* collection and iterates over it, adding each element with the
* add(Object) method (thus this method will fail with an
* UnsupportedOperationException if the add method does). The behavior is
* unspecified if the specified collection is modified during the iteration,
* including the special case of trying addAll(this) on a non-empty
* collection.
*
* @param c the collection to add the elements of to this collection
* @return true if the add operation caused the Collection to change
* @exception UnsupportedOperationException if the add operation is not
* @throws UnsupportedOperationException if the add operation is not
* supported on this collection
* @throws NullPointerException if this collection does not support null,
* or if the specified collection is null
* @throws ClassCastException if an object in c is of the wrong type
* @throws IllegalArgumentException if some aspect of an object in c prevents
* it from being added
* @see #add(Object)
*/
public boolean addAll(Collection c)
{
Iterator itr = c.iterator();
int size = c.size();
boolean modified = false;
for (int pos = 0; pos < size; pos++)
{
int pos = c.size();
while (--pos >= 0)
modified |= add(itr.next());
}
return modified;
}
/**
* Remove all elements from the collection. This implementation obtains an
* iterator over the collection and calls next and remove on it repeatedly
* (thus this method will fail with an UnsupportedOperationException if the
* Iterator's remove method does) until there are no more elements to remove.
* Remove all elements from the collection (optional operation). This
* implementation obtains an iterator over the collection and calls next
* and remove on it repeatedly (thus this method will fail with an
* UnsupportedOperationException if the Iterator's remove method does)
* until there are no more elements to remove.
* Many implementations will have a faster way of doing this.
*
* @exception UnsupportedOperationException if the Iterator returned by
* @throws UnsupportedOperationException if the Iterator returned by
* iterator does not provide an implementation of remove
* @see Iterator#remove()
*/
public void clear()
{
Iterator itr = iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
int pos = size();
while (--pos >= 0)
{
itr.next();
itr.remove();
@ -130,12 +172,10 @@ public abstract class AbstractCollection implements Collection
public boolean contains(Object o)
{
Iterator itr = iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
{
if (o == null ? itr.next() == null : o.equals(itr.next()))
int pos = size();
while (--pos >= 0)
if (equals(o, itr.next()))
return true;
}
return false;
}
@ -148,16 +188,16 @@ public abstract class AbstractCollection implements Collection
* @param c the collection to test against
* @return true if this collection contains all the elements in the given
* collection
* @throws NullPointerException if the given collection is null
* @see #contains(Object)
*/
public boolean containsAll(Collection c)
{
Iterator itr = c.iterator();
int size = c.size();
for (int pos = 0; pos < size; pos++)
{
int pos = c.size();
while (--pos >= 0)
if (!contains(itr.next()))
return false;
}
return true;
}
@ -166,6 +206,7 @@ public abstract class AbstractCollection implements Collection
* size() == 0.
*
* @return true if this collection is empty.
* @see #size()
*/
public boolean isEmpty()
{
@ -173,92 +214,131 @@ public abstract class AbstractCollection implements Collection
}
/**
* Remove a single instance of an object from this collection. That is,
* remove one element e such that (o == null ? e == null : o.equals(e)), if
* such an element exists. This implementation obtains an iterator over the
* collection and iterates over it, testing each element for equality with
* the given object. If it is equal, it is removed by the iterator's remove
* method (thus this method will fail with an UnsupportedOperationException
* if the Iterator's remove method does). After the first element has been
* Remove a single instance of an object from this collection (optional
* operation). That is, remove one element e such that
* <code>(o == null ? e == null : o.equals(e))</code>, if such an element
* exists. This implementation obtains an iterator over the collection
* and iterates over it, testing each element for equality with the given
* object. If it is equal, it is removed by the iterator's remove method
* (thus this method will fail with an UnsupportedOperationException if
* the Iterator's remove method does). After the first element has been
* removed, true is returned; if the end of the collection is reached, false
* is returned.
*
* @param o the object to remove from this collection
* @return true if the remove operation caused the Collection to change, or
* equivalently if the collection did contain o.
* @exception UnsupportedOperationException if this collection's Iterator
* @throws UnsupportedOperationException if this collection's Iterator
* does not support the remove method
* @see Iterator#remove()
*/
public boolean remove(Object o)
{
Iterator itr = iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
{
if (o == null ? itr.next() == null : o.equals(itr.next()))
int pos = size();
while (--pos >= 0)
if (equals(o, itr.next()))
{
itr.remove();
return true;
}
}
return false;
}
/**
* Remove from this collection all its elements that are contained in a given
* collection. This implementation iterates over this collection, and for
* each element tests if it is contained in the given collection. If so, it
* is removed by the Iterator's remove method (thus this method will fail
* with an UnsupportedOperationException if the Iterator's remove method
* does).
* collection (optional operation). This implementation iterates over this
* collection, and for each element tests if it is contained in the given
* collection. If so, it is removed by the Iterator's remove method (thus
* this method will fail with an UnsupportedOperationException if the
* Iterator's remove method does).
*
* @param c the collection to remove the elements of
* @return true if the remove operation caused the Collection to change
* @exception UnsupportedOperationException if this collection's Iterator
* @throws UnsupportedOperationException if this collection's Iterator
* does not support the remove method
* @see Iterator#remove()
*/
public boolean removeAll(Collection c)
{
Iterator itr = iterator();
int size = size();
boolean modified = false;
for (int pos = 0; pos < size; pos++)
return removeAllInternal(c);
}
/**
* Remove from this collection all its elements that are contained in a given
* collection (optional operation). This implementation iterates over this
* collection, and for each element tests if it is contained in the given
* collection. If so, it is removed by the Iterator's remove method (thus
* this method will fail with an UnsupportedOperationException if the
* Iterator's remove method does). This method is necessary for ArrayList,
* which cannot publicly override removeAll but can optimize this call.
*
* @param c the collection to remove the elements of
* @return true if the remove operation caused the Collection to change
* @throws UnsupportedOperationException if this collection's Iterator
* does not support the remove method
* @see Iterator#remove()
*/
boolean removeAllInternal(Collection c)
{
Iterator itr = iterator();
boolean modified = false;
int pos = size();
while (--pos >= 0)
if (c.contains(itr.next()))
{
itr.remove();
modified = true;
}
}
return modified;
}
/**
* Remove from this collection all its elements that are not contained in a
* given collection. This implementation iterates over this collection, and
* for each element tests if it is contained in the given collection. If not,
* it is removed by the Iterator's remove method (thus this method will fail
* with an UnsupportedOperationException if the Iterator's remove method
* does).
* given collection (optional operation). This implementation iterates over
* this collection, and for each element tests if it is contained in the
* given collection. If not, it is removed by the Iterator's remove method
* (thus this method will fail with an UnsupportedOperationException if
* the Iterator's remove method does).
*
* @param c the collection to retain the elements of
* @return true if the remove operation caused the Collection to change
* @exception UnsupportedOperationException if this collection's Iterator
* @throws UnsupportedOperationException if this collection's Iterator
* does not support the remove method
* @see Iterator#remove()
*/
public boolean retainAll(Collection c)
{
Iterator itr = iterator();
int size = size();
boolean modified = false;
for (int pos = 0; pos < size; pos++)
return retainAllInternal(c);
}
/**
* Remove from this collection all its elements that are not contained in a
* given collection (optional operation). This implementation iterates over
* this collection, and for each element tests if it is contained in the
* given collection. If not, it is removed by the Iterator's remove method
* (thus this method will fail with an UnsupportedOperationException if
* the Iterator's remove method does). This method is necessary for
* ArrayList, which cannot publicly override retainAll but can optimize
* this call.
*
* @param c the collection to retain the elements of
* @return true if the remove operation caused the Collection to change
* @throws UnsupportedOperationException if this collection's Iterator
* does not support the remove method
* @see Iterator#remove()
*/
boolean retainAllInternal(Collection c)
{
Iterator itr = iterator();
boolean modified = false;
int pos = size();
while (--pos >= 0)
if (!c.contains(itr.next()))
{
itr.remove();
modified = true;
}
}
return modified;
}
@ -266,18 +346,18 @@ public abstract class AbstractCollection implements Collection
* Return an array containing the elements of this collection. This
* implementation creates an Object array of size size() and then iterates
* over the collection, setting each element of the array from the value
* returned by the iterator.
* returned by the iterator. The returned array is safe, and is not backed
* by the collection.
*
* @return an array containing the elements of this collection
*/
public Object[] toArray()
{
Iterator itr = iterator();
Object[]a = new Object[size()];
for (int pos = 0; pos < a.length; pos++)
{
int size = size();
Object[] a = new Object[size];
for (int pos = 0; pos < size; pos++)
a[pos] = itr.next();
}
return a;
}
@ -293,29 +373,29 @@ public abstract class AbstractCollection implements Collection
* obtained over the collection and the elements are placed in the array as
* they are returned by the iterator. Finally the first spare element, if
* any, of the array is set to null, and the created array is returned.
* The returned array is safe; it is not backed by the collection. Note that
* null may not mark the last element, if the collection allows null
* elements.
*
* @param a the array to copy into, or of the correct run-time type
* @return the array that was produced
* @exception ClassCastException if the type of the array precludes holding
* @throws NullPointerException if the given array is null
* @throws ArrayStoreException if the type of the array precludes holding
* one of the elements of the Collection
*/
public Object[] toArray(Object[] a)
{
int size = size();
if (a.length < size)
{
a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
size);
}
else if (a.length > size)
a[size] = null;
Iterator itr = iterator();
for (int pos = 0; pos < size; pos++)
{
a[pos] = itr.next();
}
if (a.length > size)
{
a[size] = null;
}
return a;
}
@ -331,15 +411,41 @@ public abstract class AbstractCollection implements Collection
public String toString()
{
Iterator itr = iterator();
int size = size();
StringBuffer r = new StringBuffer("[");
for (int pos = 0; pos < size; pos++)
for (int pos = size(); pos > 0; pos--)
{
r.append(itr.next());
if (pos < size - 1)
if (pos > 1)
r.append(", ");
}
r.append("]");
return r.toString();
}
/**
* Compare two objects according to Collection semantics.
*
* @param o1 the first object
* @param o2 the second object
* @return o1 == null ? o2 == null : o1.equals(o2)
*/
// Package visible for use throughout java.util.
// It may be inlined since it is final.
static final boolean equals(Object o1, Object o2)
{
return o1 == null ? o2 == null : o1.equals(o2);
}
/**
* Hash an object according to Collection semantics.
*
* @param o the object to hash
* @return o1 == null ? 0 : o1.hashCode()
*/
// Package visible for use throughout java.util.
// It may be inlined since it is final.
static final int hashCode(Object o)
{
return o == null ? 0 : o.hashCode();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* AbstractMap.java -- Abstract implementation of most of Map
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -25,22 +25,71 @@ This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public License. */
// TO DO:
// comments
// test suite
package java.util;
/**
* An abstract implementation of Map to make it easier to create your own
* implementations. In order to create an unmodifiable Map, subclass
* AbstractMap and implement the <code>entrySet</code> (usually via an
* AbstractSet). To make it modifiable, also implement <code>put</code>,
* and have <code>entrySet().iterator()</code> support <code>remove</code>.
* <p>
*
* It is recommended that classes which extend this support at least the
* no-argument constructor, and a constructor which accepts another Map.
* Further methods in this class may be overridden if you have a more
* efficient implementation.
*
* @author Original author unknown
* @author Bryce McKinlay
* @author Eric Blake <ebb9@email.byu.edu>
* @see Map
* @see Collection
* @see HashMap
* @see LinkedHashMap
* @see TreeMap
* @see WeakHashMap
* @see IdentityHashMap
* @since 1.2
* @status updated to 1.4
*/
public abstract class AbstractMap implements Map
{
/** An "enum" of iterator types. */
// Package visible for use by subclasses.
static final int KEYS = 0,
VALUES = 1,
ENTRIES = 2;
/**
* Remove all entries from this Map. This default implementation calls
* entrySet().clear().
* The cache for {@link #keySet()}.
*/
// Package visible for use by subclasses.
Set keys;
/**
* The cache for {@link #values()}.
*/
// Package visible for use by subclasses.
Collection values;
/**
* The main constructor, for use by subclasses.
*/
protected AbstractMap()
{
}
/**
* Remove all entries from this Map (optional operation). This default
* implementation calls entrySet().clear(). NOTE: If the entry set does
* not permit clearing, then this will fail, too. Subclasses often
* override this for efficiency. Your implementation of entrySet() should
* not call <code>AbstractMap.clear</code> unless you want an infinite loop.
*
* @throws UnsupportedOperationException
* @specnote The JCL book claims that this implementation always throws
* UnsupportedOperationException, while the online docs claim it
* calls entrySet().clear(). We take the later to be correct.
* @throws UnsupportedOperationException if <code>entrySet().clear()</code>
* does not support clearing.
* @see Set#clear()
*/
public void clear()
{
@ -48,107 +97,174 @@ public abstract class AbstractMap implements Map
}
/**
* Create a shallow copy of this Map, no keys or values are copied.
* Create a shallow copy of this Map, no keys or values are copied. The
* default implementation simply calls <code>super.clone()</code>.
*
* @return the shallow clone
* @throws CloneNotSupportedException if a subclass is not Cloneable
* @see Cloneable
* @see Object#clone()
*/
protected Object clone() throws CloneNotSupportedException
{
return super.clone ();
AbstractMap copy = (AbstractMap) super.clone();
// Clear out the caches; they are stale.
copy.keys = null;
copy.values = null;
return copy;
}
/**
* Returns true if this contains a mapping for the given key. This
* implementation does a linear search, O(n), over the
* <code>entrySet()</code>, returning <code>true</code> if a match
* is found, <code>false</code> if the iteration ends. Many subclasses
* can implement this more efficiently.
*
* @param key the key to search for
* @return true if the map contains the key
* @throws NullPointerException if key is <code>null</code> but the map
* does not permit null keys
* @see #containsValue(Object)
*/
public boolean containsKey(Object key)
{
Object k;
Set es = entrySet();
Iterator entries = es.iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
{
k = ((Map.Entry) entries.next()).getKey();
if (key == null ? k == null : key.equals(k))
Iterator entries = entrySet().iterator();
int pos = size();
while (--pos >= 0)
if (equals(key, ((Map.Entry) entries.next()).getKey()))
return true;
}
return false;
}
/**
* Returns true if this contains at least one mapping with the given value.
* This implementation does a linear search, O(n), over the
* <code>entrySet()</code>, returning <code>true</code> if a match
* is found, <code>false</code> if the iteration ends. A match is
* defined as <code>(value == null ? v == null : value.equals(v))</code>
* Subclasses are unlikely to implement this more efficiently.
*
* @param value the value to search for
* @return true if the map contains the value
* @see #containsKey(Object)
*/
public boolean containsValue(Object value)
{
Object v;
Set es = entrySet();
Iterator entries = es.iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
{
v = ((Map.Entry) entries.next()).getValue();
if (value == null ? v == null : value.equals(v))
Iterator entries = entrySet().iterator();
int pos = size();
while (--pos >= 0)
if (equals(value, ((Map.Entry) entries.next()).getValue()))
return true;
}
return false;
}
/**
* Returns a set view of the mappings in this Map. Each element in the
* set must be an implementation of Map.Entry. The set is backed by
* the map, so that changes in one show up in the other. Modifications
* made while an iterator is in progress cause undefined behavior. If
* the set supports removal, these methods must be valid:
* <code>Iterator.remove</code>, <code>Set.remove</code>,
* <code>removeAll</code>, <code>retainAll</code>, and <code>clear</code>.
* Element addition is not supported via this set.
*
* @return the entry set
* @see Map.Entry
*/
public abstract Set entrySet();
/**
* Compares the specified object with this map for equality. Returns
* <code>true</code> if the other object is a Map with the same mappings,
* that is,<br>
* <code>o instanceof Map && entrySet().equals(((Map) o).entrySet();</code>
*
* @param o the object to be compared
* @return true if the object equals this map
* @see Set#equals(Object)
*/
public boolean equals(Object o)
{
if (o == this)
return true;
if (!(o instanceof Map))
return false;
Map m = (Map) o;
Set s = m.entrySet();
Iterator itr = entrySet().iterator();
int size = size();
if (m.size() != size)
return false;
for (int pos = 0; pos < size; pos++)
{
if (!s.contains(itr.next()))
return false;
}
return true;
return (o == this ||
(o instanceof Map &&
entrySet().equals(((Map) o).entrySet())));
}
/**
* Returns the value mapped by the given key. Returns <code>null</code> if
* there is no mapping. However, in Maps that accept null values, you
* must rely on <code>containsKey</code> to determine if a mapping exists.
* This iteration takes linear time, searching entrySet().iterator() of
* the key. Many implementations override this method.
*
* @param key the key to look up
* @return the value associated with the key, or null if key not in map
* @throws NullPointerException if this map does not accept null keys
* @see #containsKey(Object)
*/
public Object get(Object key)
{
Set s = entrySet();
Iterator entries = s.iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
Iterator entries = entrySet().iterator();
int pos = size();
while (--pos >= 0)
{
Map.Entry entry = (Map.Entry) entries.next();
Object k = entry.getKey();
if (key == null ? k == null : key.equals(k))
if (equals(key, entry.getKey()))
return entry.getValue();
}
return null;
}
/**
* Returns the hash code for this map. As defined in Map, this is the sum
* of all hashcodes for each Map.Entry object in entrySet, or basically
* entrySet().hashCode().
*
* @return the hash code
* @see Map.Entry#hashCode()
* @see Set#hashCode()
*/
public int hashCode()
{
int hashcode = 0;
Iterator itr = entrySet().iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
{
hashcode += itr.next().hashCode();
}
return hashcode;
return entrySet().hashCode();
}
/**
* Returns true if the map contains no mappings. This is implemented by
* <code>size() == 0</code>.
*
* @return true if the map is empty
* @see #size()
*/
public boolean isEmpty()
{
return size() == 0;
}
/**
* Returns a set view of this map's keys. The set is backed by the map,
* so changes in one show up in the other. Modifications while an iteration
* is in progress produce undefined behavior. The set supports removal
* if entrySet() does, but does not support element addition.
* <p>
*
* This implementation creates an AbstractSet, where the iterator wraps
* the entrySet iterator, size defers to the Map's size, and contains
* defers to the Map's containsKey. The set is created on first use, and
* returned on subsequent uses, although since no synchronization occurs,
* there is a slight possibility of creating two sets.
*
* @return a Set view of the keys
* @see Set#iterator()
* @see #size()
* @see #containsKey(Object)
* @see #values()
*/
public Set keySet()
{
if (this.keySet == null)
{
this.keySet = new AbstractSet()
if (keys == null)
keys = new AbstractSet()
{
public int size()
{
@ -157,14 +273,14 @@ public abstract class AbstractMap implements Map
public boolean contains(Object key)
{
return AbstractMap.this.containsKey(key);
return containsKey(key);
}
public Iterator iterator()
{
return new Iterator()
{
Iterator map_iterator = AbstractMap.this.entrySet().iterator();
private final Iterator map_iterator = entrySet().iterator();
public boolean hasNext()
{
@ -183,77 +299,156 @@ public abstract class AbstractMap implements Map
};
}
};
return keys;
}
return this.keySet;
}
/**
* Associates the given key to the given value (optional operation). If the
* map already contains the key, its value is replaced. This implementation
* simply throws an UnsupportedOperationException. Be aware that in a map
* that permits <code>null</code> values, a null return does not always
* imply that the mapping was created.
*
* @param key the key to map
* @param value the value to be mapped
* @return the previous value of the key, or null if there was no mapping
* @throws UnsupportedOperationException if the operation is not supported
* @throws ClassCastException if the key or value is of the wrong type
* @throws IllegalArgumentException if something about this key or value
* prevents it from existing in this map
* @throws NullPointerException if the map forbids null keys or values
* @see #containsKey(Object)
*/
public Object put(Object key, Object value)
{
throw new UnsupportedOperationException();
}
/**
* Copies all entries of the given map to this one (optional operation). If
* the map already contains a key, its value is replaced. This implementation
* simply iterates over the map's entrySet(), calling <code>put</code>,
* so it is not supported if puts are not.
*
* @param m the mapping to load into this map
* @throws UnsupportedOperationException if the operation is not supported
* @throws ClassCastException if a key or value is of the wrong type
* @throws IllegalArgumentException if something about a key or value
* prevents it from existing in this map
* @throws NullPointerException if the map forbids null keys or values, or
* if <code>m</code> is null.
* @see #put(Object, Object)
*/
public void putAll(Map m)
{
Map.Entry entry;
Iterator entries = m.entrySet().iterator();
int size = m.size();
for (int pos = 0; pos < size; pos++)
int pos = size();
while (--pos >= 0)
{
entry = (Map.Entry) entries.next();
Map.Entry entry = (Map.Entry) entries.next();
put(entry.getKey(), entry.getValue());
}
}
/**
* Removes the mapping for this key if present (optional operation). This
* implementation iterates over the entrySet searching for a matching
* key, at which point it calls the iterator's <code>remove</code> method.
* It returns the result of <code>getValue()</code> on the entry, if found,
* or null if no entry is found. Note that maps which permit null values
* may also return null if the key was removed. If the entrySet does not
* support removal, this will also fail. This is O(n), so many
* implementations override it for efficiency.
*
* @param key the key to remove
* @return the value the key mapped to, or null if not present
* @throws UnsupportedOperationException if deletion is unsupported
* @see Iterator#remove()
*/
public Object remove(Object key)
{
Iterator entries = entrySet().iterator();
int size = size();
for (int pos = 0; pos < size; pos++)
int pos = size();
while (--pos >= 0)
{
Map.Entry entry = (Map.Entry) entries.next();
Object k = entry.getKey();
if (key == null ? k == null : key.equals(k))
if (equals(key, entry.getKey()))
{
Object value = entry.getValue();
// Must get the value before we remove it from iterator.
Object r = entry.getValue();
entries.remove();
return value;
return r;
}
}
return null;
}
/**
* Returns the number of key-value mappings in the map. If there are more
* than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. This is
* implemented as <code>entrySet().size()</code>.
*
* @return the number of mappings
* @see Set#size()
*/
public int size()
{
return entrySet().size();
}
/**
* Returns a String representation of this map. This is a listing of the
* map entries (which are specified in Map.Entry as being
* <code>getKey() + "=" + getValue()</code>), separated by a comma and
* space (", "), and surrounded by braces ('{' and '}'). This implementation
* uses a StringBuffer and iterates over the entrySet to build the String.
* Note that this can fail with an exception if underlying keys or
* values complete abruptly in toString().
*
* @return a String representation
* @see Map.Entry#toString()
*/
public String toString()
{
Iterator entries = entrySet().iterator();
int size = size();
StringBuffer r = new StringBuffer("{");
for (int pos = 0; pos < size; pos++)
for (int pos = size(); pos > 0; pos--)
{
// Append the toString value of the entries rather than calling
// getKey/getValue. This is more efficient and it matches the JDK
// behaviour.
r.append(entries.next());
if (pos < size - 1)
if (pos > 1)
r.append(", ");
}
r.append("}");
return r.toString();
}
/**
* Returns a collection or bag view of this map's values. The collection
* is backed by the map, so changes in one show up in the other.
* Modifications while an iteration is in progress produce undefined
* behavior. The collection supports removal if entrySet() does, but
* does not support element addition.
* <p>
*
* This implementation creates an AbstractCollection, where the iterator
* wraps the entrySet iterator, size defers to the Map's size, and contains
* defers to the Map's containsValue. The collection is created on first
* use, and returned on subsequent uses, although since no synchronization
* occurs, there is a slight possibility of creating two collections.
*
* @return a Collection view of the values
* @see Collection#iterator()
* @see #size()
* @see #containsValue(Object)
* @see #keySet()
*/
public Collection values()
{
if (this.valueCollection == null)
{
this.valueCollection = new AbstractCollection()
if (values == null)
values = new AbstractCollection()
{
public int size()
{
@ -264,7 +459,7 @@ public abstract class AbstractMap implements Map
{
return new Iterator()
{
Iterator map_iterator = AbstractMap.this.entrySet().iterator();
private final Iterator map_iterator = entrySet().iterator();
public boolean hasNext()
{
@ -283,11 +478,33 @@ public abstract class AbstractMap implements Map
};
}
};
return values;
}
return this.valueCollection;
/**
* Compare two objects according to Collection semantics.
*
* @param o1 the first object
* @param o2 the second object
* @return o1 == null ? o2 == null : o1.equals(o2)
*/
// Package visible for use throughout java.util.
// It may be inlined since it is final.
static final boolean equals(Object o1, Object o2)
{
return o1 == null ? o2 == null : o1.equals(o2);
}
private Collection valueCollection = null;
private Set keySet = null;
/**
* Hash an object according to Collection semantics.
*
* @param o the object to hash
* @return o1 == null ? 0 : o1.hashCode()
*/
// Package visible for use throughout java.util.
// It may be inlined since it is final.
static final int hashCode(Object o)
{
return o == null ? 0 : o.hashCode();
}
}

View file

@ -1,5 +1,5 @@
/* AbstractSequentialList.java -- List implementation for sequential access
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -25,100 +25,192 @@ This exception does not however invalidate any other reasons why the
executable file might be covered by the GNU General Public License. */
// TO DO:
// ~ Lots of doc comments still missing.
// ~ The class comment should include a description of what should be overridden
// to provide what features, as should the listIterator comment.
package java.util;
/**
* Abstract superclass to make it easier to implement the List interface when
* backed by a sequential-access store, such as a linked list.
* backed by a sequential-access store, such as a linked list. For random
* access data, use AbstractList. This class implements the random access
* methods (<code>get</code>, <code>set</code>, <code>add</code>, and
* <code>remove</code>) atop the list iterator, opposite of AbstractList's
* approach of implementing the iterator atop random access.
* <p>
*
* To implement a list, you need an implementation for <code>size()</code>
* and <code>listIterator</code>. With just <code>hasNext</code>,
* <code>next</code>, <code>hasPrevious</code>, <code>previous</code>,
* <code>nextIndex</code>, and <code>previousIndex</code>, you have an
* unmodifiable list. For a modifiable one, add <code>set</code>, and for
* a variable-size list, add <code>add</code> and <code>remove</code>.
* <p>
*
* The programmer should provide a no-argument constructor, and one that
* accepts another Collection, as recommended by the Collection interface.
* Unfortunately, there is no way to enforce this in Java.
*
* @author Original author unknown
* @author Bryce McKinlay
* @author Eric Blake <ebb9@email.byu.edu>
* @see Collection
* @see List
* @see AbstractList
* @see AbstractCollection
* @see ListIterator
* @see LinkedList
* @since 1.2
* @status updated to 1.4
*/
public abstract class AbstractSequentialList extends AbstractList
{
/**
* The main constructor, for use by subclasses.
*/
protected AbstractSequentialList()
{
}
/**
* Returns a ListIterator over the list, starting from position index.
* Subclasses must provide an implementation of this method.
*
* @exception IndexOutOfBoundsException if index < 0 || index > size()
* @param index the starting position of the list
* @return the list iterator
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
*/
public abstract ListIterator listIterator(int index);
/**
* Add an element to the list at a given index. This implementation obtains a
* ListIterator positioned at the specified index, and then adds the element
* using the ListIterator's add method.
* Insert an element into the list at a given position (optional operation).
* This shifts all existing elements from that position to the end one
* index to the right. This version of add has no return, since it is
* assumed to always succeed if there is no exception. This iteration
* uses listIterator(index).add(o).
*
* @param index the position to add the element
* @param o the element to insert
* @exception IndexOutOfBoundsException if index < 0 || index > size()
* @exception UnsupportedOperationException if the iterator returned by
* listIterator(index) does not support the add method.
* @param index the location to insert the item
* @param o the object to insert
* @throws UnsupportedOperationException if this list does not support the
* add operation
* @throws IndexOutOfBoundsException if index &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)
{
ListIterator i = listIterator(index);
i.add(o);
listIterator(index).add(o);
}
/**
* @specnote The spec in the JDK1.3 online docs is wrong. The implementation
* should not call next() to skip over new elements as they are
* added, because iterator.add() should add new elements BEFORE
* the cursor.
* Insert the contents of a collection into the list at a given position
* (optional operation). Shift all elements at that position to the right
* by the number of elements inserted. This operation is undefined if
* this list is modified during the operation (for example, if you try
* to insert a list into itself).
* <p>
*
* This implementation grabs listIterator(index), then proceeds to use add
* for each element returned by c's iterator. Sun's online specs are wrong,
* claiming that this also calls next(): listIterator.add() correctly
* skips the added element.
*
* @param index the location to insert the collection
* @param c the collection to insert
* @return true if the list was modified by this action, that is, if c is
* non-empty
* @throws UnsupportedOperationException if this list does not support the
* addAll operation
* @throws IndexOutOfBoundsException if index &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)
{
boolean modified = false;
Iterator ci = c.iterator();
int size = c.size();
ListIterator i = listIterator(index);
for (int pos = 0; pos < size; pos++)
{
for (int pos = size; pos > 0; pos--)
i.add(ci.next());
}
return (size > 0);
}
public Object get(int index)
{
ListIterator i = listIterator(index);
if (index < 0 || index > size())
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
return i.next();
return size > 0;
}
/**
* Return an Iterator over this List. This implementation returns
* listIterator().
* Get the element at a given index in this list. This implementation
* returns listIterator(index).next().
*
* @return an Iterator over this List
* @param index the index of the element to be returned
* @return the element at index index in this list
* @throws IndexOutOfBoundsException if index &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()
{
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)
{
// This is a legal listIterator position, but an illegal remove.
if (index == size())
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+ size());
ListIterator i = listIterator(index);
if (index < 0 || index > size())
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
Object removed = i.next();
i.remove();
return removed;
}
/**
* Replace an element of this list with another object (optional operation).
* This implementation uses listIterator(index) and ListIterator.set(o).
*
* @param index the position within this list of the element to be replaced
* @param o the object to replace it with
* @return the object that was replaced
* @throws UnsupportedOperationException if this list does not support the
* set operation
* @throws IndexOutOfBoundsException if index &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)
{
// This is a legal listIterator position, but an illegal set.
if (index == size())
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+ size());
ListIterator i = listIterator(index);
if (index < 0 || index > size())
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size());
Object old = i.next();
i.set(o);
return old;

View file

@ -1,5 +1,5 @@
/* AbstractSet.java -- Abstract implementation of most of Set
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -35,9 +35,27 @@ package java.util;
* on them - specifically, no element may be in the set more than once). This
* class simply provides implementations of equals() and hashCode() to fulfil
* the requirements placed on them by the Set interface.
*
* @author Original author unknown
* @author Eric Blake <ebb9@email.byu.edu>
* @see Collection
* @see AbstractCollection
* @see Set
* @see HashSet
* @see TreeSet
* @see LinkedHashSet
* @since 1.2
* @status updated to 1.4
*/
public abstract class AbstractSet extends AbstractCollection implements Set
{
/**
* The main constructor, for use by subclasses.
*/
protected AbstractSet()
{
}
/**
* Tests whether the given object is equal to this Set. This implementation
* first checks whether this set <em>is</em> the given object, and returns
@ -50,12 +68,9 @@ public abstract class AbstractSet extends AbstractCollection implements Set
*/
public boolean equals(Object o)
{
if (o == this)
return true;
else if (o instanceof Set && ((Set) o).size() == size())
return containsAll((Collection) o);
else
return false;
return (o == this ||
(o instanceof Set && ((Set) o).size() == size()
&& containsAll((Collection) o)));
}
/**
@ -69,14 +84,45 @@ public abstract class AbstractSet extends AbstractCollection implements Set
public int hashCode()
{
Iterator itr = iterator();
int size = size();
int hash = 0;
for (int pos = 0; pos < size; pos++)
{
Object obj = itr.next();
if (obj != null)
hash += obj.hashCode();
}
int pos = size();
while (--pos >= 0)
hash += hashCode(itr.next());
return hash;
}
/**
* Removes from this set all elements in the given collection (optional
* operation). This implementation uses <code>size()</code> to determine
* the smaller collection. Then, if this set is smaller, it iterates
* over the set, calling Iterator.remove if the collection contains
* the element. If this set is larger, it iterates over the collection,
* calling Set.remove for all elements in the collection. Note that
* this operation will fail if a remove methods is not supported.
*
* @param c the collection of elements to remove
* @return true if the set was modified as a result
* @throws UnsupportedOperationException if remove is not supported
* @throws NullPointerException if the collection is null
* @see AbstractCollection#remove(Object)
* @see Collection#contains(Object)
* @see Iterator#remove()
*/
public boolean removeAll(Collection c)
{
int oldsize = size();
int count = c.size();
Iterator i;
if (oldsize < count)
{
for (i = iterator(), count = oldsize; count > 0; count--)
if (c.contains(i.next()))
i.remove();
}
else
for (i = c.iterator(); count > 0; count--)
remove(i.next());
return oldsize != size();
}
}

View file

@ -1,6 +1,6 @@
/* ArrayList.java -- JDK1.2's answer to Vector; this is an array-backed
implementation of the List interface
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -35,39 +35,81 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* An array-backed implementation of the List interface. ArrayList
* performs well on simple tasks: random access into a list, appending
* to or removing from the end of a list, checking the size, &c.
* An array-backed implementation of the List interface. This implements
* all optional list operations, and permits null elements, so that it is
* better than Vector, which it replaces. Random access is roughly constant
* time, and iteration is roughly linear time, so it is nice and fast, with
* less overhead than a LinkedList.
* <p>
*
* Each list has a capacity, and as the array reaches that capacity it
* is automatically transferred to a larger array. You also have access to
* ensureCapacity and trimToSize to control the backing array's size, avoiding
* reallocation or wasted memory.
* <p>
*
* ArrayList is not synchronized, so if you need multi-threaded access,
* consider using:<br>
* <code>List l = Collections.synchronizedList(new ArrayList(...));</code>
* <p>
*
* The iterators are <i>fail-fast</i>, meaning that any structural
* modification, except for <code>remove()</code> called on the iterator
* itself, cause the iterator to throw a
* {@link ConcurrentModificationException} rather than exhibit
* non-deterministic behavior.
*
* @author Jon A. Zeppieri
* @see java.util.AbstractList
* @see java.util.List
* @author Bryce McKinlay
* @author Eric Blake <ebb9@email.byu.edu>
* @see Collection
* @see List
* @see LinkedList
* @see Vector
* @see Collections#synchronizedList(List)
* @see AbstractList
* @status updated to 1.4
*/
public class ArrayList extends AbstractList
implements List, Cloneable, Serializable
implements List, RandomAccess, Cloneable, Serializable
{
/** the default capacity for new ArrayLists */
/**
* Compatible with JDK 1.2
*/
private static final long serialVersionUID = 8683452581122892189L;
/**
* The default capacity for new ArrayLists.
*/
private static final int DEFAULT_CAPACITY = 16;
/** the number of elements in this list */
int size;
/**
* The number of elements in this list.
* @serial the list size
*/
private int size;
/** where the data is stored */
transient Object[] data;
/**
* Where the data is stored.
*/
private transient Object[] data;
/**
* Construct a new ArrayList with the supplied initial capacity.
*
* @param capacity Initial capacity of this ArrayList
* @param capacity initial capacity of this ArrayList
* @throws IllegalArgumentException if capacity is negative
*/
public ArrayList(int capacity)
{
// Must explicitly check, to get correct exception.
if (capacity < 0)
throw new IllegalArgumentException();
data = new Object[capacity];
}
/**
* Construct a new ArrayList with the default capcity
* Construct a new ArrayList with the default capcity (16).
*/
public ArrayList()
{
@ -76,71 +118,60 @@ public class ArrayList extends AbstractList
/**
* Construct a new ArrayList, and initialize it with the elements
* in the supplied Collection; Sun specs say that the initial
* capacity is 110% of the Collection's size.
* in the supplied Collection. The initial capacity is 110% of the
* Collection's size.
*
* @param c the collection whose elements will initialize this list
* @throws NullPointerException if c is null
*/
public ArrayList(Collection c)
{
this((int) (c.size() * 1.1));
this((int) (c.size() * 1.1f));
addAll(c);
}
/**
* Guarantees that this list will have at least enough capacity to
* hold minCapacity elements.
*
* @specnote This implementation will grow the list to
* max(current * 2, minCapacity) if (minCapacity > current). The JCL says
* explictly that "this method increases its capacity to minCap", while
* the JDK 1.3 online docs specify that the list will grow to at least the
* size specified.
* @param minCapacity the minimum guaranteed capacity
* Trims the capacity of this List to be equal to its size;
* a memory saver.
*/
public void ensureCapacity(int minCapacity)
public void trimToSize()
{
Object[] newData;
int current = data.length;
if (minCapacity > current)
// Not a structural change from the perspective of iterators on this list,
// so don't update modCount.
if (size != data.length)
{
newData = new Object[Math.max((current * 2), minCapacity)];
Object[] newData = new Object[size];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
}
/**
* Appends the supplied element to the end of this list.
* Guarantees that this list will have at least enough capacity to
* hold minCapacity elements. This implementation will grow the list to
* max(current * 2, minCapacity) if (minCapacity > current). The JCL says
* explictly that "this method increases its capacity to minCap", while
* the JDK 1.3 online docs specify that the list will grow to at least the
* size specified.
*
* @param e the element to be appended to this list
* @param minCapacity the minimum guaranteed capacity
*/
public boolean add(Object e)
public void ensureCapacity(int minCapacity)
{
modCount++;
if (size == data.length)
ensureCapacity(size + 1);
data[size++] = e;
return true;
int current = data.length;
if (minCapacity > current)
{
Object[] newData = new Object[Math.max(current * 2, minCapacity)];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
}
/**
* Retrieves the element at the user-supplied index.
* Returns the number of elements in this list.
*
* @param index the index of the element we are fetching
* @throws IndexOutOfBoundsException (iIndex < 0) || (iIndex >= size())
*/
public Object get(int index)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
return data[index];
}
/**
* Returns the number of elements in this list
* @return the list size
*/
public int size()
{
@ -148,106 +179,60 @@ public class ArrayList extends AbstractList
}
/**
* Removes the element at the user-supplied index
* Checks if the list is empty.
*
* @param iIndex the index of the element to be removed
* @return the removed Object
* @throws IndexOutOfBoundsException (iIndex < 0) || (iIndex >= size())
* @return true if there are no elements
*/
public Object remove(int index)
public boolean isEmpty()
{
modCount++;
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
Object r = data[index];
if (index != --size)
System.arraycopy(data, (index + 1), data, index, (size - index));
data[size] = null;
return r;
return size == 0;
}
/**
* Removes all elements in the half-open interval [iFromIndex, iToIndex).
* Returns true iff element is in this ArrayList.
*
* @param fromIndex the first index which will be removed
* @param toIndex one greater than the last index which will be
* removed
* @param e the element whose inclusion in the List is being tested
* @return true if the list contains e
*/
protected void removeRange(int fromIndex, int toIndex)
public boolean contains(Object e)
{
modCount++;
if (fromIndex != toIndex)
{
System.arraycopy(data, toIndex, data, fromIndex, size - toIndex);
size -= (toIndex - fromIndex);
}
return indexOf(e) != -1;
}
/**
* Adds the supplied element at the specified index, shifting all
* elements currently at that index or higher one to the right.
* Returns the lowest index at which element appears in this List, or
* -1 if it does not appear.
*
* @param index the index at which the element is being added
* @param e the item being added
* @param e the element whose inclusion in the List is being tested
* @return the index where e was found
*/
public void add(int index, Object e)
public int indexOf(Object e)
{
modCount++;
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
if (size == data.length)
ensureCapacity(size + 1);
if (index != size)
System.arraycopy(data, index, data, index + 1, size - index);
data[index] = e;
size++;
for (int i = 0; i < size; i++)
if (equals(e, data[i]))
return i;
return -1;
}
/**
* Add each element in the supplied Collection to this List.
* Returns the highest index at which element appears in this List, or
* -1 if it does not appear.
*
* @param c a Collection containing elements to be
* added to this List
* @param e the element whose inclusion in the List is being tested
* @return the index where e was found
*/
public boolean addAll(Collection c)
public int lastIndexOf(Object e)
{
return addAll(size, c);
for (int i = size - 1; i >= 0; i--)
if (equals(e, data[i]))
return i;
return -1;
}
/**
* Add all elements in the supplied collection, inserting them beginning
* at the specified index.
* Creates a shallow copy of this ArrayList (elements are not cloned).
*
* @param index the index at which the elements will be inserted
* @param c the Collection containing the elements to be
* inserted
*/
public boolean addAll(int index, Collection c)
{
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
modCount++;
Iterator itr = c.iterator();
int csize = c.size();
if (csize + size > data.length)
ensureCapacity(size + csize);
int end = index + csize;
if (size > 0 && index != size)
System.arraycopy(data, index, data, end, csize);
size += csize;
for (; index < end; index++)
{
data[index] = itr.next();
}
return (csize > 0);
}
/**
* Creates a shallow copy of this ArrayList
* @return the cloned object
*/
public Object clone()
{
@ -255,95 +240,20 @@ public class ArrayList extends AbstractList
try
{
clone = (ArrayList) super.clone();
clone.data = new Object[data.length];
System.arraycopy(data, 0, clone.data, 0, size);
clone.data = (Object[]) data.clone();
}
catch (CloneNotSupportedException e)
{
// Impossible to get here.
}
catch (CloneNotSupportedException e) {}
return clone;
}
/**
* Returns true iff oElement is in this ArrayList.
* Returns an Object array containing all of the elements in this ArrayList.
* The array is independent of this list.
*
* @param e the element whose inclusion in the List is being
* tested
*/
public boolean contains(Object e)
{
return (indexOf(e) != -1);
}
/**
* Returns the lowest index at which oElement appears in this List, or
* -1 if it does not appear.
*
* @param e the element whose inclusion in the List is being
* tested
*/
public int indexOf(Object e)
{
for (int i = 0; i < size; i++)
{
if (e == null ? data[i] == null : e.equals(data[i]))
return i;
}
return -1;
}
/**
* Returns the highest index at which oElement appears in this List, or
* -1 if it does not appear.
*
* @param e the element whose inclusion in the List is being
* tested
*/
public int lastIndexOf(Object e)
{
int i;
for (i = size - 1; i >= 0; i--)
{
if (e == null ? data[i] == null : e.equals(data[i]))
return i;
}
return -1;
}
/**
* Removes all elements from this List
*/
public void clear()
{
modCount++;
for (int i = 0; i < size; i++)
{
data[i] = null;
}
size = 0;
}
/**
* Sets the element at the specified index.
*
* @param index the index at which the element is being set
* @param e the element to be set
* @return the element previously at the specified index, or null if
* none was there
*/
public Object set(int index, Object e)
{
Object result;
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
result = data[index];
// SEH: no structural change, so don't update modCount
data[index] = e;
return result;
}
/**
* Returns an Object Array containing all of the elements in this ArrayList
* @return an array representation of this list
*/
public Object[] toArray()
{
@ -360,58 +270,300 @@ public class ArrayList extends AbstractList
* and returned; if the passed-in Array is <i>larger</i> than the size
* of this List, then size() index will be set to null.
*
* @param array the passed-in Array
* @param a the passed-in Array
* @return an array representation of this list
* @throws ArrayStoreException if the runtime type of a does not allow
* an element in this list
* @throws NullPointerException if a is null
*/
public Object[] toArray(Object[] array)
public Object[] toArray(Object[] a)
{
if (array.length < size)
array = (Object[]) Array.newInstance(array.getClass().getComponentType(),
if (a.length < size)
a = (Object[]) Array.newInstance(a.getClass().getComponentType(),
size);
else if (array.length > size)
array[size] = null;
System.arraycopy(data, 0, array, 0, size);
return array;
else if (a.length > size)
a[size] = null;
System.arraycopy(data, 0, a, 0, size);
return a;
}
/**
* Trims the capacity of this List to be equal to its size;
* a memory saver.
* Retrieves the element at the user-supplied index.
*
* @param index the index of the element we are fetching
* @throws IndexOutOfBoundsException if index &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,
// so don't update modCount
Object[] newData = new Object[size];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
checkBoundExclusive(index);
return data[index];
}
private void writeObject(ObjectOutputStream out) throws IOException
/**
* Sets the element at the specified index.
*
* @param index the index at which the element is being set
* @param e the element to be set
* @return the element previously at the specified index
* @throws IndexOutOfBoundsException if index &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 j;
for (i = 0; i < size; i++)
if (c.contains(data[i]))
break;
if (i == size)
return false;
// The 'size' field.
out.defaultWriteObject();
// FIXME: Do we really want to serialize unused list entries??
out.writeInt(data.length);
for (i = 0; i < data.length; i++)
out.writeObject(data[i]);
modCount++;
for (j = i++; i < size; i++)
if (! c.contains(data[i]))
data[j++] = data[i];
size -= i - j;
return true;
}
private void readObject(ObjectInputStream in)
/**
* Retain in this vector only the elements contained in the given collection.
* This is not public, due to Sun's API, but this performs in linear
* time while the default behavior of AbstractList would be quadratic.
*
* @param c the collection to filter by
* @return true if this vector changed
* @throws NullPointerException if c is null
* @since 1.2
*/
boolean retainAllInternal(Collection c)
{
int i;
int j;
for (i = 0; i < size; i++)
if (! c.contains(data[i]))
break;
if (i == size)
return false;
modCount++;
for (j = i++; i < size; i++)
if (c.contains(data[i]))
data[j++] = data[i];
size -= i - j;
return true;
}
/**
* Serializes this object to the given stream.
*
* @param out the stream to write to
* @throws IOException if the underlying stream fails
* @serialData the size field (int), the length of the backing array
* (int), followed by its elements (Objects) in proper order.
*/
private void writeObject(ObjectOutputStream s) throws IOException
{
// The 'size' field.
s.defaultWriteObject();
// We serialize unused list entries to preserve capacity.
int len = data.length;
s.writeInt(len);
for (int i = 0; i < len; i++)
s.writeObject(data[i]);
}
/**
* Deserializes this object from the given stream.
*
* @param in the stream to read from
* @throws ClassNotFoundException if the underlying stream fails
* @throws IOException if the underlying stream fails
* @serialData the size field (int), the length of the backing array
* (int), followed by its elements (Objects) in proper order.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
int i;
int capacity;
// the `size' field.
in.defaultReadObject();
capacity = in.readInt();
s.defaultReadObject();
int capacity = s.readInt();
data = new Object[capacity];
for (i = 0; i < capacity; i++)
data[i] = in.readObject();
for (int i = 0; i < capacity; i++)
data[i] = s.readObject();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* BasicMapEntry.java -- a class providing a plain-vanilla implementation of
the Map.Entry interface; could be used anywhere in java.util
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -29,52 +29,113 @@ executable file might be covered by the GNU General Public License. */
package java.util;
/**
* A class which implements Map.Entry. It is shared by HashMap, TreeMap, and
* Hashtable.
* A class which implements Map.Entry. It is shared by HashMap, TreeMap,
* Hashtable, and Collections. It is not specified by the JDK, but makes
* life much easier.
*
* @author Jon Zeppieri
* @author Eric Blake <ebb9@email.byu.edu>
*/
class BasicMapEntry implements Map.Entry
{
/**
* The key. Package visible for direct manipulation.
*/
Object key;
/**
* The value. Package visible for direct manipulation.
*/
Object value;
/**
* Basic constructor initializes the fields.
* @param newKey the key
* @param newValue the value
*/
BasicMapEntry(Object newKey, Object newValue)
{
key = newKey;
value = newValue;
}
/**
* Compares the specified object with this entry. Returns true only if
* the object is a mapping of identical key and value. In other words,
* this must be:
* <pre>
* (o instanceof Map.Entry) &&
* (getKey() == null ? ((HashMap) o).getKey() == null
* : getKey().equals(((HashMap) o).getKey())) &&
* (getValue() == null ? ((HashMap) o).getValue() == null
* : getValue().equals(((HashMap) o).getValue()))
* </pre>
*
* @param o the object to compare
* @return true if it is equal
*/
public final boolean equals(Object o)
{
if (! (o instanceof Map.Entry))
return false;
// Optimize for our own entries.
if (o instanceof BasicMapEntry)
{
BasicMapEntry e = (BasicMapEntry) o;
return (AbstractCollection.equals(key, e.key)
&& AbstractCollection.equals(value, e.value));
}
Map.Entry e = (Map.Entry) o;
return (key == null ? e.getKey() == null : key.equals(e.getKey())
&& value == null ? e.getValue() == null
: value.equals(e.getValue()));
return (AbstractCollection.equals(key, e.getKey())
&& AbstractCollection.equals(value, e.getValue()));
}
/**
* Get the key corresponding to this entry.
*
* @return the key
*/
public final Object getKey()
{
return key;
}
/**
* Get the value corresponding to this entry. If you already called
* Iterator.remove(), the behavior undefined, but in this case it works.
*
* @return the value
*/
public final Object getValue()
{
return value;
}
/**
* Returns the hash code of the entry. This is defined as the exclusive-or
* of the hashcodes of the key and value (using 0 for null). In other
* words, this must be:
* <pre>
* (getKey() == null ? 0 : getKey().hashCode()) ^
* (getValue() == null ? 0 : getValue().hashCode())
* </pre>
*
* @return the hash code
*/
public final int hashCode()
{
int kc = (key == null ? 0 : key.hashCode());
int vc = (value == null ? 0 : value.hashCode());
return kc ^ vc;
return (AbstractCollection.hashCode(key)
^ AbstractCollection.hashCode(value));
}
/**
* sets the value of this Map.Entry. Note that this is overriden by
* Hashtable.Entry, which does not permit a null value.
* Replaces the value with the specified object. This writes through
* to the map, unless you have already called Iterator.remove(). It
* may be overridden to restrict a null value.
*
* @param newVal the new value to store
* @return the old value
* @throws NullPointerException if the map forbids null values
*/
public Object setValue(Object newVal)
{
@ -83,6 +144,12 @@ class BasicMapEntry implements Map.Entry
return r;
}
/**
* This provides a string representation of the entry. It is of the form
* "key=value", where string concatenation is used on key and value.
*
* @return the string representation
*/
public final String toString()
{
return key + "=" + value;

View file

@ -1,6 +1,5 @@
// BitSet - A vector of bits.
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
/* BitSet.java -- A vector of bits.
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -50,22 +49,32 @@ import java.io.Serializable;
* while another thread is simultaneously modifying it, the results are
* undefined.
*
* @specnote Historically, there has been some confusion as to whether or not
* this class should be synchronized. From an efficiency perspective,
* it is very undesirable to synchronize it because multiple locks
* and explicit lock ordering are required to safely synchronize some
* methods. The JCL 1.2 supplement book specifies that as of JDK
* 1.2, the class is no longer synchronized.
*
* @author Jochen Hoenicke
* @author Tom Tromey <tromey@cygnus.com>
* @date October 23, 1998.
* @status API complete to JDK 1.3.
* @author Eric Blake <ebb9@email.byu.edu>
* @status updated to 1.4
*/
public class BitSet implements Cloneable, Serializable
{
/**
* Create a new empty bit set.
* Compatible with JDK 1.0.
*/
private static final long serialVersionUID = 7997698588986878753L;
/**
* A common mask.
*/
private static final int LONG_MASK = 0x3f;
/**
* The actual bits.
* @serial the i'th bit is in bits[i/64] at position i%64 (where position
* 0 is the least significant).
*/
private long[] bits;
/**
* Create a new empty bit set. All bits are initially false.
*/
public BitSet()
{
@ -76,17 +85,14 @@ public class BitSet implements Cloneable, Serializable
* Create a new empty bit set, with a given size. This
* constructor reserves enough space to represent the integers
* from <code>0</code> to <code>nbits-1</code>.
* @param nbits the initial size of the bit set.
* @throws NegativeArraySizeException if the specified initial
* size is negative.
* @require nbits >= 0
*
* @param nbits the initial size of the bit set
* @throws NegativeArraySizeException if nbits &lt; 0
*/
public BitSet(int nbits)
{
if (nbits < 0)
throw new NegativeArraySizeException();
int length = nbits / 64;
if (nbits % 64 != 0)
int length = nbits >>> 6;
if ((nbits & LONG_MASK) != 0)
++length;
bits = new long[length];
}
@ -95,8 +101,9 @@ public class BitSet implements Cloneable, Serializable
* Performs the logical AND operation on this bit set and the
* given <code>set</code>. This means it builds the intersection
* of the two sets. The result is stored into this bit set.
* @param set the second bit set.
* @require set != null
*
* @param set the second bit set
* @throws NullPointerException if set is null
*/
public void and(BitSet bs)
{
@ -104,8 +111,8 @@ public class BitSet implements Cloneable, Serializable
int i;
for (i = 0; i < max; ++i)
bits[i] &= bs.bits[i];
for (; i < bits.length; ++i)
bits[i] = 0;
while (i < bits.length)
bits[i++] = 0;
}
/**
@ -113,54 +120,134 @@ public class BitSet implements Cloneable, Serializable
* complement of the given <code>set</code>. This means it
* selects every element in the first set, that isn't in the
* second set. The result is stored into this bit set.
* @param set the second bit set.
* @require set != null
* @since JDK1.2
*
* @param set the second bit set
* @throws NullPointerException if set is null
* @since 1.2
*/
public void andNot(BitSet bs)
{
int max = Math.min(bits.length, bs.bits.length);
int i;
for (i = 0; i < max; ++i)
int i = Math.min(bits.length, bs.bits.length);
while (--i >= 0)
bits[i] &= ~bs.bits[i];
}
/**
* Returns the number of bits set to true.
*
* @return the number of true bits
* @since 1.4
*/
public int cardinality()
{
int card = 0;
for (int i = bits.length - 1; i >= 0; i--)
{
long a = bits[i];
// Take care of common cases.
if (a == 0)
continue;
if (a == -1)
{
card += 64;
continue;
}
// Successively collapse alternating bit groups into a sum.
a = ((a >> 1) & 0x5555555555555555L) + (a & 0x5555555555555555L);
a = ((a >> 2) & 0x3333333333333333L) + (a & 0x3333333333333333L);
int b = (int) ((a >>> 32) + a);
b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f);
b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff);
card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff);
}
return card;
}
/**
* Sets all bits in the set to false.
*
* @since 1.4
*/
public void clear()
{
Arrays.fill(bits, 0);
}
/**
* Removes the integer <code>bitIndex</code> from this set. That is
* the corresponding bit is cleared. If the index is not in the set,
* this method does nothing.
* @param bitIndex a non-negative integer.
* @exception ArrayIndexOutOfBoundsException if the specified bit index
* is negative.
* @require bitIndex >= 0
*
* @param bitIndex a non-negative integer
* @throws IndexOutOfBoundsException if bitIndex &lt; 0
*/
public void clear(int pos)
{
if (pos < 0)
throw new IndexOutOfBoundsException();
int bit = pos % 64;
int offset = pos / 64;
int offset = pos >>> 6;
ensure(offset);
bits[offset] &= ~(1L << bit);
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
// so we'll just let that be our exception.
bits[offset] &= ~(1L << pos);
}
/**
* Sets the bits between from (inclusive) and to (exclusive) to false.
*
* @param from the start range (inclusive)
* @param to the end range (exclusive)
* @throws IndexOutOfBoundsException if from &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
* class and contains the same elements. But it doesn't change when
* this bit set changes.
*
* @return the clone of this object.
*/
public Object clone()
{
BitSet bs = new BitSet(bits.length * 64);
System.arraycopy(bits, 0, bs.bits, 0, bits.length);
try
{
BitSet bs = (BitSet) super.clone();
bs.bits = (long[]) bits.clone();
return bs;
}
catch (CloneNotSupportedException e)
{
// Impossible to get here.
return null;
}
}
/**
* Returns true if the <code>obj</code> is a bit set that contains
* exactly the same elements as this bit set, otherwise false.
* @return true if obj equals this bit set.
*
* @param obj the object to compare to
* @return true if obj equals this bit set
*/
public boolean equals(Object obj)
{
@ -182,27 +269,109 @@ public class BitSet implements Cloneable, Serializable
return true;
}
/**
* Sets the bit at the index to the opposite value.
*
* @param index the index of the bit
* @throws IndexOutOfBoundsException if index is negative
* @since 1.4
*/
public void flip(int index)
{
int offset = index >>> 6;
ensure(offset);
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
// so we'll just let that be our exception.
bits[offset] ^= 1L << index;
}
/**
* Sets a range of bits to the opposite value.
*
* @param from the low index (inclusive)
* @param to the high index (exclusive)
* @throws IndexOutOfBoundsException if from &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
* set, otherwise false.
* @param bitIndex a non-negative integer
* @return the value of the bit at the specified index.
* @exception ArrayIndexOutOfBoundsException if the specified bit index
* is negative.
* @require bitIndex >= 0
*
* @param pos a non-negative integer
* @return the value of the bit at the specified index
* @throws IndexOutOfBoundsException if the index is negative
*/
public boolean get(int pos)
{
if (pos < 0)
throw new IndexOutOfBoundsException();
int bit = pos % 64;
int offset = pos / 64;
int offset = pos >>> 6;
if (offset >= bits.length)
return false;
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
// so we'll just let that be our exception.
return (bits[offset] & (1L << pos)) != 0;
}
return (bits[offset] & (1L << bit)) == 0 ? false : true;
/**
* Returns a new <code>BitSet</code> composed of a range of bits from
* this one.
*
* @param from the low index (inclusive)
* @param to the high index (exclusive)
* @throws IndexOutOfBoundsException if from &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;
}
/**
@ -233,20 +402,54 @@ public class BitSet implements Cloneable, Serializable
* </pre>
*
* Note that the hash code values changes, if the set is changed.
*
* @return the hash code value for this bit set.
*/
public int hashCode()
{
long h = 1234;
for (int i = bits.length - 1; i >= 0; --i)
h ^= bits[i] * (i + 1);
for (int i = bits.length; i > 0; )
h ^= i * bits[--i];
return (int) ((h >> 32) ^ h);
}
/**
* Returns true if the specified BitSet and this one share at least one
* common true bit.
*
* @param set the set to check for intersection
* @return true if the sets intersect
* @throws NullPointerException if set is null
* @since 1.4
*/
public boolean intersects(BitSet set)
{
int i = Math.min(bits.length, set.bits.length);
while (--i >= 0)
if ((bits[i] & set.bits[i]) != 0)
return true;
return false;
}
/**
* Returns true if this set contains no true bits.
*
* @return true if all bits are false
* @since 1.4
*/
public boolean isEmpty()
{
for (int i = bits.length - 1; i >= 0; i--)
if (bits[i] != 0)
return false;
return true;
}
/**
* Returns the logical number of bits actually used by this bit
* set. It returns the index of the highest set bit plus one.
* Note that this method doesn't return the number of set bits.
*
* @return the index of the highest set bit plus one.
*/
public int length()
@ -273,20 +476,88 @@ public class BitSet implements Cloneable, Serializable
return len;
}
/**
* Returns the index of the next false bit, from the specified bit
* (inclusive).
*
* @param from the start location
* @return the first false bit
* @throws IndexOutOfBoundsException if from is negative
* @since 1.4
*/
public int nextClearBit(int from)
{
int offset = from >>> 6;
long mask = 1L << from;
while (offset < bits.length)
{
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
// so we'll just let that be our exception.
long h = bits[offset];
do
{
if ((h & mask) == 0)
return from;
mask <<= 1;
from++;
}
while (mask != 0);
mask = 1;
offset++;
}
return from;
}
/**
* Returns the index of the next true bit, from the specified bit
* (inclusive). If there is none, -1 is returned. You can iterate over
* all true bits with this loop:<br>
* <pre>
* for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1))
* { // operate on i here }
* </pre>
*
* @param from the start location
* @return the first true bit, or -1
* @throws IndexOutOfBoundsException if from is negative
* @since 1.4
*/
public int nextSetBit(int from)
{
int offset = from >>> 6;
long mask = 1L << from;
while (offset < bits.length)
{
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
// so we'll just let that be our exception.
long h = bits[offset];
do
{
if ((h & mask) != 0)
return from;
mask <<= 1;
from++;
}
while (mask != 0);
mask = 1;
offset++;
}
return -1;
}
/**
* Performs the logical OR operation on this bit set and the
* given <code>set</code>. This means it builds the union
* of the two sets. The result is stored into this bit set, which
* grows as necessary.
* @param set the second bit set.
* @exception OutOfMemoryError if the current set can't grow.
* @require set != null
*
* @param bs the second bit set
* @throws NullPointerException if bs is null
*/
public void or(BitSet bs)
{
ensure(bs.bits.length - 1);
int i;
for (i = 0; i < bs.bits.length; ++i)
for (int i = bs.bits.length - 1; i >= 0; i--)
bits[i] |= bs.bits[i];
}
@ -295,25 +566,89 @@ public class BitSet implements Cloneable, Serializable
* the corresponding bit is set to true. If the index was already in
* the set, this method does nothing. The size of this structure
* is automatically increased as necessary.
* @param bitIndex a non-negative integer.
* @exception ArrayIndexOutOfBoundsException if the specified bit index
* is negative.
* @require bitIndex >= 0
*
* @param pos a non-negative integer.
* @throws IndexOutOfBoundsException if pos is negative
*/
public void set(int pos)
{
if (pos < 0)
throw new IndexOutOfBoundsException();
int bit = pos % 64;
int offset = pos / 64;
int offset = pos >>> 6;
ensure(offset);
bits[offset] |= 1L << bit;
// ArrayIndexOutOfBoundsException subclasses IndexOutOfBoundsException,
// so we'll just let that be our exception.
bits[offset] |= 1L << pos;
}
/**
* Sets the bit at the given index to the specified value. The size of
* this structure is automatically increased as necessary.
*
* @param index the position to set
* @param value the value to set it to
* @throws IndexOutOfBoundsException if index is negative
* @since 1.4
*/
public void set(int index, boolean value)
{
if (value)
set(index);
else
clear(index);
}
/**
* Sets the bits between from (inclusive) and to (exclusive) to true.
*
* @param from the start range (inclusive)
* @param to the end range (exclusive)
* @throws IndexOutOfBoundsException if from &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
* that this method doesn't return the number of set bits.
* @returns the number of bits currently used.
* that this method doesn't return the number of set bits, and that
* future requests for larger bits will make this automatically grow.
*
* @return the number of bits currently used.
*/
public int size()
{
@ -324,11 +659,12 @@ public class BitSet implements Cloneable, Serializable
* Returns the string representation of this bit set. This
* consists of a comma separated list of the integers in this set
* surrounded by curly braces. There is a space after each comma.
* A sample string is thus "{1, 3, 53}".
* @return the string representation.
*/
public String toString()
{
String r = "{";
StringBuffer r = new StringBuffer("{");
boolean first = true;
for (int i = 0; i < bits.length; ++i)
{
@ -341,15 +677,14 @@ public class BitSet implements Cloneable, Serializable
if ((word & bit) != 0)
{
if (! first)
r += ", ";
r += Integer.toString(64 * i + j);
r.append(", ");
r.append(64 * i + j);
first = false;
}
bit <<= 1;
}
}
return r += "}";
return r.append("}").toString();
}
/**
@ -358,31 +693,29 @@ public class BitSet implements Cloneable, Serializable
* remainder of the two sets (the elements that are in one set,
* but not in the other). The result is stored into this bit set,
* which grows as necessary.
* @param set the second bit set.
* @exception OutOfMemoryError if the current set can't grow.
* @require set != null
*
* @param bs the second bit set
* @throws NullPointerException if bs is null
*/
public void xor(BitSet bs)
{
ensure(bs.bits.length - 1);
int i;
for (i = 0; i < bs.bits.length; ++i)
for (int i = bs.bits.length - 1; i >= 0; i--)
bits[i] ^= bs.bits[i];
}
// Make sure the vector is big enough.
/**
* Make sure the vector is big enough.
*
* @param lastElt the size needed for the bits array
*/
private final void ensure(int lastElt)
{
if (lastElt + 1 > bits.length)
if (lastElt >= bits.length)
{
long[] nd = new long[lastElt + 1];
System.arraycopy(bits, 0, nd, 0, bits.length);
bits = nd;
}
}
// The actual bits.
long[] bits;
private static final long serialVersionUID = 7997698588986878753L;
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
/* Dictionary.java -- an abstract (and essentially worthless)
class which is Hashtable's superclass
Copyright (C) 1998 Free Software Foundation, Inc.
Copyright (C) 1998, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -35,49 +35,88 @@ package java.util;
* This is an abstract class which has really gone by the wayside.
* People at Javasoft are probably embarrassed by it. At this point,
* it might as well be an interface rather than a class, but it remains
* this poor, laugable skeleton for the sake of backwards compatibility.
* this poor, laughable skeleton for the sake of backwards compatibility.
* At any rate, this was what came before the <pre>Map</pre> interface
* in the Collections framework.
*
* @author Jon Zeppieri
* @author Eric Blake <ebb9@email.byu.edu>
* @see Map
* @see Hashtable
* @since 1.0
* @status updated to 1.4
*/
public abstract class Dictionary extends Object
{
/** returns an Enumeration of the values in this Dictionary */
/**
* Sole constructor (often called implicitly).
*/
public Dictionary()
{
}
/**
* Returns an Enumeration of the values in this Dictionary.
*
* @return an Enumeration of the values
* @see #keys()
*/
public abstract Enumeration elements();
/**
* returns the value associated with the supplied key, or null
* if no such value exists
* Returns the value associated with the supplied key, or null
* if no such value exists. Since Dictionaries are not allowed null keys
* or elements, a null result always means the key is not present.
*
* @param key the key to use to fetch the value
* @return the mapped value
* @throws NullPointerException if key is null
* @see #put(Object, Object)
*/
public abstract Object get(Object key);
/** returns true IFF there are no elements in this Dictionary (size() == 0) */
/**
* Returns true when there are no elements in this Dictionary.
*
* @return <code>size() == 0</code>
*/
public abstract boolean isEmpty();
/** returns an Enumeration of the keys in this Dictionary */
/**
* Returns an Enumeration of the keys in this Dictionary
*
* @return an Enumeration of the keys
* @see #elements()
*/
public abstract Enumeration keys();
/**
* inserts a new value into this Dictionary, located by the
* supllied key; note: Dictionary's subclasses (all 1 of them)
* do not support null keys or values (I can only assume this
* would have been more general)
* Inserts a new value into this Dictionary, located by the
* supplied key. Dictionary does not support null keys or values, so
* a null return can safely be interpreted as adding a new key.
*
* @param key the key which locates the value
* @param value the value to put into the Dictionary
* @return the previous value of the key, or null if there was none
* @throws NullPointerException if key or value is null
* @see #get(Object)
*/
public abstract Object put(Object key, Object value);
/**
* removes fro the Dictionary the value located by the given key
* Removes from the Dictionary the value located by the given key. A null
* return safely means that the key was not mapped in the Dictionary.
*
* @param key the key used to locate the value to be removed
* @return the value associated with the removed key
* @throws NullPointerException if key is null
*/
public abstract Object remove(Object key);
/** returns the number of values currently in this Dictionary */
/**
* Returns the number of values currently in this Dictionary.
*
* @return the number of keys in the Dictionary
*/
public abstract int size();
}

View file

@ -53,14 +53,16 @@ import java.io.ObjectOutputStream;
* <p>
*
* Under ideal circumstances (no collisions), HashMap offers O(1)
* performance on most operations (<pre>containsValue()</pre> is,
* performance on most operations (<code>containsValue()</code> is,
* of course, O(n)). In the worst case (all keys map to the same
* hash code -- very unlikely), most operations are O(n).
* <p>
*
* HashMap is part of the JDK1.2 Collections API. It differs from
* Hashtable in that it accepts the null key and null values, and it
* does not support "Enumeration views."
* does not support "Enumeration views." Also, it is not synchronized;
* if you plan to use it in multiple threads, consider using:<br>
* <code>Map m = Collections.synchronizedMap(new HashMap(...));</code>
* <p>
*
* The iterators are <i>fail-fast</i>, meaning that any structural
@ -81,6 +83,7 @@ import java.io.ObjectOutputStream;
* @see IdentityHashMap
* @see Hashtable
* @since 1.2
* @status updated to 1.4
*/
public class HashMap extends AbstractMap
implements Map, Cloneable, Serializable
@ -88,19 +91,16 @@ public class HashMap extends AbstractMap
/**
* Default number of buckets. This is the value the JDK 1.3 uses. Some
* early documentation specified this value as 101. That is incorrect.
* Package visible for use by HashSet.
*/
static final int DEFAULT_CAPACITY = 11;
/**
* The default load factor; this is explicitly specified by the spec.
* Package visible for use by HashSet.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/** "enum" of iterator types. */
static final int KEYS = 0,
VALUES = 1,
ENTRIES = 2;
/**
* Compatible with JDK 1.2.
*/
@ -108,41 +108,54 @@ public class HashMap extends AbstractMap
/**
* The rounded product of the capacity and the load factor; when the number
* of elements exceeds the threshold, the HashMap calls <pre>rehash()</pre>.
* @serial
* of elements exceeds the threshold, the HashMap calls
* <code>rehash()</code>.
* @serial the threshold for rehashing
*/
int threshold;
private int threshold;
/**
* Load factor of this HashMap: used in computing the threshold.
* @serial
* Package visible for use by HashSet.
* @serial the load factor
*/
final float loadFactor;
/**
* Array containing the actual key-value mappings.
* Package visible for use by nested and subclasses.
*/
transient HashEntry[] buckets;
/**
* Counts the number of modifications this HashMap has undergone, used
* by Iterators to know when to throw ConcurrentModificationExceptions.
* Package visible for use by nested and subclasses.
*/
transient int modCount;
/**
* The size of this HashMap: denotes the number of key-value pairs.
* Package visible for use by nested and subclasses.
*/
transient int size;
/**
* Class to represent an entry in the hash table. Holds a single key-value
* pair. This is extended again in LinkedHashMap. See {@link clone()}
* for why this must be Cloneable.
* The cache for {@link #entrySet()}.
*/
static class HashEntry extends BasicMapEntry implements Cloneable
private transient Set entries;
/**
* Class to represent an entry in the hash table. Holds a single key-value
* pair. Package visible for use by subclass.
*
* @author Eric Blake <ebb9@email.byu.edu>
*/
static class HashEntry extends BasicMapEntry
{
/** The next entry in the linked list. */
/**
* The next entry in the linked list. Package visible for use by subclass.
*/
HashEntry next;
/**
@ -158,7 +171,8 @@ public class HashMap extends AbstractMap
/**
* Called when this entry is removed from the map. This version simply
* returns the value, but in LinkedHashMap, it must also do bookkeeping.
* @return the value of this key as it is removed.
*
* @return the value of this key as it is removed
*/
Object cleanup()
{
@ -182,9 +196,8 @@ public class HashMap extends AbstractMap
*
* Every element in Map m will be put into this new HashMap.
*
* @param m a Map whose key / value pairs will be put into
* the new HashMap. <b>NOTE: key / value pairs
* are not cloned in this constructor.</b>
* @param m a Map whose key / value pairs will be put into the new HashMap.
* <b>NOTE: key / value pairs are not cloned in this constructor.</b>
* @throws NullPointerException if m is null
*/
public HashMap(Map m)
@ -197,8 +210,8 @@ public class HashMap extends AbstractMap
* Construct a new HashMap with a specific inital capacity and
* default load factor of 0.75.
*
* @param initialCapacity the initial capacity of this HashMap (>=0)
* @throws IllegalArgumentException if (initialCapacity < 0)
* @param initialCapacity the initial capacity of this HashMap (&gt;=0)
* @throws IllegalArgumentException if (initialCapacity &lt; 0)
*/
public HashMap(int initialCapacity)
{
@ -208,10 +221,10 @@ public class HashMap extends AbstractMap
/**
* Construct a new HashMap with a specific inital capacity and load factor.
*
* @param initialCapacity the initial capacity (>=0)
* @param loadFactor the load factor (>0, not NaN)
* @throws IllegalArgumentException if (initialCapacity < 0) ||
* ! (loadFactor > 0.0)
* @param initialCapacity the initial capacity (&gt;=0)
* @param loadFactor the load factor (&gt; 0, not NaN)
* @throws IllegalArgumentException if (initialCapacity &lt; 0) ||
* ! (loadFactor &gt; 0.0)
*/
public HashMap(int initialCapacity, float loadFactor)
{
@ -229,7 +242,8 @@ public class HashMap extends AbstractMap
}
/**
* Returns the number of kay-value mappings currently in this Map
* Returns the number of kay-value mappings currently in this Map.
*
* @return the size
*/
public int size()
@ -238,7 +252,8 @@ public class HashMap extends AbstractMap
}
/**
* Returns true if there are no key-value mappings currently in this Map
* Returns true if there are no key-value mappings currently in this Map.
*
* @return <code>size() == 0</code>
*/
public boolean isEmpty()
@ -246,52 +261,9 @@ public class HashMap extends AbstractMap
return size == 0;
}
/**
* Returns true if this HashMap contains a value <pre>o</pre>, such that
* <pre>o.equals(value)</pre>.
*
* @param value the value to search for in this HashMap
* @return true if at least one key maps to the value
*/
public boolean containsValue(Object value)
{
for (int i = buckets.length - 1; i >= 0; i--)
{
HashEntry e = buckets[i];
while (e != null)
{
if (value == null ? e.value == null : value.equals(e.value))
return true;
e = e.next;
}
}
return false;
}
/**
* Returns true if the supplied object <pre>equals()</pre> a key
* in this HashMap.
*
* @param key the key to search for in this HashMap
* @return true if the key is in the table
* @see #containsValue(Object)
*/
public boolean containsKey(Object key)
{
int idx = hash(key);
HashEntry e = buckets[idx];
while (e != null)
{
if (key == null ? e.key == null : key.equals(e.key))
return true;
e = e.next;
}
return false;
}
/**
* Return the value in this HashMap associated with the supplied key,
* or <pre>null</pre> if the key maps to nothing. NOTE: Since the value
* or <code>null</code> if the key maps to nothing. NOTE: Since the value
* could also be null, you must use containsKey to see if this key
* actually maps to something.
*
@ -306,13 +278,34 @@ public class HashMap extends AbstractMap
HashEntry e = buckets[idx];
while (e != null)
{
if (key == null ? e.key == null : key.equals(e.key))
if (equals(key, e.key))
return e.value;
e = e.next;
}
return null;
}
/**
* Returns true if the supplied object <code>equals()</code> a key
* in this HashMap.
*
* @param key the key to search for in this HashMap
* @return true if the key is in the table
* @see #containsValue(Object)
*/
public boolean containsKey(Object key)
{
int idx = hash(key);
HashEntry e = buckets[idx];
while (e != null)
{
if (equals(key, e.key))
return true;
e = e.next;
}
return false;
}
/**
* Puts the supplied value into the Map, mapped by the supplied key.
* The value may be retrieved by any object which <code>equals()</code>
@ -328,13 +321,12 @@ public class HashMap extends AbstractMap
*/
public Object put(Object key, Object value)
{
modCount++;
int idx = hash(key);
HashEntry e = buckets[idx];
while (e != null)
{
if (key == null ? e.key == null : key.equals(e.key))
if (equals(key, e.key))
// Must use this method for necessary bookkeeping in LinkedHashMap.
return e.setValue(value);
else
@ -342,6 +334,7 @@ public class HashMap extends AbstractMap
}
// At this point, we know we need to add a new entry.
modCount++;
if (++size > threshold)
{
rehash();
@ -354,59 +347,6 @@ public class HashMap extends AbstractMap
return null;
}
/**
* Helper method for put, that creates and adds a new Entry. This is
* overridden in LinkedHashMap for bookkeeping purposes.
*
* @param key the key of the new Entry
* @param value the value
* @param idx the index in buckets where the new Entry belongs
* @param callRemove Whether to call the removeEldestEntry method.
* @see #put(Object, Object)
*/
void addEntry(Object key, Object value, int idx, boolean callRemove)
{
HashEntry e = new HashEntry(key, value);
e.next = buckets[idx];
buckets[idx] = e;
}
/**
* Removes from the HashMap and returns the value which is mapped by the
* supplied key. If the key maps to nothing, then the HashMap remains
* unchanged, and <pre>null</pre> is returned. NOTE: Since the value
* could also be null, you must use containsKey to see if you are
* actually removing a mapping.
*
* @param key the key used to locate the value to remove
* @return whatever the key mapped to, if present
*/
public Object remove(Object key)
{
modCount++;
int idx = hash(key);
HashEntry e = buckets[idx];
HashEntry last = null;
while (e != null)
{
if (key == null ? e.key == null : key.equals(e.key))
{
if (last == null)
buckets[idx] = e.next;
else
last.next = e.next;
size--;
// Method call necessary for LinkedHashMap to work correctly.
return e.cleanup();
}
last = e;
e = e.next;
}
return null;
}
/**
* Copies all elements of the given map into this hashtable. If this table
* already has a mapping for a key, the new mapping replaces the current
@ -434,15 +374,76 @@ public class HashMap extends AbstractMap
}
}
/**
* Removes from the HashMap and returns the value which is mapped by the
* supplied key. If the key maps to nothing, then the HashMap remains
* unchanged, and <code>null</code> is returned. NOTE: Since the value
* could also be null, you must use containsKey to see if you are
* actually removing a mapping.
*
* @param key the key used to locate the value to remove
* @return whatever the key mapped to, if present
*/
public Object remove(Object key)
{
int idx = hash(key);
HashEntry e = buckets[idx];
HashEntry last = null;
while (e != null)
{
if (equals(key, e.key))
{
modCount++;
if (last == null)
buckets[idx] = e.next;
else
last.next = e.next;
size--;
// Method call necessary for LinkedHashMap to work correctly.
return e.cleanup();
}
last = e;
e = e.next;
}
return null;
}
/**
* Clears the Map so it has no keys. This is O(1).
*/
public void clear()
{
if (size != 0)
{
modCount++;
Arrays.fill(buckets, null);
size = 0;
}
}
/**
* Returns true if this HashMap contains a value <code>o</code>, such that
* <code>o.equals(value)</code>.
*
* @param value the value to search for in this HashMap
* @return true if at least one key maps to the value
* @see containsKey(Object)
*/
public boolean containsValue(Object value)
{
for (int i = buckets.length - 1; i >= 0; i--)
{
HashEntry e = buckets[i];
while (e != null)
{
if (equals(value, e.value))
return true;
e = e.next;
}
}
return false;
}
/**
* Returns a shallow clone of this HashMap. The Map itself is cloned,
@ -463,6 +464,8 @@ public class HashMap extends AbstractMap
}
copy.buckets = new HashEntry[buckets.length];
copy.putAllInternal(this);
// Clear the entry cache. AbstractMap.clone() does the others.
copy.entries = null;
return copy;
}
@ -477,9 +480,10 @@ public class HashMap extends AbstractMap
*/
public Set keySet()
{
// Create an AbstractSet with custom implementations of those methods that
// can be overridden easily and efficiently.
return new AbstractSet()
if (keys == null)
// Create an AbstractSet with custom implementations of those methods
// that can be overridden easily and efficiently.
keys = new AbstractSet()
{
public int size()
{
@ -499,19 +503,20 @@ public class HashMap extends AbstractMap
public boolean contains(Object o)
{
return HashMap.this.containsKey(o);
return containsKey(o);
}
public boolean remove(Object o)
{
// Test against the size of the HashMap to determine if anything
// really got removed. This is necessary because the return value of
// HashMap.remove() is ambiguous in the null case.
// really got removed. This is neccessary because the return value
// of HashMap.remove() is ambiguous in the null case.
int oldsize = size;
HashMap.this.remove(o);
return (oldsize != size);
return oldsize != size;
}
};
return keys;
}
/**
@ -526,9 +531,10 @@ public class HashMap extends AbstractMap
*/
public Collection values()
{
if (values == null)
// We don't bother overriding many of the optional methods, as doing so
// wouldn't provide any significant performance advantage.
return new AbstractCollection()
values = new AbstractCollection()
{
public int size()
{
@ -546,13 +552,13 @@ public class HashMap extends AbstractMap
HashMap.this.clear();
}
};
return values;
}
/**
* Returns a "set view" of this HashMap's entries. The set is backed by
* the HashMap, so changes in one show up in the other. The set supports
* element removal, but not element addition.
* <p>
* element removal, but not element addition.<p>
*
* Note that the iterators for all three views, from keySet(), entrySet(),
* and values(), traverse the HashMap in the same sequence.
@ -564,9 +570,10 @@ public class HashMap extends AbstractMap
*/
public Set entrySet()
{
// Create an AbstractSet with custom implementations of those methods that
// can be overridden easily and efficiently.
return new AbstractSet()
if (entries == null)
// Create an AbstractSet with custom implementations of those methods
// that can be overridden easily and efficiently.
entries = new AbstractSet()
{
public int size()
{
@ -600,17 +607,25 @@ public class HashMap extends AbstractMap
return false;
}
};
return entries;
}
/** Helper method that returns an index in the buckets array for `key;
* based on its hashCode().
/**
* Helper method for put, that creates and adds a new Entry. This is
* overridden in LinkedHashMap for bookkeeping purposes.
*
* @param key the key
* @return the bucket number
* @param key the key of the new Entry
* @param value the value
* @param idx the index in buckets where the new Entry belongs
* @param callRemove whether to call the removeEldestEntry method
* @see #put(Object, Object)
*/
int hash(Object key)
void addEntry(Object key, Object value, int idx, boolean callRemove)
{
return (key == null) ? 0 : Math.abs(key.hashCode() % buckets.length);
HashEntry e = new HashEntry(key, value);
e.next = buckets[idx];
buckets[idx] = e;
}
/**
@ -637,6 +652,52 @@ public class HashMap extends AbstractMap
return null;
}
/**
* Helper method that returns an index in the buckets array for `key'
* based on its hashCode(). Package visible for use by subclasses.
*
* @param key the key
* @return the bucket number
*/
final int hash(Object key)
{
return key == null ? 0 : Math.abs(key.hashCode() % buckets.length);
}
/**
* Generates a parameterized iterator. Must be overrideable, since
* LinkedHashMap iterates in a different order.
*
* @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
* @return the appropriate iterator
*/
Iterator iterator(int type)
{
return new HashIterator(type);
}
/**
* A simplified, more efficient internal implementation of putAll(). The
* Map constructor and clone() should not call putAll or put, in order to
* be compatible with the JDK implementation with respect to subclasses.
*
* @param m the map to initialize this from
*/
void putAllInternal(Map m)
{
Iterator itr = m.entrySet().iterator();
int msize = m.size();
this.size = msize;
for (; msize > 0; msize--)
{
Map.Entry e = (Map.Entry) itr.next();
Object key = e.getKey();
int idx = hash(key);
addEntry(key, e.getValue(), idx, false);
}
}
/**
* Increases the size of the HashMap and rehashes all keys to new array
* indices; this is called when the addition of a new value would cause
@ -681,35 +742,6 @@ public class HashMap extends AbstractMap
}
}
/**
* Generates a parameterized iterator. Must be overrideable, since
* LinkedHashMap iterates in a different order.
* @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES}
* @return the appropriate iterator
*/
Iterator iterator(int type)
{
return new HashIterator(type);
}
/**
* A simplified, more efficient internal implementation of putAll(). The
* Map constructor and clone() should not call putAll or put, in order to
* be compatible with the JDK implementation with respect to subclasses.
*/
void putAllInternal(Map m)
{
Iterator itr = m.entrySet().iterator();
for (int msize = m.size(); msize > 0; msize--)
{
Map.Entry e = (Map.Entry) itr.next();
Object key = e.getKey();
int idx = hash(key);
addEntry(key, e.getValue(), idx, false);
}
}
/**
* Serializes this object to the given stream.
*
@ -757,9 +789,6 @@ public class HashMap extends AbstractMap
// Read and use capacity.
buckets = new HashEntry[s.readInt()];
int len = s.readInt();
// Already happens automatically.
// size = 0;
// modCount = 0;
// Read and use key/value pairs.
for ( ; len > 0; len--)
@ -773,29 +802,29 @@ public class HashMap extends AbstractMap
*
* @author Jon Zeppieri
*/
class HashIterator implements Iterator
private final class HashIterator implements Iterator
{
/**
* The type of this Iterator: {@link #KEYS}, {@link #VALUES},
* or {@link #ENTRIES}.
*/
final int type;
private final int type;
/**
* The number of modifications to the backing HashMap that we know about.
*/
int knownMod = modCount;
private int knownMod = modCount;
/** The number of elements remaining to be returned by next(). */
int count = size;
private int count = size;
/** Current index in the physical hash table. */
int idx = buckets.length;
private int idx = buckets.length;
/** The last Entry returned by a next() call. */
HashEntry last;
private HashEntry last;
/**
* The next entry that should be returned by next(). It is set to something
* if we're iterating through a bucket that contains multiple linked
* entries. It is null if next() needs to find a new bucket.
*/
HashEntry next;
private HashEntry next;
/**
* Construct a new HashIterator with the supplied type.
@ -840,14 +869,14 @@ public class HashMap extends AbstractMap
last = e;
if (type == VALUES)
return e.value;
else if (type == KEYS)
if (type == KEYS)
return e.key;
return e;
}
/**
* Removes from the backing HashMap the last element which was fetched
* with the <pre>next()</pre> method.
* with the <code>next()</code> method.
* @throws ConcurrentModificationException if the HashMap was modified
* @throws IllegalStateException if called when there is no last element
*/
@ -859,8 +888,8 @@ public class HashMap extends AbstractMap
throw new IllegalStateException();
HashMap.this.remove(last.key);
knownMod++;
last = null;
knownMod++;
}
}
}

View file

@ -1,5 +1,5 @@
/* HashSet.java -- a class providing a HashMap-backet Set
Copyright (C) 1998, 1999 Free Software Foundation, Inc.
/* HashSet.java -- a class providing a HashMap-backed Set
Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -33,87 +33,115 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* This class provides a HashMap-backed implementation of the
* Set interface.
*
* Each element in the Set is a key in the backing HashMap; each key
* maps to a static token, denoting that the key does, in fact, exist.
* This class provides a HashMap-backed implementation of the Set interface.
* <p>
*
* Most operations are O(1), assuming no hash collisions. In the worst
* case (where all hases collide), operations are O(n).
* case (where all hashes collide), operations are O(n). Setting the
* initial capacity too low will force many resizing operations, but
* setting the initial capacity too high (or loadfactor too low) leads
* to wasted memory and slower iteration.
* <p>
*
* HashSet is a part of the JDK1.2 Collections API.
* HashSet accepts the null key and null values. It is not synchronized,
* so if you need multi-threaded access, consider using:<br>
* <code>Set s = Collections.synchronizedSet(new HashSet(...));</code>
* <p>
*
* The iterators are <i>fail-fast</i>, meaning that any structural
* modification, except for <code>remove()</code> called on the iterator
* itself, cause the iterator to throw a
* {@link ConcurrentModificationException} rather than exhibit
* non-deterministic behavior.
*
* @author Jon Zeppieri
* @author Eric Blake <ebb9@email.byu.edu>
* @see Collection
* @see Set
* @see TreeSet
* @see Collections#synchronizedSet(Set)
* @see HashMap
* @see LinkedHashSet
* @since 1.2
* @status updated to 1.4
*/
public class HashSet extends AbstractSet
implements Set, Cloneable, Serializable
{
/** the HashMap which backs this Set */
transient HashMap map;
static final long serialVersionUID = -5024744406713321676L;
/**
* Compatible with JDK 1.2.
*/
private static final long serialVersionUID = -5024744406713321676L;
/**
* construct a new, empty HashSet whose backing HashMap has the default
* capacity and loadFacor
* The HashMap which backs this Set.
*/
private transient HashMap map;
/**
* Construct a new, empty HashSet whose backing HashMap has the default
* capacity (11) and loadFacor (0.75).
*/
public HashSet()
{
map = new HashMap();
this(HashMap.DEFAULT_CAPACITY, HashMap.DEFAULT_LOAD_FACTOR);
}
/**
* construct a new, empty HashSet whose backing HashMap has the supplied
* capacity and the default load factor
* Construct a new, empty HashSet whose backing HashMap has the supplied
* capacity and the default load factor (0.75).
*
* @param initialCapacity the initial capacity of the backing
* HashMap
* @param initialCapacity the initial capacity of the backing HashMap
* @throws IllegalArgumentException if the capacity is negative
*/
public HashSet(int initialCapacity)
{
map = new HashMap(initialCapacity);
this(initialCapacity, HashMap.DEFAULT_LOAD_FACTOR);
}
/**
* construct a new, empty HashSet whose backing HashMap has the supplied
* capacity and load factor
* Construct a new, empty HashSet whose backing HashMap has the supplied
* capacity and load factor.
*
* @param initialCapacity the initial capacity of the backing
* HashMap
* @param initialCapacity the initial capacity of the backing HashMap
* @param loadFactor the load factor of the backing HashMap
* @throws IllegalArgumentException if either argument is negative, or
* if loadFactor is POSITIVE_INFINITY or NaN
*/
public HashSet(int initialCapacity, float loadFactor)
{
map = new HashMap(initialCapacity, loadFactor);
map = init(initialCapacity, loadFactor);
}
/**
* construct a new HashSet with the same elements as are in the supplied
* collection (eliminating any duplicates, of course; the backing HashMap
* will have the default capacity and load factor
* Construct a new HashSet with the same elements as are in the supplied
* collection (eliminating any duplicates, of course). The backing storage
* has twice the size of the collection, or the default size of 11,
* whichever is greater; and the default load factor (0.75).
*
* @param c a collection containing the elements with
* which this set will be initialized
* @param c a collection of initial set elements
* @throws NullPointerException if c is null
*/
public HashSet(Collection c)
{
map = new HashMap();
this(Math.max(2 * c.size(), HashMap.DEFAULT_CAPACITY));
addAll(c);
}
/**
* adds the given Object to the set if it is not already in the Set,
* returns true if teh element was added, false otherwise
* Adds the given Object to the set if it is not already in the Set.
* This set permits a null element.
*
* @param o the Object to add to this Set
* @return true if the set did not already contain o
*/
public boolean add(Object o)
{
return (map.put(o, Boolean.TRUE) == null);
return map.put(o, "") == null;
}
/**
* empties this Set of all elements; this is a fast operation [O(1)]
* Empties this Set of all elements; this takes constant time.
*/
public void clear()
{
@ -121,8 +149,10 @@ public class HashSet extends AbstractSet
}
/**
* returns a shallow copy of this Set (the Set itself is cloned; its
* elements are not)
* Returns a shallow copy of this Set. The Set itself is cloned; its
* elements are not.
*
* @return a shallow clone of the set
*/
public Object clone()
{
@ -133,15 +163,17 @@ public class HashSet extends AbstractSet
}
catch (CloneNotSupportedException x)
{
// Impossible to get here.
}
copy.map = (HashMap) map.clone();
return copy;
}
/**
* returns true if the supplied element is in this Set, false otherwise
* Returns true if the supplied element is in this Set.
*
* @param o the Object whose presence in this Set we are testing for
* @param o the Object to look for
* @return true if it is in the set
*/
public boolean contains(Object o)
{
@ -149,25 +181,35 @@ public class HashSet extends AbstractSet
}
/**
* returns true if this set has no elements in it (size() == 0)
* Returns true if this set has no elements in it.
*
* @return <code>size() == 0</code>.
*/
public boolean isEmpty()
{
return map.isEmpty();
return map.size == 0;
}
/**
* returns an Iterator over the elements of this Set; the Iterator allows
* removal of elements
* Returns an Iterator over the elements of this Set, which visits the
* elements in no particular order. For this class, the Iterator allows
* removal of elements. The iterator is fail-fast, and will throw a
* ConcurrentModificationException if the set is modified externally.
*
* @return a set iterator
* @see ConcurrentModificationException
*/
public Iterator iterator()
{
return map.keySet().iterator();
// Avoid creating intermediate keySet() object by using non-public API.
return map.iterator(HashMap.KEYS);
}
/**
* removes the supplied Object from this Set if it is in the Set; returns
* true if an element was removed, false otherwise
* Removes the supplied Object from this Set if it is in the Set.
*
* @param o the object to remove
* @return true if an element was removed
*/
public boolean remove(Object o)
{
@ -175,18 +217,42 @@ public class HashSet extends AbstractSet
}
/**
* returns the number of elements in this Set
* Returns the number of elements in this Set (its cardinality).
*
* @return the size of the set
*/
public int size()
{
return map.size();
return map.size;
}
/** Serialize this Object in a manner which is binary-compatible with the
* JDK */
/**
* Helper method which initializes the backing Map. Overridden by
* LinkedHashSet for correct semantics.
*
* @param capacity the initial capacity
* @param load the initial load factor
* @return the backing HashMap
*/
HashMap init(int capacity, float load)
{
return new HashMap(capacity, load);
}
/**
* Serializes this object to the given stream.
*
* @param s the stream to write to
* @throws IOException if the underlying stream fails
* @serialData the <i>capacity</i> (int) and <i>loadFactor</i> (float)
* of the backing store, followed by the set size (int),
* then a listing of its elements (Object) in no order
*/
private void writeObject(ObjectOutputStream s) throws IOException
{
Iterator it = iterator();
s.defaultWriteObject();
// Avoid creating intermediate keySet() object by using non-public API.
Iterator it = map.iterator(HashMap.KEYS);
s.writeInt(map.buckets.length);
s.writeFloat(map.loadFactor);
s.writeInt(map.size);
@ -194,25 +260,23 @@ public class HashSet extends AbstractSet
s.writeObject(it.next());
}
/** Deserialize this Object in a manner which is binary-compatible with
* the JDK */
private void readObject(ObjectInputStream s) throws IOException,
ClassNotFoundException
/**
* Deserializes this object from the given stream.
*
* @param s the stream to read from
* @throws ClassNotFoundException if the underlying stream fails
* @throws IOException if the underlying stream fails
* @serialData the <i>capacity</i> (int) and <i>loadFactor</i> (float)
* of the backing store, followed by the set size (int),
* then a listing of its elements (Object) in no order
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
int i, size, capacity;
float loadFactor;
Object element;
s.defaultReadObject();
capacity = s.readInt();
loadFactor = s.readFloat();
size = s.readInt();
map = new HashMap(capacity, loadFactor);
for (i = 0; i < size; i++)
{
element = s.readObject();
map.put(element, Boolean.TRUE);
}
map = init(s.readInt(), s.readFloat());
for (int size = s.readInt(); size > 0; size--)
map.put(s.readObject(), "");
}
}

View file

@ -66,7 +66,9 @@ import java.io.ObjectOutputStream;
* Unlike HashMap, Hashtable does not accept `null' as a key value. Also,
* all accesses are synchronized: in a single thread environment, this is
* expensive, but in a multi-thread environment, this saves you the effort
* of extra synchronization.
* of extra synchronization. However, the old-style enumerators are not
* synchronized, because they can lead to unspecified behavior even if
* they were synchronized. You have been warned.
* <p>
*
* The iterators are <i>fail-fast</i>, meaning that any structural
@ -84,6 +86,7 @@ import java.io.ObjectOutputStream;
* @see IdentityHashMap
* @see LinkedHashMap
* @since 1.0
* @status updated to 1.4
*/
public class Hashtable extends Dictionary
implements Map, Cloneable, Serializable
@ -93,6 +96,12 @@ public class Hashtable extends Dictionary
*/
private static final int DEFAULT_CAPACITY = 11;
/** An "enum" of iterator types. */
// Package visible for use by nested classes.
static final int KEYS = 0,
VALUES = 1,
ENTRIES = 2;
/**
* The default load factor; this is explicitly specified by the spec.
*/
@ -106,39 +115,57 @@ public class Hashtable extends Dictionary
/**
* The rounded product of the capacity and the load factor; when the number
* of elements exceeds the threshold, the Hashtable calls
* <pre>rehash()</pre>.
* <code>rehash()</code>.
* @serial
*/
int threshold;
private int threshold;
/**
* Load factor of this Hashtable: used in computing the threshold.
* @serial
*/
final float loadFactor;
private final float loadFactor;
/**
* Array containing the actual key-value mappings.
*/
// Package visible for use by nested classes.
transient HashEntry[] buckets;
/**
* Counts the number of modifications this Hashtable has undergone, used
* by Iterators to know when to throw ConcurrentModificationExceptions.
*/
// Package visible for use by nested classes.
transient int modCount;
/**
* The size of this Hashtable: denotes the number of key-value pairs.
*/
// Package visible for use by nested classes.
transient int size;
/**
* The cache for {@link #keySet()}.
*/
private transient Set keys;
/**
* The cache for {@link #values()}.
*/
private transient Collection values;
/**
* The cache for {@link #entrySet()}.
*/
private transient Set entries;
/**
* Class to represent an entry in the hash table. Holds a single key-value
* pair. A Hashtable Entry is identical to a HashMap Entry, except that
* `null' is not allowed for keys and values.
*/
static class HashEntry extends BasicMapEntry
private static final class HashEntry extends BasicMapEntry
{
/** The next entry in the linked list. */
HashEntry next;
@ -159,7 +186,7 @@ public class Hashtable extends Dictionary
* @return the prior value
* @throws NullPointerException if <code>newVal</code> is null
*/
public final Object setValue(Object newVal)
public Object setValue(Object newVal)
{
if (newVal == null)
throw new NullPointerException();
@ -193,15 +220,15 @@ public class Hashtable extends Dictionary
public Hashtable(Map m)
{
this(Math.max(m.size() * 2, DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR);
putAll(m);
putAllInternal(m);
}
/**
* Construct a new Hashtable with a specific inital capacity and
* default load factor of 0.75.
*
* @param initialCapacity the initial capacity of this Hashtable (>=0)
* @throws IllegalArgumentException if (initialCapacity < 0)
* @param initialCapacity the initial capacity of this Hashtable (&gt;= 0)
* @throws IllegalArgumentException if (initialCapacity &lt; 0)
*/
public Hashtable(int initialCapacity)
{
@ -212,10 +239,10 @@ public class Hashtable extends Dictionary
* Construct a new Hashtable with a specific initial capacity and
* load factor.
*
* @param initialCapacity the initial capacity (>=0)
* @param loadFactor the load factor (>0, not NaN)
* @throws IllegalArgumentException if (initialCapacity < 0) ||
* ! (loadFactor > 0.0)
* @param initialCapacity the initial capacity (&gt;= 0)
* @param loadFactor the load factor (&gt; 0, not NaN)
* @throws IllegalArgumentException if (initialCapacity &lt; 0) ||
* ! (loadFactor &gt; 0.0)
*/
public Hashtable(int initialCapacity, float loadFactor)
{
@ -251,30 +278,36 @@ public class Hashtable extends Dictionary
}
/**
* Return an enumeration of the keys of this table.
* Return an enumeration of the keys of this table. There's no point
* in synchronizing this, as you have already been warned that the
* enumeration is not specified to be thread-safe.
*
* @return the keys
* @see #elements()
* @see #keySet()
*/
public synchronized Enumeration keys()
public Enumeration keys()
{
return new Enumerator(Enumerator.KEYS);
return new Enumerator(KEYS);
}
/**
* Return an enumeration of the values of this table.
* Return an enumeration of the values of this table. There's no point
* in synchronizing this, as you have already been warned that the
* enumeration is not specified to be thread-safe.
*
* @return the values
* @see #keys()
* @see #values()
*/
public synchronized Enumeration elements()
public Enumeration elements()
{
return new Enumerator(Enumerator.VALUES);
return new Enumerator(VALUES);
}
/**
* Returns true if this Hashtable contains a value <pre>o</pre>,
* such that <pre>o.equals(value)</pre>. This is the same as
* Returns true if this Hashtable contains a value <code>o</code>,
* such that <code>o.equals(value)</code>. This is the same as
* <code>containsValue()</code>, and is O(n).
* <p>
*
@ -284,22 +317,37 @@ public class Hashtable extends Dictionary
*
* @param value the value to search for in this Hashtable
* @return true if at least one key maps to the value
* @throws NullPointerException if <pre>value</pre> is null
* @throws NullPointerException if <code>value</code> is null
* @see #containsValue(Object)
* @see #containsKey(Object)
*/
public synchronized boolean contains(Object value)
{
// Check if value is null in case Hashtable is empty.
// Check if value is null.
if (value == null)
throw new NullPointerException();
return containsValue(value);
}
/**
* Returns true if this Hashtable contains a value <code>o</code>, such that
* <code>o.equals(value)</code>. This is the new API for the old
* <code>contains()</code>, except that it is forgiving of null.
*
* @param value the value to search for in this Hashtable
* @return true if at least one key maps to the value
* @see #contains(Object)
* @see #containsKey(Object)
* @since 1.2
*/
public boolean containsValue(Object value)
{
for (int i = buckets.length - 1; i >= 0; i--)
{
HashEntry e = buckets[i];
while (e != null)
{
if (value.equals(e.value))
if (AbstractCollection.equals(value, e.value))
return true;
e = e.next;
}
@ -308,24 +356,7 @@ public class Hashtable extends Dictionary
}
/**
* Returns true if this Hashtable contains a value <pre>o</pre>, such that
* <pre>o.equals(value)</pre>. This is the new API for the old
* <code>contains()</code>.
*
* @param value the value to search for in this Hashtable
* @return true if at least one key maps to the value
* @throws NullPointerException if <pre>value</pre> is null
* @see #contains(Object)
* @see #containsKey(Object)
* @since 1.2
*/
public boolean containsValue(Object value)
{
return contains(value);
}
/**
* Returns true if the supplied object <pre>equals()</pre> a key
* Returns true if the supplied object <code>equals()</code> a key
* in this Hashtable.
*
* @param key the key to search for in this Hashtable
@ -348,7 +379,7 @@ public class Hashtable extends Dictionary
/**
* Return the value in this Hashtable associated with the supplied key,
* or <pre>null</pre> if the key maps to nothing.
* or <code>null</code> if the key maps to nothing.
*
* @param key the key for which to fetch an associated value
* @return what the key maps to, if present
@ -383,7 +414,6 @@ public class Hashtable extends Dictionary
*/
public synchronized Object put(Object key, Object value)
{
modCount++;
int idx = hash(key);
HashEntry e = buckets[idx];
@ -407,6 +437,7 @@ public class Hashtable extends Dictionary
}
// At this point, we know we need to add a new entry.
modCount++;
if (++size > threshold)
{
rehash();
@ -425,15 +456,18 @@ public class Hashtable extends Dictionary
/**
* Removes from the table and returns the value which is mapped by the
* supplied key. If the key maps to nothing, then the table remains
* unchanged, and <pre>null</pre> is returned.
* unchanged, and <code>null</code> is returned.
* <b>NOTE:</b>Map.remove and Dictionary.remove disagree whether null
* is a valid parameter; at the moment, this implementation obeys Map.remove,
* and silently ignores null.
*
* @param key the key used to locate the value to remove
* @return whatever the key mapped to, if present
* @throws NullPointerException if key is null
*/
public synchronized Object remove(Object key)
{
modCount++;
if (key == null)
return null;
int idx = hash(key);
HashEntry e = buckets[idx];
HashEntry last = null;
@ -442,6 +476,7 @@ public class Hashtable extends Dictionary
{
if (key.equals(e.key))
{
modCount++;
if (last == null)
buckets[idx] = e.next;
else
@ -487,11 +522,14 @@ public class Hashtable extends Dictionary
* Clears the hashtable so it has no keys. This is O(1).
*/
public synchronized void clear()
{
if (size > 0)
{
modCount++;
Arrays.fill(buckets, null);
size = 0;
}
}
/**
* Returns a shallow clone of this Hashtable. The Map itself is cloned,
@ -511,36 +549,18 @@ public class Hashtable extends Dictionary
// This is impossible.
}
copy.buckets = new HashEntry[buckets.length];
for (int i = buckets.length - 1; i >= 0; i--)
{
HashEntry e = buckets[i];
HashEntry last = null;
while (e != null)
{
if (last == null)
{
last = new HashEntry(e.key, e.value);
copy.buckets[i] = last;
}
else
{
last.next = new HashEntry(e.key, e.value);
last = last.next;
}
e = e.next;
}
}
copy.putAllInternal(this);
// Clear the caches.
copy.keys = null;
copy.values = null;
copy.entries = null;
return copy;
}
/**
* Converts this Hashtable to a String, surrounded by braces (<pre>'{'</pre>
* and <pre>'}'</pre>), key/value pairs listed with an equals sign between,
* (<pre>'='</pre>), and pairs separated by comma and space
* (<pre>", "</pre>).
* <p>
* Converts this Hashtable to a String, surrounded by braces, and with
* key/value pairs listed with an equals sign between, separated by a
* comma and space. For example, <code>"{a=1, b=2}"</code>.<p>
*
* NOTE: if the <code>toString()</code> method of any key or value
* throws an exception, this will fail for the same reason.
@ -552,7 +572,7 @@ public class Hashtable extends Dictionary
// Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the
// unsynchronized HashIterator instead.
Iterator entries = new HashIterator(HashIterator.ENTRIES);
Iterator entries = new HashIterator(ENTRIES);
StringBuffer r = new StringBuffer("{");
for (int pos = size; pos > 0; pos--)
{
@ -568,9 +588,11 @@ public class Hashtable extends Dictionary
* Returns a "set view" of this Hashtable's keys. The set is backed by
* the hashtable, so changes in one show up in the other. The set supports
* element removal, but not element addition. The set is properly
* synchronized on the original hashtable. The set will throw a
* {@link NullPointerException} if null is passed to <code>contains</code>,
* <code>remove</code>, or related methods.
* synchronized on the original hashtable. Sun has not documented the
* proper interaction of null with this set, but has inconsistent behavior
* in the JDK. Therefore, in this implementation, contains, remove,
* containsAll, retainAll, removeAll, and equals just ignore a null key
* rather than throwing a {@link NullPointerException}.
*
* @return a set view of the keys
* @see #values()
@ -579,8 +601,10 @@ public class Hashtable extends Dictionary
*/
public Set keySet()
{
// Create a synchronized AbstractSet with custom implementations of those
// methods that can be overridden easily and efficiently.
if (keys == null)
{
// Create a synchronized AbstractSet with custom implementations of
// those methods that can be overridden easily and efficiently.
Set r = new AbstractSet()
{
public int size()
@ -590,7 +614,7 @@ public class Hashtable extends Dictionary
public Iterator iterator()
{
return new HashIterator(HashIterator.KEYS);
return new HashIterator(KEYS);
}
public void clear()
@ -600,29 +624,33 @@ public class Hashtable extends Dictionary
public boolean contains(Object o)
{
return Hashtable.this.containsKey(o);
if (o == null)
return false;
return containsKey(o);
}
public boolean remove(Object o)
{
return (Hashtable.this.remove(o) != null);
return Hashtable.this.remove(o) != null;
}
};
// We must specify the correct object to synchronize upon, hence the
// use of a non-public API
return new Collections.SynchronizedSet(this, r);
keys = new Collections.SynchronizedSet(this, r);
}
return keys;
}
/**
* Returns a "collection view" (or "bag view") of this Hashtable's values.
* The collection is backed by the hashtable, so changes in one show up
* in the other. The collection supports element removal, but not element
* addition. The collection is properly synchronized on the original
* hashtable. The collection will throw a {@link NullPointerException}
* if null is passed to <code>contains</code> or related methods, but not
* if passed to <code>remove</code> or related methods.
* hashtable. Sun has not documented the proper interaction of null with
* this set, but has inconsistent behavior in the JDK. Therefore, in this
* implementation, contains, remove, containsAll, retainAll, removeAll, and
* equals just ignore a null value rather than throwing a
* {@link NullPointerException}.
*
* @return a bag view of the values
* @see #keySet()
@ -630,6 +658,8 @@ public class Hashtable extends Dictionary
* @since 1.2
*/
public Collection values()
{
if (values == null)
{
// We don't bother overriding many of the optional methods, as doing so
// wouldn't provide any significant performance advantage.
@ -642,35 +672,32 @@ public class Hashtable extends Dictionary
public Iterator iterator()
{
return new HashIterator(HashIterator.VALUES);
return new HashIterator(VALUES);
}
public void clear()
{
Hashtable.this.clear();
}
// Override this so that we check for null
public boolean contains(Object o)
{
return Hashtable.this.contains(o);
}
};
// We must specify the correct object to synchronize upon, hence the
// use of a non-public API
return new Collections.SynchronizedCollection(this, r);
values = new Collections.SynchronizedCollection(this, r);
}
return values;
}
/**
* Returns a "set view" of this Hashtable's entries. The set is backed by
* the hashtable, so changes in one show up in the other. The set supports
* element removal, but not element addition. The set is properly
* synchronized on the original hashtable. The set will throw a
* {@link NullPointerException} if the Map.Entry passed to
* <code>contains</code>, <code>remove</code>, or related methods returns
* null for <code>getKey</code>, but not if the Map.Entry is null or
* returns null for <code>getValue</code>.
* synchronized on the original hashtable. Sun has not documented the
* proper interaction of null with this set, but has inconsistent behavior
* in the JDK. Therefore, in this implementation, contains, remove,
* containsAll, retainAll, removeAll, and equals just ignore a null entry,
* or an entry with a null key or value, rather than throwing a
* {@link NullPointerException}. However, calling entry.setValue(null)
* will fail.
* <p>
*
* Note that the iterators for all three views, from keySet(), entrySet(),
@ -684,8 +711,10 @@ public class Hashtable extends Dictionary
*/
public Set entrySet()
{
// Create an AbstractSet with custom implementations of those methods that
// can be overridden easily and efficiently.
if (entries == null)
{
// Create an AbstractSet with custom implementations of those methods
// that can be overridden easily and efficiently.
Set r = new AbstractSet()
{
public int size()
@ -695,7 +724,7 @@ public class Hashtable extends Dictionary
public Iterator iterator()
{
return new HashIterator(HashIterator.ENTRIES);
return new HashIterator(ENTRIES);
}
public void clear()
@ -719,14 +748,15 @@ public class Hashtable extends Dictionary
return false;
}
};
// We must specify the correct object to synchronize upon, hence the
// use of a non-public API
return new Collections.SynchronizedSet(this, r);
entries = new Collections.SynchronizedSet(this, r);
}
return entries;
}
/**
* Returns true if this Hashtable equals the supplied Object <pre>o</pre>.
* Returns true if this Hashtable equals the supplied Object <code>o</code>.
* As specified by Map, this is:
* <pre>
* (o instanceof Map) && entrySet().equals(((Map) o).entrySet());
@ -759,7 +789,7 @@ public class Hashtable extends Dictionary
// Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the
// unsynchronized HashIterator instead.
Iterator itr = new HashIterator(HashIterator.ENTRIES);
Iterator itr = new HashIterator(ENTRIES);
int hashcode = 0;
for (int pos = size; pos > 0; pos--)
hashcode += itr.next().hashCode();
@ -782,29 +812,55 @@ public class Hashtable extends Dictionary
/**
* Helper method for entrySet(), which matches both key and value
* simultaneously.
* simultaneously. Ignores null, as mentioned in entrySet().
*
* @param o the entry to match
* @return the matching entry, if found, or null
* @throws NullPointerException if me.getKey() returns null
* @see #entrySet()
*/
private HashEntry getEntry(Object o)
{
if (! (o instanceof Map.Entry))
return null;
Map.Entry me = (Map.Entry) o;
int idx = hash(me.getKey());
Object key = ((Map.Entry) o).getKey();
if (key == null)
return null;
int idx = hash(key);
HashEntry e = buckets[idx];
while (e != null)
{
if (e.equals(me))
if (o.equals(e))
return e;
e = e.next;
}
return null;
}
/**
* A simplified, more efficient internal implementation of putAll(). The
* Map constructor and clone() should not call putAll or put, in order to
* be compatible with the JDK implementation with respect to subclasses.
*
* @param m the map to initialize this from
*/
void putAllInternal(Map m)
{
Iterator itr = m.entrySet().iterator();
int msize = m.size();
this.size = msize;
for (; msize > 0; msize--)
{
Map.Entry e = (Map.Entry) itr.next();
Object key = e.getKey();
int idx = hash(key);
HashEntry he = new HashEntry(key, e.getValue());
he.next = buckets[idx];
buckets[idx] = he;
}
}
/**
* Increases the size of the Hashtable and rehashes all keys to new array
* indices; this is called when the addition of a new value would cause
@ -813,7 +869,8 @@ public class Hashtable extends Dictionary
* <p>
*
* This is not specified, but the new size is twice the current size plus
* one; this number is not always prime, unfortunately.
* one; this number is not always prime, unfortunately. This implementation
* is not synchronized, as it is only invoked from synchronized methods.
*/
protected void rehash()
{
@ -870,7 +927,7 @@ public class Hashtable extends Dictionary
// Since we are already synchronized, and entrySet().iterator()
// would repeatedly re-lock/release the monitor, we directly use the
// unsynchronized HashIterator instead.
Iterator it = new HashIterator(HashIterator.ENTRIES);
Iterator it = new HashIterator(ENTRIES);
while (it.hasNext())
{
HashEntry entry = (HashEntry) it.next();
@ -901,7 +958,8 @@ public class Hashtable extends Dictionary
int len = s.readInt();
// Read and use key/value pairs.
for ( ; len > 0; len--)
// TODO: should we be defensive programmers, and check for illegal nulls?
while (--len >= 0)
put(s.readObject(), s.readObject());
}
@ -916,13 +974,8 @@ public class Hashtable extends Dictionary
*
* @author Jon Zeppieri
*/
class HashIterator implements Iterator
private final class HashIterator implements Iterator
{
/** "enum" of iterator types. */
static final int KEYS = 0,
VALUES = 1,
ENTRIES = 2;
/**
* The type of this Iterator: {@link #KEYS}, {@link #VALUES},
* or {@link #ENTRIES}.
@ -988,14 +1041,14 @@ public class Hashtable extends Dictionary
last = e;
if (type == VALUES)
return e.value;
else if (type == KEYS)
if (type == KEYS)
return e.key;
return e;
}
/**
* Removes from the backing Hashtable the last element which was fetched
* with the <pre>next()</pre> method.
* with the <code>next()</code> method.
* @throws ConcurrentModificationException if the hashtable was modified
* @throws IllegalStateException if called when there is no last element
*/
@ -1007,10 +1060,10 @@ public class Hashtable extends Dictionary
throw new IllegalStateException();
Hashtable.this.remove(last.key);
knownMod++;
last = null;
knownMod++;
}
}
} // class HashIterator
/**
@ -1027,21 +1080,21 @@ public class Hashtable extends Dictionary
*
* @author Jon Zeppieri
*/
class Enumerator implements Enumeration
private final class Enumerator implements Enumeration
{
/** "enum" of iterator types. */
static final int KEYS = 0,
VALUES = 1;
/**
* The type of this Iterator: {@link #KEYS} or {@link #VALUES}.
*/
int type;
final int type;
/** The number of elements remaining to be returned by next(). */
int count = size;
/** Current index in the physical hash table. */
int idx;
/** The last Entry returned by nextEntry(). */
HashEntry last;
/** Entry which will be returned by the next nextElement() call. */
int idx = buckets.length;
/**
* Entry which will be returned by the next nextElement() call. It is
* set if we are iterating through a bucket with multiple entries, or null
* if we must look in the next bucket.
*/
HashEntry next;
/**
@ -1051,25 +1104,6 @@ public class Hashtable extends Dictionary
Enumerator(int type)
{
this.type = type;
this.idx = buckets.length;
}
/**
* Helper method to find the next entry.
* @return the next entry, or null
*/
private HashEntry nextEntry()
{
HashEntry e = null;
if (last != null)
e = last.next;
while (e == null && idx > 0)
e = buckets[--idx];
last = e;
return e;
}
/**
@ -1078,10 +1112,7 @@ public class Hashtable extends Dictionary
*/
public boolean hasMoreElements()
{
if (next != null)
return true;
next = nextEntry();
return next != null;
return count > 0;
}
/**
@ -1091,19 +1122,16 @@ public class Hashtable extends Dictionary
*/
public Object nextElement()
{
HashEntry e;
if (next != null)
{
e = next;
next = null;
}
else
e = nextEntry();
if (e == null)
if (count == 0)
throw new NoSuchElementException("Hashtable Enumerator");
if (type == VALUES)
return e.value;
return e.key;
}
count--;
HashEntry e = next;
while (e == null)
e = buckets[--idx];
next = e.next;
return type == VALUES ? e.value : e.key;
}
} // class Enumerator
}

File diff suppressed because it is too large Load diff

View file

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

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

View file

@ -1,5 +1,5 @@
/* LinkedList.java -- Linked list implementation of the List interface
Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -32,25 +32,50 @@ import java.io.ObjectInputStream;
import java.io.IOException;
import java.lang.reflect.Array;
// TO DO:
// ~ Doc comment for the class.
// ~ Doc comments for the non-list methods.
// ~ other general implementation notes.
/**
* Linked list implementation of the List interface.
* Linked list implementation of the List interface. In addition to the
* methods of the List interface, this class provides access to the first
* and last list elements in O(1) time for easy stack, queue, or double-ended
* queue (deque) creation. The list is doubly-linked, with traversal to a
* given index starting from the end closest to the element.<p>
*
* LinkedList is not synchronized, so if you need multi-threaded access,
* consider using:<br>
* <code>List l = Collections.synchronizedList(new LinkedList(...));</code>
* <p>
*
* The iterators are <i>fail-fast</i>, meaning that any structural
* modification, except for <code>remove()</code> called on the iterator
* itself, cause the iterator to throw a
* {@link ConcurrentModificationException} rather than exhibit
* non-deterministic behavior.
*
* @author Original author unknown
* @author Bryce McKinlay
* @author Eric Blake <ebb9@email.byu.edu>
* @see List
* @see ArrayList
* @see Vector
* @see Collections#synchronizedList(List)
* @since 1.2
* @status missing javadoc, but complete to 1.4
*/
public class LinkedList extends AbstractSequentialList
implements List, Cloneable, Serializable
{
static final long serialVersionUID = 876323262645176354L;
/**
* Compatible with JDK 1.2.
*/
private static final long serialVersionUID = 876323262645176354L;
/**
* An Entry containing the head (in the next field) and the tail (in the
* previous field) of the list. The data field is null. If the list is empty,
* both the head and the tail point to ends itself.
* The first element in the list.
*/
transient Entry first;
/**
* The last element in the list.
*/
transient Entry last;
/**
@ -61,17 +86,26 @@ public class LinkedList extends AbstractSequentialList
/**
* Class to represent an entry in the list. Holds a single element.
*/
private static class Entry
private static final class Entry
{
/** The element in the list. */
Object data;
/** The next list entry, null if this is last. */
Entry next;
/** The previous list entry, null if this is first. */
Entry previous;
/**
* Construct an entry.
* @param data the list element
*/
Entry(Object data)
{
this.data = data;
}
}
} // class Entry
/**
* Obtain the Entry at a given position in a list. This method of course
@ -82,7 +116,8 @@ public class LinkedList extends AbstractSequentialList
* For speed and flexibility, range checking is not done in this method:
* Incorrect values will be returned if (n < 0) or (n >= size).
*
* @param n the number of the entry to get.
* @param n the number of the entry to get
* @return the entry at position n
*/
private Entry getEntry(int n)
{
@ -92,28 +127,29 @@ public class LinkedList extends AbstractSequentialList
e = first;
// n less than size/2, iterate from start
while (n-- > 0)
{
e = e.next;
}
}
else
{
e = last;
// n greater than size/2, iterate from end
while (++n < size)
{
e = e.previous;
}
}
return e;
}
/** Remove an entry from the list. This will adjust size and deal with
* `first' and `last' appropriatly. It does not effect modCount, that is
* the responsibility of the caller. */
/**
* Remove an entry from the list. This will adjust size and deal with
* `first' and `last' appropriatly.
*
* @param e the entry to remove
*/
private void removeEntry(Entry e)
{
if (size == 1)
modCount++;
size--;
if (size == 0)
first = last = null;
else
{
@ -133,7 +169,32 @@ public class LinkedList extends AbstractSequentialList
e.previous.next = e.next;
}
}
size--;
}
/**
* Checks that the index is in the range of possible elements (inclusive).
*
* @param index the index to check
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size
*/
private void checkBoundsInclusive(int index)
{
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+ size);
}
/**
* Checks that the index is in the range of existing elements (exclusive).
*
* @param index the index to check
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size
*/
private void checkBoundsExclusive(int index)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
+ size);
}
/**
@ -141,24 +202,26 @@ public class LinkedList extends AbstractSequentialList
*/
public LinkedList()
{
super();
}
/**
* Create a linked list containing the elements, in order, of a given
* collection.
*
* @param c the collection to populate this list from.
* @param c the collection to populate this list from
* @throws NullPointerException if c is null
*/
public LinkedList(Collection c)
{
super();
// Note: addAll could be made slightly faster, but not enough so to justify
// re-implementing it from scratch. It is just a matter of a relatively
// small constant factor.
addAll(c);
}
/**
* Returns the first element in the list.
*
* @return the first list element
* @throws NoSuchElementException if the list is empty
*/
public Object getFirst()
{
if (size == 0)
@ -166,6 +229,12 @@ public class LinkedList extends AbstractSequentialList
return first.data;
}
/**
* Returns the last element in the list.
*
* @return the last list element
* @throws NoSuchElementException if the list is empty
*/
public Object getLast()
{
if (size == 0)
@ -173,12 +242,18 @@ public class LinkedList extends AbstractSequentialList
return last.data;
}
/**
* Remove and return the first element in the list.
*
* @return the former first element in the list
* @throws NoSuchElementException if the list is empty
*/
public Object removeFirst()
{
if (size == 0)
throw new NoSuchElementException();
size--;
modCount++;
size--;
Object r = first.data;
if (first.next != null)
@ -191,12 +266,18 @@ public class LinkedList extends AbstractSequentialList
return r;
}
/**
* Remove and return the last element in the list.
*
* @return the former last element in the list
* @throws NoSuchElementException if the list is empty
*/
public Object removeLast()
{
if (size == 0)
throw new NoSuchElementException();
size--;
modCount++;
size--;
Object r = last.data;
if (last.previous != null)
@ -209,11 +290,16 @@ public class LinkedList extends AbstractSequentialList
return r;
}
/**
* Insert an element at the first of the list.
*
* @param o the element to insert
*/
public void addFirst(Object o)
{
modCount++;
Entry e = new Entry(o);
modCount++;
if (size == 0)
first = last = e;
else
@ -225,14 +311,24 @@ public class LinkedList extends AbstractSequentialList
size++;
}
/**
* Insert an element at the last of the list.
*
* @param o the element to insert
*/
public void addLast(Object o)
{
modCount++;
addLastEntry(new Entry(o));
}
/**
* Inserts an element at the end of the list.
*
* @param e the entry to add
*/
private void addLastEntry(Entry e)
{
modCount++;
if (size == 0)
first = last = e;
else
@ -244,37 +340,60 @@ public class LinkedList extends AbstractSequentialList
size++;
}
/**
* Returns true if the list contains the given object. Comparison is done by
* <code>o == null ? e = null : o.equals(e)</code>.
*
* @param o the element to look for
* @return true if it is found
*/
public boolean contains(Object o)
{
Entry e = first;
while (e != null)
{
if (e.data == null ? o == null : o.equals(e.data))
if (equals(o, e.data))
return true;
e = e.next;
}
return false;
}
/**
* Returns the size of the list.
*
* @return the list size
*/
public int size()
{
return size;
}
/**
* Adds an element to the end of the list.
*
* @param e the entry to add
* @return true, as it always succeeds
*/
public boolean add(Object o)
{
modCount++;
addLastEntry(new Entry(o));
return true;
}
/**
* Removes the entry at the lowest index in the list that matches the given
* object, comparing by <code>o == null ? e = null : o.equals(e)</code>.
*
* @param o the object to remove
* @return true if an instance of the object was removed
*/
public boolean remove(Object o)
{
modCount++;
Entry e = first;
while (e != null)
{
if (e.data == null ? o == null : o.equals(e.data))
if (equals(o, e.data))
{
removeEntry(e);
return true;
@ -284,17 +403,33 @@ public class LinkedList extends AbstractSequentialList
return false;
}
/**
* Append the elements of the collection in iteration order to the end of
* this list. If this list is modified externally (for example, if this
* list is the collection), behavior is unspecified.
*
* @param c the collection to append
* @return true if the list was modified
* @throws NullPointerException if c is null
*/
public boolean addAll(Collection c)
{
return addAll(size, c);
}
/**
* Insert the elements of the collection in iteration order at the given
* index of this list. If this list is modified externally (for example,
* if this list is the collection), behavior is unspecified.
*
* @param c the collection to append
* @return true if the list was modified
* @throws NullPointerException if c is null
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
*/
public boolean addAll(int index, Collection c)
{
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
modCount++;
checkBoundsInclusive(index);
int csize = c.size();
if (csize == 0)
@ -303,8 +438,8 @@ public class LinkedList extends AbstractSequentialList
Iterator itr = c.iterator();
// Get the entries just before and after index. If index is at the start
// of the list, BEFORE is null. If index is at the end of thelist, AFTER is
// null. If the list is empty, both are null.
// of the list, BEFORE is null. If index is at the end of the list, AFTER
// is null. If the list is empty, both are null.
Entry after = null;
Entry before = null;
if (index != size)
@ -332,7 +467,10 @@ public class LinkedList extends AbstractSequentialList
prev.next = e;
prev = e;
}
// Link the new chain of entries into the list.
modCount++;
size += csize;
prev.next = after;
if (after != null)
after.previous = e;
@ -343,52 +481,68 @@ public class LinkedList extends AbstractSequentialList
before.next = firstNew;
else
first = firstNew;
size += csize;
return true;
}
/**
* Remove all elements from this list.
*/
public void clear()
{
if (size > 0)
{
modCount++;
first = null;
last = null;
size = 0;
}
public Object get(int index)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
Entry e = getEntry(index);
return e.data;
}
/**
* Return the element at index.
*
* @param index the place to look
* @return the element at index
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
*/
public Object get(int index)
{
checkBoundsExclusive(index);
return getEntry(index).data;
}
/**
* Replace the element at the given location in the list.
*
* @param index which index to change
* @param o the new element
* @return the prior element
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt;= size()
*/
public Object set(int index, Object o)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
checkBoundsExclusive(index);
Entry e = getEntry(index);
Object old = e.data;
e.data = o;
return old;
}
/**
* Inserts an element in the given position in the list.
*
* @param index where to insert the element
* @param o the element to insert
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
*/
public void add(int index, Object o)
{
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
modCount++;
addEntry(index, new Entry(o));
}
checkBoundsInclusive(index);
Entry e = new Entry(o);
private void addEntry(int index, Entry e)
{
if (index < size)
{
modCount++;
Entry after = getEntry(index);
e.next = after;
e.previous = after.previous;
@ -403,40 +557,56 @@ public class LinkedList extends AbstractSequentialList
addLastEntry(e);
}
/**
* Removes the element at the given position from the list.
*
* @param index the location of the element to remove
* @return the removed element
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
*/
public Object remove(int index)
{
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
modCount++;
checkBoundsExclusive(index);
Entry e = getEntry(index);
removeEntry(e);
return e.data;
}
/**
* Returns the first index where the element is located in the list, or -1.
*
* @param o the element to look for
* @return its position, or -1 if not found
*/
public int indexOf(Object o)
{
int index = 0;
Entry e = first;
while (e != null)
{
if (e.data == null ? o == null : o.equals(e.data))
if (equals(o, e.data))
return index;
++index;
index++;
e = e.next;
}
return -1;
}
/**
* Returns the last index where the element is located in the list, or -1.
*
* @param o the element to look for
* @return its position, or -1 if not found
*/
public int lastIndexOf(Object o)
{
int index = size - 1;
Entry e = last;
while (e != null)
{
if (e.data == null ? o == null : o.equals(e.data))
if (equals(o, e.data))
return index;
--index;
index--;
e = e.previous;
}
return -1;
@ -448,21 +618,20 @@ public class LinkedList extends AbstractSequentialList
* methods.
*
* @param index the index of the element to be returned by the first call to
* next(), or size() to be initially positioned at the end of the list.
* @exception IndexOutOfBoundsException if index < 0 || index > size().
* next(), or size() to be initially positioned at the end of the list
* @throws IndexOutOfBoundsException if index &lt; 0 || index &gt; size()
*/
public ListIterator listIterator(int index)
{
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size:" +
size);
checkBoundsInclusive(index);
return new LinkedListItr(index);
}
/**
* Create a shallow copy of this LinkedList.
* Create a shallow copy of this LinkedList (the elements are not cloned).
*
* @return an object of the same class as this object, containing the
* same elements in the same order.
* same elements in the same order
*/
public Object clone()
{
@ -479,6 +648,11 @@ public class LinkedList extends AbstractSequentialList
return copy;
}
/**
* Returns an array which contains the elements of the list in order.
*
* @return an array containing the list elements
*/
public Object[] toArray()
{
Object[] array = new Object[size];
@ -491,59 +665,102 @@ public class LinkedList extends AbstractSequentialList
return array;
}
public Object[] toArray(Object[] array)
/**
* Returns an Array whose component type is the runtime component type of
* the passed-in Array. The returned Array is populated with all of the
* elements in this LinkedList. If the passed-in Array is not large enough
* to store all of the elements in this List, a new Array will be created
* and returned; if the passed-in Array is <i>larger</i> than the size
* of this List, then size() index will be set to null.
*
* @param a the passed-in Array
* @return an array representation of this list
* @throws ArrayStoreException if the runtime type of a does not allow
* an element in this list
* @throws NullPointerException if a is null
*/
public Object[] toArray(Object[] a)
{
if (array.length < size)
array = (Object[]) Array.newInstance(array.getClass().getComponentType(),
size);
else if (array.length > size)
array[size] = null;
if (a.length < size)
a = (Object[]) Array.newInstance(a.getClass().getComponentType(), size);
else if (a.length > size)
a[size] = null;
Entry e = first;
for (int i = 0; i < size; i++)
{
array[i] = e.data;
a[i] = e.data;
e = e.next;
}
return array;
return a;
}
/**
* Serialize an object to a stream.
* @serialdata the size of the list (int), followed by all the elements
* (Object) in proper order.
* Serializes this object to the given stream.
*
* @param s the stream to write to
* @throws IOException if the underlying stream fails
* @serialData the size of the list (int), followed by all the elements
* (Object) in proper order
*/
private void writeObject(ObjectOutputStream s) throws IOException
{
s.defaultWriteObject();
s.writeInt(size);
Iterator itr = iterator();
for (int i = 0; i < size; i++)
s.writeObject(itr.next());
Entry e = first;
while (e != null)
{
s.writeObject(e.data);
e = e.next;
}
}
/**
* Deserialize an object from a stream.
* @serialdata the size of the list (int), followed by all the elements
* (Object) in proper order.
* Deserializes this object from the given stream.
*
* @param s the stream to read from
* @throws ClassNotFoundException if the underlying stream fails
* @throws IOException if the underlying stream fails
* @serialData the size of the list (int), followed by all the elements
* (Object) in proper order
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
int serialSize = s.readInt();
for (int i = 0; i < serialSize; i++)
s.defaultReadObject();
int i = s.readInt();
while (--i >= 0)
addLastEntry(new Entry(s.readObject()));
}
/** A ListIterator over the list. This class keeps track of its
/**
* A ListIterator over the list. This class keeps track of its
* position in the list and the two list entries it is between.
*
* @author Original author unknown
* @author Eric Blake <ebb9@email.byu.edu>
*/
class LinkedListItr implements ListIterator
private final class LinkedListItr implements ListIterator
{
int knownMod;
Entry next; // entry that will be returned by next().
Entry previous; // entry that will be returned by previous().
Entry lastReturned; // entry that will be affected by remove() or set().
int position; // index of `next'.
/** Number of modifications we know about. */
private int knownMod = modCount;
/** Entry that will be returned by next(). */
private Entry next;
/** Entry that will be returned by previous(). */
private Entry previous;
/** Entry that will be affected by remove() or set(). */
private Entry lastReturned;
/** Index of `next'. */
private int position;
/**
* Initialize the iterator.
*
* @param index the initial index
*/
LinkedListItr(int index)
{
if (index == size)
@ -557,39 +774,74 @@ public class LinkedList extends AbstractSequentialList
previous = next.previous;
}
position = index;
knownMod = modCount;
}
/**
* Checks for iterator consistency.
*
* @throws ConcurrentModificationException if the list was modified
*/
private void checkMod()
{
if (knownMod != modCount)
throw new ConcurrentModificationException();
}
/**
* Returns the index of the next element.
*
* @return the next index
* @throws ConcurrentModificationException if the list was modified
*/
public int nextIndex()
{
checkMod();
return position;
}
/**
* Returns the index of the previous element.
*
* @return the previous index
* @throws ConcurrentModificationException if the list was modified
*/
public int previousIndex()
{
checkMod();
return position - 1;
}
/**
* Returns true if more elements exist via next.
*
* @return true if next will succeed
* @throws ConcurrentModificationException if the list was modified
*/
public boolean hasNext()
{
checkMod();
return (next != null);
}
/**
* Returns true if more elements exist via previous.
*
* @return true if previous will succeed
* @throws ConcurrentModificationException if the list was modified
*/
public boolean hasPrevious()
{
checkMod();
return (previous != null);
}
/**
* Returns the next element.
*
* @return the next element
* @throws ConcurrentModificationException if the list was modified
* @throws NoSuchElementException if there is no next
*/
public Object next()
{
checkMod();
@ -601,6 +853,13 @@ public class LinkedList extends AbstractSequentialList
return lastReturned.data;
}
/**
* Returns the previous element.
*
* @return the previous element
* @throws ConcurrentModificationException if the list was modified
* @throws NoSuchElementException if there is no previous
*/
public Object previous()
{
checkMod();
@ -612,6 +871,12 @@ public class LinkedList extends AbstractSequentialList
return lastReturned.data;
}
/**
* Remove the most recently returned element from the list.
*
* @throws ConcurrentModificationException if the list was modified
* @throws IllegalStateException if there was no last element
*/
public void remove()
{
checkMod();
@ -625,18 +890,25 @@ public class LinkedList extends AbstractSequentialList
next = lastReturned.next;
previous = lastReturned.previous;
modCount++;
knownMod++;
removeEntry(lastReturned);
knownMod++;
lastReturned = null;
}
/**
* Adds an element between the previous and next, and advance to the next.
*
* @param o the element to add
* @throws ConcurrentModificationException if the list was modified
*/
public void add(Object o)
{
checkMod();
modCount++;
knownMod++;
size++;
position++;
Entry e = new Entry(o);
e.previous = previous;
e.next = next;
@ -647,19 +919,21 @@ public class LinkedList extends AbstractSequentialList
first = e;
if (next != null)
{
next.previous = e;
next = next.next;
}
else
last = e;
previous = e;
size++;
position++;
lastReturned = null;
}
/**
* Changes the contents of the element most recently returned.
*
* @param o the new element
* @throws ConcurrentModificationException if the list was modified
* @throws IllegalStateException if there was no last element
*/
public void set(Object o)
{
checkMod();

View file

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

View file

@ -32,24 +32,30 @@ package java.util;
* "The Java Language Specification", ISBN 0-201-63451-1
* plus online API docs for JDK 1.2 beta from http://www.javasoft.com.
* Status: Believed complete and correct
*/
/**
* Stack provides a Last In First Out (LIFO) data type, commonly known
* as a Stack.
*
* Stack itself extends Vector and provides the additional methods
* for stack manipulation (push, pop, peek).
* as a Stack. Stack itself extends Vector and provides the additional
* methods for stack manipulation (push, pop, peek). You can also seek for
* the 1-based position of an element on the stack.
*
* @author Warren Levy <warrenl@cygnus.com>
* @date August 20, 1998.
* @author Eric Blake <ebb9@email.byu.edu>
* @see List
* @see AbstractList
* @see LinkedList
* @since 1.0
* @status updated to 1.4
*/
public class Stack extends Vector
{
// Could use Vector methods internally for the following methods
// We could use Vector methods internally for the following methods,
// but have used Vector fields directly for efficiency (i.e. this
// often reduces out duplicate bounds checking).
/**
* Compatible with JDK 1.0+.
*/
private static final long serialVersionUID = 1224463164541339165L;
/**
@ -57,16 +63,15 @@ public class Stack extends Vector
*/
public Stack()
{
super();
}
/**
* Pushes an Object onto the top of the stack. This method is effectively
* the same as addElement(item)
* the same as addElement(item).
*
* @param item the Object to push onto the stack
* @returns the Object pushed onto the stack
* @see java.util.Vector#addElement(java.util.Object)
* @return the Object pushed onto the stack
* @see Vector#addElement(Object)
*/
public Object push(Object item)
{
@ -80,26 +85,29 @@ public class Stack extends Vector
/**
* Pops an item from the stack and returns it. The item popped is
* removed from the Stack
* removed from the Stack.
*
* @returns the Object popped from the stack
* @return the Object popped from the stack
* @throws EmptyStackException if the stack is empty
*/
public synchronized Object pop()
{
if (elementCount == 0)
throw new EmptyStackException();
modCount++;
Object obj = elementData[--elementCount];
// Set topmost element to null to assist the gc in cleanup
// Set topmost element to null to assist the gc in cleanup.
elementData[elementCount] = null;
return obj;
}
/**
* Returns the top Object on the stack without removing it
* Returns the top Object on the stack without removing it.
*
* @returns the top Object on the stack
* @return the top Object on the stack
* @throws EmptyStackException if the stack is empty
*/
public synchronized Object peek()
{
@ -110,11 +118,11 @@ public class Stack extends Vector
}
/**
* Tests if the stack is empty
* Tests if the stack is empty.
*
* @returns true if the stack contains no items, false otherwise
* @return true if the stack contains no items, false otherwise
*/
public boolean empty()
public synchronized boolean empty()
{
return elementCount == 0;
}
@ -122,18 +130,18 @@ public class Stack extends Vector
/**
* Returns the position of an Object on the stack, with the top
* most Object being at position 1, and each Object deeper in the
* stack at depth + 1
* stack at depth + 1.
*
* @param o The object to search for
* @returns The 1 based depth of the Object, or -1 if the Object
* is not on the stack.
* @return The 1 based depth of the Object, or -1 if the Object
* is not on the stack
*/
public synchronized int search(Object o)
{
for (int i = elementCount-1; i >=0; --i)
if (elementData[i].equals(o))
int i = elementCount;
while (--i >= 0)
if (equals(o, elementData[i]))
return elementCount - i;
return -1;
}
}

File diff suppressed because it is too large Load diff

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.
This file is part of GNU Classpath.
@ -33,30 +33,62 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* This class provides a TreeMap-backed implementation of the
* SortedSet interface.
* This class provides a TreeMap-backed implementation of the SortedSet
* interface. The elements will be sorted according to their <i>natural
* order</i>, or according to the provided <code>Comparator</code>.<p>
*
* Each element in the Set is a key in the backing TreeMap; each key
* maps to a static token, denoting that the key does, in fact, exist.
* Most operations are O(log n), but there is so much overhead that this
* makes small sets expensive. Note that the ordering must be <i>consistent
* with equals</i> to correctly implement the Set interface. If this
* condition is violated, the set is still well-behaved, but you may have
* suprising results when comparing it to other sets.<p>
*
* Most operations are O(log n).
* This implementation is not synchronized. If you need to share this between
* multiple threads, do something like:<br>
* <code>SortedSet s
* = Collections.synchronizedSortedSet(new TreeSet(...));</code><p>
*
* TreeSet is a part of the JDK1.2 Collections API.
* The iterators are <i>fail-fast</i>, meaning that any structural
* modification, except for <code>remove()</code> called on the iterator
* itself, cause the iterator to throw a
* <code>ConcurrentModificationException</code> rather than exhibit
* non-deterministic behavior.
*
* @author Jon Zeppieri
* @author Bryce McKinlay
* @author Eric Blake <ebb9@email.byu.edu>
* @see Collection
* @see Set
* @see HashSet
* @see LinkedHashSet
* @see Comparable
* @see Comparator
* @see Collections#synchronizedSortedSet(SortedSet)
* @see TreeMap
* @since 1.2
* @status updated to 1.4
*/
public class TreeSet extends AbstractSet
implements SortedSet, Cloneable, Serializable
{
/** The TreeMap which backs this Set */
transient SortedMap map;
/**
* Compatible with JDK 1.2.
*/
private static final long serialVersionUID = -2479143000061671589L;
static final long serialVersionUID = -2479143000061671589L;
/**
* The SortedMap which backs this Set.
*/
// Not final because of readObject. This will always be one of TreeMap or
// TreeMap.SubMap, which both extend AbstractMap.
private transient SortedMap map;
/**
* Construct a new TreeSet whose backing TreeMap using the "natural"
* ordering of keys.
* ordering of keys. Elements that are not mutually comparable will cause
* ClassCastExceptions down the road.
*
* @see Comparable
*/
public TreeSet()
{
@ -65,9 +97,10 @@ public class TreeSet extends AbstractSet
/**
* Construct a new TreeSet whose backing TreeMap uses the supplied
* Comparator.
* Comparator. Elements that are not mutually comparable will cause
* ClassCastExceptions down the road.
*
* @param oComparator the Comparator this Set will use
* @param comparator the Comparator this Set will use
*/
public TreeSet(Comparator comparator)
{
@ -77,10 +110,14 @@ public class TreeSet extends AbstractSet
/**
* Construct a new TreeSet whose backing TreeMap uses the "natural"
* orering of the keys and which contains all of the elements in the
* supplied Collection.
* supplied Collection. This runs in n*log(n) time.
*
* @param oCollection the new Set will be initialized with all
* @param collection the new Set will be initialized with all
* of the elements in this Collection
* @throws ClassCastException if the elements of the collection are not
* comparable
* @throws NullPointerException if the collection is null
* @see Comparable
*/
public TreeSet(Collection collection)
{
@ -93,54 +130,57 @@ public class TreeSet extends AbstractSet
* SortedSet and containing all of the elements in the supplied SortedSet.
* This constructor runs in linear time.
*
* @param sortedSet the new TreeSet will use this SortedSet's
* comparator and will initialize itself
* with all of the elements in this SortedSet
* @param sortedSet the new TreeSet will use this SortedSet's comparator
* and will initialize itself with all its elements
* @throws NullPointerException if sortedSet is null
*/
public TreeSet(SortedSet sortedSet)
{
TreeMap map = new TreeMap(sortedSet.comparator());
int i = 0;
map = new TreeMap(sortedSet.comparator());
Iterator itr = sortedSet.iterator();
map.putKeysLinear(itr, sortedSet.size());
this.map = map;
((TreeMap) map).putKeysLinear(itr, sortedSet.size());
}
/* This private constructor is used to implement the subSet() calls around
a backing TreeMap.SubMap. */
TreeSet(SortedMap backingMap)
/**
* This private constructor is used to implement the subSet() calls around
* a backing TreeMap.SubMap.
*
* @param backingMap the submap
*/
private TreeSet(SortedMap backingMap)
{
map = backingMap;
}
/**
* Adds the spplied Object to the Set if it is not already in the Set;
* returns true if the element is added, false otherwise
* returns true if the element is added, false otherwise.
*
* @param obj the Object to be added to this Set
* @throws ClassCastException if the element cannot be compared with objects
* already in the set
*/
public boolean add(Object obj)
{
return (map.put(obj, Boolean.TRUE) == null);
return map.put(obj, "") == null;
}
/**
* Adds all of the elements in the supplied Collection to this TreeSet.
*
* @param c All of the elements in this Collection
* will be added to the Set.
*
* @param c The collection to add
* @return true if the Set is altered, false otherwise
* @throws NullPointerException if c is null
* @throws ClassCastException if an element in c cannot be compared with
* objects already in the set
*/
public boolean addAll(Collection c)
{
boolean result = false;
int size = c.size();
int pos = c.size();
Iterator itr = c.iterator();
for (int i = 0; i < size; i++)
result |= (map.put(itr.next(), Boolean.TRUE) == null);
while (--pos >= 0)
result |= (map.put(itr.next(), "") == null);
return result;
}
@ -152,94 +192,75 @@ public class TreeSet extends AbstractSet
map.clear();
}
/** Returns a shallow copy of this Set. */
/**
* Returns a shallow copy of this Set. The elements are not cloned.
*
* @return the cloned set
*/
public Object clone()
{
TreeSet copy = null;
try
{
copy = (TreeSet) super.clone();
// Map may be either TreeMap or TreeMap.SubMap, hence the ugly casts.
copy.map = (SortedMap) ((AbstractMap) map).clone();
}
catch (CloneNotSupportedException x)
{
// Impossible result.
}
copy.map = (SortedMap) ((TreeMap) map).clone();
return copy;
}
/** Returns this Set's comparator */
/**
* Returns this Set's comparator.
*
* @return the comparator, or null if the set uses natural ordering
*/
public Comparator comparator()
{
return map.comparator();
}
/**
* Returns true if this Set contains the supplied Object,
* false otherwise
* Returns true if this Set contains the supplied Object, false otherwise.
*
* @param oObject the Object whose existence in the Set is
* being tested
* @param obj the Object to check for
* @return true if it is in the set
* @throws ClassCastException if obj cannot be compared with objects
* already in the set
*/
public boolean contains(Object obj)
{
return map.containsKey(obj);
}
/** Returns true if this Set has size 0, false otherwise */
public boolean isEmpty()
{
return map.isEmpty();
}
/** Returns the number of elements in this Set */
public int size()
{
return map.size();
}
/**
* If the supplied Object is in this Set, it is removed, and true is
* returned; otherwise, false is returned.
* Returns the first (by order) element in this Set.
*
* @param obj the Object we are attempting to remove
* from this Set
* @return the first element
* @throws NoSuchElementException if the set is empty
*/
public boolean remove(Object obj)
{
return (map.remove(obj) != null);
}
/** Returns the first (by order) element in this Set */
public Object first()
{
return map.firstKey();
}
/** Returns the last (by order) element in this Set */
public Object last()
{
return map.lastKey();
}
/**
* Returns a view of this Set including all elements in the interval
* [oFromElement, oToElement).
* Returns a view of this Set including all elements less than
* <code>to</code>. The returned set is backed by the original, so changes
* in one appear in the other. The subset will throw an
* {@link IllegalArgumentException} for any attempt to access or add an
* element beyond the specified cutoff. The returned set does not include
* the endpoint; if you want inclusion, pass the successor element.
*
* @param from the resultant view will contain all
* elements greater than or equal to this element
* @param to the resultant view will contain all
* elements less than this element
*/
public SortedSet subSet(Object from, Object to)
{
return new TreeSet(map.subMap(from, to));
}
/**
* Returns a view of this Set including all elements less than oToElement
*
* @param toElement the resultant view will contain all
* elements less than this element
* @param to the (exclusive) cutoff point
* @return a view of the set less than the cutoff
* @throws ClassCastException if <code>to</code> is not compatible with
* the comparator (or is not Comparable, for natural ordering)
* @throws NullPointerException if to is null, but the comparator does not
* tolerate null elements
*/
public SortedSet headSet(Object to)
{
@ -247,42 +268,138 @@ public class TreeSet extends AbstractSet
}
/**
* Returns a view of this Set including all elements greater than or
* equal to oFromElement.
* Returns true if this Set has size 0, false otherwise.
*
* @param from the resultant view will contain all
* elements greater than or equal to this element
* @return true if the set is empty
*/
public boolean isEmpty()
{
return map.isEmpty();
}
/**
* Returns in Iterator over the elements in this TreeSet, which traverses
* in ascending order.
*
* @return an iterator
*/
public Iterator iterator()
{
return map.keySet().iterator();
}
/**
* Returns the last (by order) element in this Set.
*
* @return the last element
* @throws NoSuchElementException if the set is empty
*/
public Object last()
{
return map.lastKey();
}
/**
* If the supplied Object is in this Set, it is removed, and true is
* returned; otherwise, false is returned.
*
* @param obj the Object to remove from this Set
* @return true if the set was modified
* @throws ClassCastException if obj cannot be compared to set elements
*/
public boolean remove(Object obj)
{
return map.remove(obj) != null;
}
/**
* Returns the number of elements in this Set
*
* @return the set size
*/
public int size()
{
return map.size();
}
/**
* Returns a view of this Set including all elements greater or equal to
* <code>from</code> and less than <code>to</code> (a half-open interval).
* The returned set is backed by the original, so changes in one appear in
* the other. The subset will throw an {@link IllegalArgumentException}
* for any attempt to access or add an element beyond the specified cutoffs.
* The returned set includes the low endpoint but not the high; if you want
* to reverse this behavior on either end, pass in the successor element.
*
* @param from the (inclusive) low cutoff point
* @param to the (exclusive) high cutoff point
* @return a view of the set between the cutoffs
* @throws ClassCastException if either cutoff is not compatible with
* the comparator (or is not Comparable, for natural ordering)
* @throws NullPointerException if from or to is null, but the comparator
* does not tolerate null elements
* @throws IllegalArgumentException if from is greater than to
*/
public SortedSet subSet(Object from, Object to)
{
return new TreeSet(map.subMap(from, to));
}
/**
* Returns a view of this Set including all elements greater or equal to
* <code>from</code>. The returned set is backed by the original, so
* changes in one appear in the other. The subset will throw an
* {@link IllegalArgumentException} for any attempt to access or add an
* element beyond the specified cutoff. The returned set includes the
* endpoint; if you want to exclude it, pass in the successor element.
*
* @param from the (inclusive) low cutoff point
* @return a view of the set above the cutoff
* @throws ClassCastException if <code>from</code> is not compatible with
* the comparator (or is not Comparable, for natural ordering)
* @throws NullPointerException if from is null, but the comparator
* does not tolerate null elements
*/
public SortedSet tailSet(Object from)
{
return new TreeSet(map.tailMap(from));
}
/** Returns in Iterator over the elements in this TreeSet */
public Iterator iterator()
{
return map.keySet().iterator();
}
private void writeObject(ObjectOutputStream out) throws IOException
/**
* Serializes this object to the given stream.
*
* @param s the stream to write to
* @throws IOException if the underlying stream fails
* @serialData the <i>comparator</i> (Object), followed by the set size
* (int), the the elements in sorted order (Object)
*/
private void writeObject(ObjectOutputStream s) throws IOException
{
s.defaultWriteObject();
Iterator itr = map.keySet().iterator();
int size = map.size();
out.writeObject(map.comparator());
out.writeInt(size);
for (int i = 0; i < size; i++)
out.writeObject(itr.next());
int pos = map.size();
s.writeObject(map.comparator());
s.writeInt(pos);
while (--pos >= 0)
s.writeObject(itr.next());
}
private void readObject(ObjectInputStream in)
/**
* Deserializes this object from the given stream.
*
* @param s the stream to read from
* @throws ClassNotFoundException if the underlying stream fails
* @throws IOException if the underlying stream fails
* @serialData the <i>comparator</i> (Object), followed by the set size
* (int), the the elements in sorted order (Object)
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
Comparator comparator = (Comparator) in.readObject();
int size = in.readInt();
TreeMap map = new TreeMap(comparator);
map.putFromObjStream(in, size, false);
this.map = map;
s.defaultReadObject();
Comparator comparator = (Comparator) s.readObject();
int size = s.readInt();
map = new TreeMap(comparator);
((TreeMap) map).putFromObjStream(s, size, false);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
/* java.util.WeakHashMap
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
/* java.util.WeakHashMap -- a hashtable that keeps only weak references
to its keys, allowing the virtual machine to reclaim them
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -26,6 +27,7 @@ executable file might be covered by the GNU General Public License. */
package java.util;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
@ -51,22 +53,26 @@ import java.lang.ref.ReferenceQueue;
* entry, that was in the set before, suddenly disappears. <br>
*
* A weak hash map is not meant for caches; use a normal map, with
* soft references as values instead. <br>
* soft references as values instead, or try {@link LinkedHashMap}. <br>
*
* The weak hash map supports null values and null keys. Null keys
* are never deleted from the map (except explictly of course).
* The weak hash map supports null values and null keys. The null key
* is never deleted from the map (except explictly of course).
* The performance of the methods are similar to that of a hash map. <br>
*
* The value object are strongly referenced by this table. So if a
* The value objects are strongly referenced by this table. So if a
* value object maintains a strong reference to the key (either direct
* or indirect) the key will never be removed from this map. According
* to Sun, this problem may be fixed in a future release. It is not
* possible to do it with the jdk 1.2 reference model, though.
*
* @since jdk1.2
* @author Jochen Hoenicke
* @author Eric Blake <ebb9@email.byu.edu>
* @see HashMap
* @see WeakReference */
* @see WeakReference
* @see LinkedHashMap
* @since 1.2
* @status updated to 1.4
*/
public class WeakHashMap extends AbstractMap implements Map
{
/**
@ -77,7 +83,7 @@ public class WeakHashMap extends AbstractMap implements Map
private static final int DEFAULT_CAPACITY = 11;
/**
* The default load factor of a HashMap
* The default load factor of a HashMap.
*/
private static final float DEFAULT_LOAD_FACTOR = 0.75F;
@ -85,18 +91,41 @@ public class WeakHashMap extends AbstractMap implements Map
* This is used instead of the key value <i>null</i>. It is needed
* to distinguish between an null key and a removed key.
*/
private static final Object NULL_KEY = new Object();
// Package visible for use by nested classes.
static final Object NULL_KEY = new Object()
{
/**
* Sets the hashCode to 0, since that's what null would map to.
* @return the hash code 0
*/
public int hashCode()
{
return 0;
}
/**
* Compares this key to the given object. Normally, an object should
* NEVER compare equal to null, but since we don't publicize NULL_VALUE,
* it saves bytecode to do so here.
* @return true iff o is this or null
*/
public boolean equals(Object o)
{
return null == o || this == o;
}
};
/**
* The reference queue where our buckets (which are WeakReferences) are
* registered to.
*/
private ReferenceQueue queue;
private final ReferenceQueue queue;
/**
* The number of entries in this hash map.
*/
private int size;
// Package visible for use by nested classes.
int size;
/**
* The load factor of this WeakHashMap. This is the maximum ratio of
@ -119,17 +148,20 @@ public class WeakHashMap extends AbstractMap implements Map
* by the garbage collection. Instead the iterators must make
* sure to have strong references to the entries they rely on.
*/
private int modCount;
// Package visible for use by nested classes.
int modCount;
/**
* The entry set. There is only one instance per hashmap, namely
* theEntrySet. Note that the entry set may silently shrink, just
* like the WeakHashMap.
*/
private class WeakEntrySet extends AbstractSet
private final class WeakEntrySet extends AbstractSet
{
/**
* Returns the size of this set.
*
* @return the set size
*/
public int size()
{
@ -138,6 +170,8 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Returns an iterator for all entries.
*
* @return an Entry iterator
*/
public Iterator iterator()
{
@ -155,7 +189,7 @@ public class WeakHashMap extends AbstractMap implements Map
* being removed under us, since the entry strongly refers
* to the key.
*/
WeakBucket.Entry lastEntry;
WeakBucket.WeakEntry lastEntry;
/**
* The entry that will be returned by the next
@ -166,11 +200,11 @@ public class WeakHashMap extends AbstractMap implements Map
* being removed under us, since the entry strongly refers
* to the key.
*/
WeakBucket.Entry nextEntry = findNext(null);
WeakBucket.WeakEntry nextEntry = findNext(null);
/**
* The known number of modification to the list, if it differs
* from the real number, we through an exception.
* from the real number, we throw an exception.
*/
int knownMod = modCount;
@ -178,12 +212,13 @@ public class WeakHashMap extends AbstractMap implements Map
* Check the known number of modification to the number of
* modifications of the table. If it differs from the real
* number, we throw an exception.
* @exception ConcurrentModificationException if the number
* @throws ConcurrentModificationException if the number
* of modifications doesn't match.
*/
private void checkMod()
{
/* This method will get inlined */
// This method will get inlined.
cleanQueue();
if (knownMod != modCount)
throw new ConcurrentModificationException();
}
@ -191,11 +226,11 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Get a strong reference to the next entry after
* lastBucket.
* @param lastBucket the previous bucket, or null if we should
* @param lastEntry the previous bucket, or null if we should
* get the first entry.
* @return the next entry.
*/
private WeakBucket.Entry findNext(WeakBucket.Entry lastEntry)
private WeakBucket.WeakEntry findNext(WeakBucket.WeakEntry lastEntry)
{
int slot;
WeakBucket nextBucket;
@ -214,48 +249,45 @@ public class WeakHashMap extends AbstractMap implements Map
{
while (nextBucket != null)
{
WeakBucket.Entry entry = nextBucket.getEntry();
WeakBucket.WeakEntry entry = nextBucket.getEntry();
if (entry != null)
/* This is the next entry */
// This is the next entry.
return entry;
/* entry was cleared, try next */
// Entry was cleared, try next.
nextBucket = nextBucket.next;
}
slot++;
if (slot == buckets.length)
/* No more buckets, we are through */
// No more buckets, we are through.
return null;
nextBucket = buckets[slot];
}
}
/**
* Checks if there are more entries.
* @return true, iff there are more elements.
* @exception IllegalModificationException if the hash map was
* @throws ConcurrentModificationException if the hash map was
* modified.
*/
public boolean hasNext()
{
cleanQueue();
checkMod();
return (nextEntry != null);
return nextEntry != null;
}
/**
* Returns the next entry.
* @return the next entry.
* @exception IllegalModificationException if the hash map was
* @throws ConcurrentModificationException if the hash map was
* modified.
* @exception NoSuchElementException if there is no entry.
* @throws NoSuchElementException if there is no entry.
*/
public Object next()
{
cleanQueue();
checkMod();
if (nextEntry == null)
throw new NoSuchElementException();
@ -267,21 +299,20 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Removes the last returned entry from this set. This will
* also remove the bucket of the underlying weak hash map.
* @exception IllegalModificationException if the hash map was
* @throws ConcurrentModificationException if the hash map was
* modified.
* @exception IllegalStateException if <code>next()</code> was
* @throws IllegalStateException if <code>next()</code> was
* never called or the element was already removed.
*/
public void remove()
{
cleanQueue();
checkMod();
if (lastEntry == null)
throw new IllegalStateException();
modCount++;
internalRemove(lastEntry.getBucket());
lastEntry = null;
modCount++;
knownMod = modCount;
knownMod++;
}
};
}
@ -293,7 +324,7 @@ public class WeakHashMap extends AbstractMap implements Map
* number. <br>
*
* It would be cleaner to have a WeakReference as field, instead of
* extending it, but if a weak reference get cleared, we only get
* extending it, but if a weak reference gets cleared, we only get
* the weak reference (by queue.poll) and wouldn't know where to
* look for this reference in the hashtable, to remove that entry.
*
@ -329,6 +360,7 @@ public class WeakHashMap extends AbstractMap implements Map
* Creates a new bucket for the given key/value pair and the specified
* slot.
* @param key the key
* @param queue the queue the weak reference belongs to
* @param value the value
* @param slot the slot. This must match the slot where this bucket
* will be enqueued.
@ -346,7 +378,7 @@ public class WeakHashMap extends AbstractMap implements Map
* current bucket. It also keeps a strong reference to the
* key; bad things may happen otherwise.
*/
class Entry implements Map.Entry
class WeakEntry implements Map.Entry
{
/**
* The strong ref to the key.
@ -355,14 +387,16 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Creates a new entry for the key.
* @param key the key
*/
public Entry(Object key)
public WeakEntry(Object key)
{
this.key = key;
}
/**
* Returns the underlying bucket.
* @return the owning bucket
*/
public WeakBucket getBucket()
{
@ -371,6 +405,7 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Returns the key.
* @return the key
*/
public Object getKey()
{
@ -379,6 +414,7 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Returns the value.
* @return the value
*/
public Object getValue()
{
@ -388,6 +424,8 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* This changes the value. This change takes place in
* the underlying hash map.
* @param newVal the new value
* @return the old value
*/
public Object setValue(Object newVal)
{
@ -398,50 +436,56 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* The hashCode as specified in the Entry interface.
* @return the hash code
*/
public int hashCode()
{
return (key == NULL_KEY ? 0 : key.hashCode())
^ (value == null ? 0 : value.hashCode());
return key.hashCode() ^ WeakHashMap.hashCode(value);
}
/**
* The equals method as specified in the Entry interface.
* @param o the object to compare to
* @return true iff o represents the same key/value pair
*/
public boolean equals(Object o)
{
if (o instanceof Map.Entry)
{
Map.Entry e = (Map.Entry) o;
return (key == NULL_KEY
? e.getKey() == null : key.equals(e.getKey()))
&& (value == null
? e.getValue() == null : value.equals(e.getValue()));
return key.equals(e.getKey())
&& WeakHashMap.equals(value, e.getValue());
}
return false;
}
public String toString()
{
return key + "=" + value;
}
}
/**
* This returns the entry stored in this bucket, or null, if the
* bucket got cleared in the mean time.
* @return the Entry for this bucket, if it exists
*/
Entry getEntry()
WeakEntry getEntry()
{
final Object key = this.get();
final Object key = get();
if (key == null)
return null;
return new Entry(key);
return new WeakEntry(key);
}
}
/**
* The entry set returned by <code>entrySet()</code>.
*/
private WeakEntrySet theEntrySet;
private final WeakEntrySet theEntrySet;
/**
* The hash buckets. This are linked lists.
* The hash buckets. These are linked lists.
*/
private WeakBucket[] buckets;
@ -458,6 +502,7 @@ public class WeakHashMap extends AbstractMap implements Map
* Creates a new weak hash map with default load factor and the given
* capacity.
* @param initialCapacity the initial capacity
* @throws IllegalArgumentException if initialCapacity is negative
*/
public WeakHashMap(int initialCapacity)
{
@ -469,10 +514,13 @@ public class WeakHashMap extends AbstractMap implements Map
* load factor.
* @param initialCapacity the initial capacity.
* @param loadFactor the load factor (see class description of HashMap).
* @throws IllegalArgumentException if initialCapacity is negative, or
* loadFactor is non-positive
*/
public WeakHashMap(int initialCapacity, float loadFactor)
{
if (initialCapacity < 0 || loadFactor <= 0 || loadFactor > 1)
// Check loadFactor for NaN as well.
if (initialCapacity < 0 || ! (loadFactor > 0))
throw new IllegalArgumentException();
this.loadFactor = loadFactor;
threshold = (int) (initialCapacity * loadFactor);
@ -482,7 +530,23 @@ public class WeakHashMap extends AbstractMap implements Map
}
/**
* simply hashes a non-null Object to its array index
* Construct a new WeakHashMap with the same mappings as the given map.
* The WeakHashMap has a default load factor of 0.75.
*
* @param m the map to copy
* @throws NullPointerException if m is null
* @since 1.3
*/
public WeakHashMap(Map m)
{
this(m.size(), DEFAULT_LOAD_FACTOR);
putAll(m);
}
/**
* Simply hashes a non-null Object to its array index.
* @param key the key to hash
* @return its slot number
*/
private int hash(Object key)
{
@ -498,7 +562,8 @@ public class WeakHashMap extends AbstractMap implements Map
* Currently the iterator maintains a strong reference to the key, so
* that is no problem.
*/
private void cleanQueue()
// Package visible for use by nested classes.
void cleanQueue()
{
Object bucket = queue.poll();
while (bucket != null)
@ -521,8 +586,7 @@ public class WeakHashMap extends AbstractMap implements Map
threshold = (int) (newsize * loadFactor);
buckets = new WeakBucket[newsize];
/* Now we have to insert the buckets again.
*/
// Now we have to insert the buckets again.
for (int i = 0; i < oldBuckets.length; i++)
{
WeakBucket bucket = oldBuckets[i];
@ -534,15 +598,15 @@ public class WeakHashMap extends AbstractMap implements Map
Object key = bucket.get();
if (key == null)
{
/* This bucket should be removed; it is probably
* already on the reference queue. We don't insert it
* at all, and mark it as cleared. */
// This bucket should be removed; it is probably
// already on the reference queue. We don't insert it
// at all, and mark it as cleared.
bucket.slot = -1;
size--;
}
else
{
/* add this bucket to its new slot */
// Add this bucket to its new slot.
int slot = hash(key);
bucket.slot = slot;
bucket.next = buckets[slot];
@ -556,10 +620,10 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Finds the entry corresponding to key. Since it returns an Entry
* it will also prevent the key from being removed under us.
* @param key the key. It may be null.
* @return The WeakBucket.Entry or null, if the key wasn't found.
* @param key the key, may be null
* @return The WeakBucket.WeakEntry or null, if the key wasn't found.
*/
private WeakBucket.Entry internalGet(Object key)
private WeakBucket.WeakEntry internalGet(Object key)
{
if (key == null)
key = NULL_KEY;
@ -567,7 +631,7 @@ public class WeakHashMap extends AbstractMap implements Map
WeakBucket bucket = buckets[slot];
while (bucket != null)
{
WeakBucket.Entry entry = bucket.getEntry();
WeakBucket.WeakEntry entry = bucket.getEntry();
if (entry != null && key.equals(entry.key))
return entry;
@ -601,13 +665,12 @@ public class WeakHashMap extends AbstractMap implements Map
{
int slot = bucket.slot;
if (slot == -1)
/* this bucket was already removed. */
// This bucket was already removed.
return;
/* mark the bucket as removed. This is necessary, since the
* bucket may be enqueued later by the garbage collection and
* internalRemove, will be called a second time.
*/
// Mark the bucket as removed. This is necessary, since the
// bucket may be enqueued later by the garbage collection, and
// internalRemove will be called a second time.
bucket.slot = -1;
if (buckets[slot] == bucket)
buckets[slot] = bucket.next;
@ -629,7 +692,7 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Returns the size of this hash map. Note that the size() may shrink
* spontanously, if the some of the keys were only weakly reachable.
* spontaneously, if the some of the keys were only weakly reachable.
* @return the number of entries in this hash map.
*/
public int size()
@ -651,8 +714,9 @@ public class WeakHashMap extends AbstractMap implements Map
/**
* Tells if the map contains the given key. Note that the result
* may change spontanously, if all the key was only weakly
* may change spontanously, if the key was only weakly
* reachable.
* @param key the key to look for
* @return true, iff the map contains an entry for the given key.
*/
public boolean containsKey(Object key)
@ -662,38 +726,38 @@ public class WeakHashMap extends AbstractMap implements Map
}
/**
* Gets the value the key will be mapped to.
* Gets the value the key is mapped to.
* @return the value the key was mapped to. It returns null if
* the key wasn't in this map, or if the mapped value was explicitly
* set to null.
* the key wasn't in this map, or if the mapped value was
* explicitly set to null.
*/
public Object get(Object key)
{
cleanQueue();
WeakBucket.Entry entry = internalGet(key);
WeakBucket.WeakEntry entry = internalGet(key);
return entry == null ? null : entry.getValue();
}
/**
* Adds a new key/value mapping to this map.
* @param key the key. This may be null.
* @param value the value. This may be null.
* @param key the key, may be null
* @param value the value, may be null
* @return the value the key was mapped to previously. It returns
* null if the key wasn't in this map, or if the mapped value was
* explicitly set to null.
* null if the key wasn't in this map, or if the mapped value
* was explicitly set to null.
*/
public Object put(Object key, Object value)
{
cleanQueue();
WeakBucket.Entry entry = internalGet(key);
WeakBucket.WeakEntry entry = internalGet(key);
if (entry != null)
return entry.setValue(value);
modCount++;
if (size >= threshold)
rehash();
internalAdd(key, value);
modCount++;
return null;
}
@ -702,17 +766,17 @@ public class WeakHashMap extends AbstractMap implements Map
* @param key the key. This may be null.
* @return the value the key was mapped to previously. It returns
* null if the key wasn't in this map, or if the mapped value was
* explicitly set to null. */
* explicitly set to null.
*/
public Object remove(Object key)
{
cleanQueue();
WeakBucket.Entry entry = internalGet(key);
WeakBucket.WeakEntry entry = internalGet(key);
if (entry == null)
{
return null;
}
internalRemove(entry.getBucket());
modCount++;
internalRemove(entry.getBucket());
return entry.getValue();
}
@ -722,10 +786,70 @@ public class WeakHashMap extends AbstractMap implements Map
* silently removed. The returned set has therefore the same
* strange behaviour (shrinking size(), disappearing entries) as
* this weak hash map.
* @return a set representation of the entries. */
* @return a set representation of the entries.
*/
public Set entrySet()
{
cleanQueue();
return theEntrySet;
}
/**
* Clears all entries from this map.
*/
public void clear()
{
super.clear();
}
/**
* Returns true if the map contains at least one key which points to
* the specified object as a value. Note that the result
* may change spontanously, if its key was only weakly reachable.
* @param value the value to search for
* @return true if it is found in the set.
*/
public boolean containsValue(Object value)
{
cleanQueue();
return super.containsValue(value);
}
/**
* Returns a set representation of the keys in this map. This
* set will not have strong references to the keys, so they can be
* silently removed. The returned set has therefore the same
* strange behaviour (shrinking size(), disappearing entries) as
* this weak hash map.
* @return a set representation of the keys.
*/
public Set keySet()
{
cleanQueue();
return super.keySet();
}
/**
* Puts all of the mappings from the given map into this one. If the
* key already exists in this map, its value is replaced.
* @param m the map to copy in
*/
public void putAll(Map m)
{
super.putAll(m);
}
/**
* Returns a collection representation of the values in this map. This
* collection will not have strong references to the keys, so mappings
* can be silently removed. The returned collection has therefore the same
* strange behaviour (shrinking size(), disappearing entries) as
* this weak hash map.
* @return a collection representation of the values.
*/
public Collection values()
{
cleanQueue();
return super.values();
}
}