mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-23 03:09:01 +08:00
488d42af6f
* Makefile.am: Add HashSet.java and java/lang/ref classes. Remove BasicMapEntry.java and Bucket.java. * Makefile.in: Rebuilt. * java/util/HashMap.java: Rewritten. * java/util/HashSet.java: Imported from classpath. * java/util/WeakHashMap.java: Imported from classpath. * java/util/Hashtable.java: Rewritten based on new HashMap code. * java/util/Bucket.java: Deleted. * java/util/BasicMapEntry.java: Deleted. * java/util/Collections.java (search): Use a for-loop, not iterator hasNext(). (copy): Use a for-loop. Throw an IndexOutOfBoundsException if run out of elements in source. (max): Use a for-loop. (min): Ditto. (reverse): Keep track of positions instead of using Iterator's nextIndex() and previousIndex(). (shuffle(List)): Initialize defaultRandom if required using double-check thread safety idiom. Call two-argument shuffle method using defaultRandom. (defaultRandom): New field. (shuffle(List, Random)): Use a for-loop. Keep track of pos instead of using previousIndex() and nextIndex(). (singletonMap(iterator)): Use a HashMap.Entry, not BasicMapEntry. * java/util/AbstractCollection.java (toString): Use a StringBuffer. * java/util/AbstractMap.java (toString): Use StringBuffer. * java/lang/ref/PhantomReference.java: Imported from classpath. * java/lang/ref/SoftReference.java: Ditto. * java/lang/ref/Reference.java: Ditto. * java/lang/ref/WeakReference.java: Ditto. * java/lang/ref/ReferenceQueue.java: Ditto. From-SVN: r38183
1853 lines
43 KiB
Java
1853 lines
43 KiB
Java
/* Collections.java -- Utility class with methods to operate on collections
|
|
Copyright (C) 1998, 1999, 2000 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. */
|
|
|
|
|
|
// TO DO:
|
|
// ~ Serialization is very much broken. Blame Sun for not specifying it.
|
|
// ~ The synchronized* and unmodifiable* methods don't have doc-comments.
|
|
|
|
package java.util;
|
|
|
|
import java.io.Serializable;
|
|
|
|
/**
|
|
* Utility class consisting of static methods that operate on, or return
|
|
* Collections. Contains methods to sort, search, reverse, fill and shuffle
|
|
* Collections, methods to facilitate interoperability with legacy APIs that
|
|
* are unaware of collections, a method to return a list which consists of
|
|
* multiple copies of one element, and methods which "wrap" collections to give
|
|
* them extra properties, such as thread-safety and unmodifiability.
|
|
*/
|
|
public class Collections
|
|
{
|
|
/**
|
|
* This class is non-instantiable.
|
|
*/
|
|
private Collections()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* An immutable, empty Set.
|
|
* Note: This implementation isn't Serializable, although it should be by the
|
|
* spec.
|
|
*/
|
|
public static final Set EMPTY_SET = new AbstractSet()
|
|
{
|
|
public int size()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// This is really cheating! I think it's perfectly valid, though - the
|
|
// more conventional code is here, commented out, in case anyone disagrees.
|
|
public Iterator iterator()
|
|
{
|
|
return EMPTY_LIST.iterator();
|
|
}
|
|
|
|
// public Iterator iterator() {
|
|
// return new Iterator() {
|
|
//
|
|
// public boolean hasNext() {
|
|
// return false;
|
|
// }
|
|
//
|
|
// public Object next() {
|
|
// throw new NoSuchElementException();
|
|
// }
|
|
//
|
|
// public void remove() {
|
|
// throw new UnsupportedOperationException();
|
|
// }
|
|
// };
|
|
// }
|
|
|
|
};
|
|
|
|
/**
|
|
* An immutable, empty List.
|
|
* Note: This implementation isn't serializable, although it should be by the
|
|
* spec.
|
|
*/
|
|
public static final List EMPTY_LIST = new AbstractList()
|
|
{
|
|
public int size()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public Object get(int index)
|
|
{
|
|
throw new IndexOutOfBoundsException();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* An immutable, empty Map.
|
|
* Note: This implementation isn't serializable, although it should be by the
|
|
* spec.
|
|
*/
|
|
public static final Map EMPTY_MAP = new AbstractMap()
|
|
{
|
|
public Set entrySet()
|
|
{
|
|
return EMPTY_SET;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Compare two objects with or without a Comparator. If c is null, uses the
|
|
* natural ordering. Slightly slower than doing it inline if the JVM isn't
|
|
* clever, but worth it for removing a duplicate of the search code.
|
|
* Note: This same code is used in Arrays (for sort as well as search)
|
|
*/
|
|
private static int compare(Object o1, Object o2, Comparator c)
|
|
{
|
|
if (c == null)
|
|
{
|
|
return ((Comparable) o1).compareTo(o2);
|
|
}
|
|
else
|
|
{
|
|
return c.compare(o1, o2);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The hard work for the search routines. If the Comparator given is null,
|
|
* uses the natural ordering of the elements.
|
|
*/
|
|
private static int search(List l, Object key, final Comparator c)
|
|
{
|
|
int pos = 0;
|
|
|
|
// We use a linear search using an iterator if we can guess that the list
|
|
// is sequential-access.
|
|
if (l instanceof AbstractSequentialList)
|
|
{
|
|
ListIterator itr = l.listIterator();
|
|
for (int i = l.size() - 1; i >= 0; --i)
|
|
{
|
|
final int d = compare(key, itr.next(), c);
|
|
if (d == 0)
|
|
{
|
|
return pos;
|
|
}
|
|
else if (d < 0)
|
|
{
|
|
return -pos - 1;
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
// We assume the list is random-access, and use a binary search
|
|
}
|
|
else
|
|
{
|
|
int low = 0;
|
|
int hi = l.size() - 1;
|
|
while (low <= hi)
|
|
{
|
|
pos = (low + hi) >> 1;
|
|
final int d = compare(key, l.get(pos), c);
|
|
if (d == 0)
|
|
{
|
|
return pos;
|
|
}
|
|
else if (d < 0)
|
|
{
|
|
hi = pos - 1;
|
|
}
|
|
else
|
|
{
|
|
low = ++pos; // This gets the insertion point right on the last loop
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we failed to find it, we do the same whichever search we did.
|
|
return -pos - 1;
|
|
}
|
|
|
|
/**
|
|
* Perform a binary search of a List for a key, using the natural ordering of
|
|
* the elements. The list must be sorted (as by the sort() method) - if it is
|
|
* not, the behaviour of this method is undefined, and may be an infinite
|
|
* loop. Further, the key must be comparable with every item in the list. If
|
|
* the list contains the key more than once, any one of them may be found. To
|
|
* avoid pathological behaviour on sequential-access lists, a linear search
|
|
* is used if (l instanceof AbstractSequentialList). Note: although the
|
|
* specification allows for an infinite loop if the list is unsorted, it will
|
|
* not happen in this (Classpath) implementation.
|
|
*
|
|
* @param l the list to search (must be sorted)
|
|
* @param key the value to search for
|
|
* @returns the index at which the key was found, or -n-1 if it was not
|
|
* found, where n is the index of the first value higher than key or
|
|
* a.length if there is no such value.
|
|
* @exception ClassCastException if key could not be compared with one of the
|
|
* elements of l
|
|
* @exception NullPointerException if a null element has compareTo called
|
|
*/
|
|
public static int binarySearch(List l, Object key)
|
|
{
|
|
return search(l, key, null);
|
|
}
|
|
|
|
/**
|
|
* Perform a binary search of a List for a key, using a supplied Comparator.
|
|
* The list must be sorted (as by the sort() method with the same Comparator)
|
|
* - if it is not, the behaviour of this method is undefined, and may be an
|
|
* infinite loop. Further, the key must be comparable with every item in the
|
|
* list. If the list contains the key more than once, any one of them may be
|
|
* found. To avoid pathological behaviour on sequential-access lists, a
|
|
* linear search is used if (l instanceof AbstractSequentialList). Note:
|
|
* although the specification allows for an infinite loop if the list is
|
|
* unsorted, it will not happen in this (Classpath) implementation.
|
|
*
|
|
* @param l the list to search (must be sorted)
|
|
* @param key the value to search for
|
|
* @param c the comparator by which the list is sorted
|
|
* @returns the index at which the key was found, or -n-1 if it was not
|
|
* found, where n is the index of the first value higher than key or
|
|
* a.length if there is no such value.
|
|
* @exception ClassCastException if key could not be compared with one of the
|
|
* elements of l
|
|
*/
|
|
public static int binarySearch(List l, Object key, Comparator c)
|
|
{
|
|
if (c == null)
|
|
{
|
|
throw new NullPointerException();
|
|
}
|
|
return search(l, key, c);
|
|
}
|
|
|
|
/**
|
|
* Copy one list to another. If the destination list is longer than the
|
|
* source list, the remaining elements are unaffected. This method runs in
|
|
* linear time.
|
|
*
|
|
* @param dest the destination list.
|
|
* @param source the source list.
|
|
* @exception IndexOutOfBoundsException if the destination list is shorter
|
|
* than the source list (the elements that can be copied will be, prior to
|
|
* the exception being thrown).
|
|
* @exception UnsupportedOperationException if dest.listIterator() does not
|
|
* support the set operation.
|
|
*/
|
|
public static void copy(List dest, List source)
|
|
{
|
|
Iterator i1 = source.iterator();
|
|
ListIterator i2 = dest.listIterator();
|
|
|
|
try
|
|
{
|
|
for (int i = source.size() - 1; i >= 0; --i)
|
|
{
|
|
i2.next();
|
|
i2.set(i1.next());
|
|
}
|
|
}
|
|
catch (NoSuchElementException x)
|
|
{
|
|
throw new IndexOutOfBoundsException("Source doesn't fit in dest.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns an Enumeration over a collection. This allows interoperability
|
|
* with legacy APIs that require an Enumeration as input.
|
|
*
|
|
* @param c the Collection to iterate over
|
|
* @returns an Enumeration backed by an Iterator over c
|
|
*/
|
|
public static Enumeration enumeration(Collection c)
|
|
{
|
|
final Iterator i = c.iterator();
|
|
return new Enumeration()
|
|
{
|
|
public final boolean hasMoreElements()
|
|
{
|
|
return i.hasNext();
|
|
}
|
|
public final Object nextElement()
|
|
{
|
|
return i.next();
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Replace every element of a list with a given value. This method runs in
|
|
* linear time.
|
|
*
|
|
* @param l the list to fill.
|
|
* @param val the object to vill the list with.
|
|
* @exception UnsupportedOperationException if l.listIterator() does not
|
|
* support the set operation.
|
|
*/
|
|
public static void fill(List l, Object val)
|
|
{
|
|
ListIterator itr = l.listIterator();
|
|
for (int i = l.size() - 1; i >= 0; --i)
|
|
{
|
|
itr.next();
|
|
itr.set(val);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find the maximum element in a Collection, according to the natural
|
|
* ordering of the elements. This implementation iterates over the
|
|
* Collection, so it works in linear time.
|
|
*
|
|
* @param c the Collection to find the maximum element of
|
|
* @returns the maximum element of c
|
|
* @exception NoSuchElementException if c is empty
|
|
* @exception ClassCastException if elements in c are not mutually comparable
|
|
* @exception NullPointerException if null.compareTo is called
|
|
*/
|
|
public static Object max(Collection c)
|
|
{
|
|
Iterator itr = c.iterator();
|
|
Comparable max = (Comparable) itr.next(); // throws NoSuchElementException
|
|
int csize = c.size();
|
|
for (int i = 1; i < csize; i++)
|
|
{
|
|
Object o = itr.next();
|
|
if (max.compareTo(o) < 0)
|
|
{
|
|
max = (Comparable) o;
|
|
}
|
|
}
|
|
return max;
|
|
}
|
|
|
|
/**
|
|
* Find the maximum element in a Collection, according to a specified
|
|
* Comparator. This implementation iterates over the Collection, so it
|
|
* works in linear time.
|
|
*
|
|
* @param c the Collection to find the maximum element of
|
|
* @param order the Comparator to order the elements by
|
|
* @returns the maximum element of c
|
|
* @exception NoSuchElementException if c is empty
|
|
* @exception ClassCastException if elements in c are not mutually comparable
|
|
*/
|
|
public static Object max(Collection c, Comparator order)
|
|
{
|
|
Iterator itr = c.iterator();
|
|
Object max = itr.next(); // throws NoSuchElementException
|
|
int csize = c.size();
|
|
for (int i = 1; i < csize; i++)
|
|
{
|
|
Object o = itr.next();
|
|
if (order.compare(max, o) < 0)
|
|
max = o;
|
|
}
|
|
return max;
|
|
}
|
|
|
|
/**
|
|
* Find the minimum element in a Collection, according to the natural
|
|
* ordering of the elements. This implementation iterates over the
|
|
* Collection, so it works in linear time.
|
|
*
|
|
* @param c the Collection to find the minimum element of
|
|
* @returns the minimum element of c
|
|
* @exception NoSuchElementException if c is empty
|
|
* @exception ClassCastException if elements in c are not mutually comparable
|
|
* @exception NullPointerException if null.compareTo is called
|
|
*/
|
|
public static Object min(Collection c)
|
|
{
|
|
Iterator itr = c.iterator();
|
|
Comparable min = (Comparable) itr.next(); // throws NoSuchElementException
|
|
int csize = c.size();
|
|
for (int i = 1; i < csize; i++)
|
|
{
|
|
Object o = itr.next();
|
|
if (min.compareTo(o) > 0)
|
|
min = (Comparable) o;
|
|
}
|
|
return min;
|
|
}
|
|
|
|
/**
|
|
* Find the minimum element in a Collection, according to a specified
|
|
* Comparator. This implementation iterates over the Collection, so it
|
|
* works in linear time.
|
|
*
|
|
* @param c the Collection to find the minimum element of
|
|
* @param order the Comparator to order the elements by
|
|
* @returns the minimum element of c
|
|
* @exception NoSuchElementException if c is empty
|
|
* @exception ClassCastException if elements in c are not mutually comparable
|
|
*/
|
|
public static Object min(Collection c, Comparator order)
|
|
{
|
|
Iterator itr = c.iterator();
|
|
Object min = itr.next(); // throws NoSuchElementExcception
|
|
int csize = c.size();
|
|
for (int i = 1; i < csize; i++)
|
|
{
|
|
Object o = itr.next();
|
|
if (order.compare(min, o) > 0)
|
|
min = o;
|
|
}
|
|
return min;
|
|
}
|
|
|
|
/**
|
|
* Creates an immutable list consisting of the same object repeated n times.
|
|
* The returned object is tiny, consisting of only a single reference to the
|
|
* object and a count of the number of elements. It is Serializable.
|
|
*
|
|
* @param n the number of times to repeat the object
|
|
* @param o the object to repeat
|
|
* @returns a List consisting of n copies of o
|
|
* @throws IllegalArgumentException if n < 0
|
|
*/
|
|
// It's not Serializable, because the serialized form is unspecced.
|
|
// Also I'm only assuming that it should be because I don't think it's
|
|
// stated - I just would be amazed if it isn't...
|
|
public static List nCopies(final int n, final Object o)
|
|
{
|
|
// Check for insane arguments
|
|
if (n < 0)
|
|
{
|
|
throw new IllegalArgumentException();
|
|
}
|
|
|
|
// Create a minimal implementation of List
|
|
return new AbstractList()
|
|
{
|
|
|
|
public int size()
|
|
{
|
|
return n;
|
|
}
|
|
|
|
public Object get(int index)
|
|
{
|
|
if (index < 0 || index >= n)
|
|
{
|
|
throw new IndexOutOfBoundsException();
|
|
}
|
|
return o;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Reverse a given list. This method works in linear time.
|
|
*
|
|
* @param l the list to reverse.
|
|
* @exception UnsupportedOperationException if l.listIterator() does not
|
|
* support the set operation.
|
|
*/
|
|
public static void reverse(List l)
|
|
{
|
|
ListIterator i1 = l.listIterator();
|
|
int pos1 = 0;
|
|
int pos2 = l.size();
|
|
ListIterator i2 = l.listIterator(pos2);
|
|
while (pos1 < pos2)
|
|
{
|
|
Object o = i1.next();
|
|
i1.set(i2.previous());
|
|
i2.set(o);
|
|
++pos1;
|
|
--pos2;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a comparator that implements the reverse of natural ordering. This is
|
|
* intended to make it easy to sort into reverse order, by simply passing
|
|
* Collections.reverseOrder() to the sort method. The return value of this
|
|
* method is Serializable.
|
|
*/
|
|
// The return value isn't Serializable, because the spec is broken.
|
|
public static Comparator reverseOrder()
|
|
{
|
|
return new Comparator()
|
|
{
|
|
public int compare(Object a, Object b)
|
|
{
|
|
return -((Comparable) a).compareTo(b);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Shuffle a list according to a default source of randomness. The algorithm
|
|
* used would result in a perfectly fair shuffle (that is, each element would
|
|
* have an equal chance of ending up in any position) with a perfect source
|
|
* of randomness; in practice the results are merely very close to perfect.
|
|
* <p>
|
|
* This method operates in linear time on a random-access list, but may take
|
|
* quadratic time on a sequential-access list.
|
|
* Note: this (classpath) implementation will never take quadratic time, but
|
|
* it does make a copy of the list. This is in line with the behaviour of the
|
|
* sort methods and seems preferable.
|
|
*
|
|
* @param l the list to shuffle.
|
|
* @exception UnsupportedOperationException if l.listIterator() does not
|
|
* support the set operation.
|
|
*/
|
|
public static void shuffle(List l)
|
|
{
|
|
if (defaultRandom == null)
|
|
{
|
|
synchronized (Collections.class)
|
|
{
|
|
if (defaultRandom == null)
|
|
defaultRandom = new Random();
|
|
}
|
|
}
|
|
shuffle(l, defaultRandom);
|
|
}
|
|
|
|
/** Cache a single Random object for use by shuffle(List). This improves
|
|
* performance as well as ensuring that sequential calls to shuffle() will
|
|
* not result in the same shuffle order occuring: the resolution of
|
|
* System.currentTimeMillis() is not sufficient to guarantee a unique seed.
|
|
*/
|
|
private static Random defaultRandom = null;
|
|
|
|
/**
|
|
* Shuffle a list according to a given source of randomness. The algorithm
|
|
* used iterates backwards over the list, swapping each element with an
|
|
* element randomly selected from the elements in positions less than or
|
|
* equal to it (using r.nextInt(int)).
|
|
* <p>
|
|
* This algorithm would result in a perfectly fair shuffle (that is, each
|
|
* element would have an equal chance of ending up in any position) if r were
|
|
* a perfect source of randomness. In practise (eg if r = new Random()) the
|
|
* results are merely very close to perfect.
|
|
* <p>
|
|
* This method operates in linear time on a random-access list, but may take
|
|
* quadratic time on a sequential-access list.
|
|
* Note: this (classpath) implementation will never take quadratic time, but
|
|
* it does make a copy of the list. This is in line with the behaviour of the
|
|
* sort methods and seems preferable.
|
|
*
|
|
* @param l the list to shuffle.
|
|
* @param r the source of randomness to use for the shuffle.
|
|
* @exception UnsupportedOperationException if l.listIterator() does not
|
|
* support the set operation.
|
|
*/
|
|
public static void shuffle(List l, Random r)
|
|
{
|
|
Object[] a = l.toArray(); // Dump l into an array
|
|
int lsize = l.size();
|
|
ListIterator i = l.listIterator(lsize);
|
|
|
|
// Iterate backwards over l
|
|
for (int pos = lsize - 1; pos >= 0; --pos)
|
|
{
|
|
// Obtain a random position to swap with. pos + 1 is used so that the
|
|
// range of the random number includes the current position.
|
|
int swap = r.nextInt(pos + 1);
|
|
|
|
// Swap the swapth element of the array with the next element of the
|
|
// list.
|
|
Object o = a[swap];
|
|
a[swap] = a[pos];
|
|
a[pos] = o;
|
|
|
|
// Set the element in the original list accordingly.
|
|
i.previous();
|
|
i.set(o);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Obtain an immutable Set consisting of a single element. The return value
|
|
* of this method is Serializable.
|
|
*
|
|
* @param o the single element.
|
|
* @returns an immutable Set containing only o.
|
|
*/
|
|
// It's not serializable because the spec is broken.
|
|
public static Set singleton(final Object o)
|
|
{
|
|
return new AbstractSet()
|
|
{
|
|
public int size()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
public Iterator iterator()
|
|
{
|
|
return new Iterator()
|
|
{
|
|
private boolean hasNext = true;
|
|
|
|
public boolean hasNext()
|
|
{
|
|
return hasNext;
|
|
}
|
|
|
|
public Object next()
|
|
{
|
|
if (hasNext)
|
|
{
|
|
hasNext = false;
|
|
return o;
|
|
}
|
|
else
|
|
{
|
|
throw new NoSuchElementException();
|
|
}
|
|
}
|
|
|
|
public void remove()
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Obtain an immutable List consisting of a single element. The return value
|
|
* of this method is Serializable.
|
|
*
|
|
* @param o the single element.
|
|
* @returns an immutable List containing only o.
|
|
*/
|
|
// It's not serializable because the spec is broken.
|
|
public static List singletonList(final Object o)
|
|
{
|
|
return new AbstractList()
|
|
{
|
|
public int size()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
public Object get(int index)
|
|
{
|
|
if (index == 0)
|
|
{
|
|
throw new IndexOutOfBoundsException();
|
|
}
|
|
else
|
|
{
|
|
return o;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Obtain an immutable Map consisting of a single key value pair.
|
|
* The return value of this method is Serializable.
|
|
*
|
|
* @param key the single key.
|
|
* @param value the single value.
|
|
* @returns an immutable Map containing only the single key value pair.
|
|
*/
|
|
// It's not serializable because the spec is broken.
|
|
public static Map singletonMap(final Object key, final Object value)
|
|
{
|
|
return new AbstractMap()
|
|
{
|
|
public Set entrySet()
|
|
{
|
|
return singleton(new HashMap.Entry(key, value));
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Sort a list according to the natural ordering of its elements. The list
|
|
* must be modifiable, but can be of fixed size. The sort algorithm is
|
|
* precisely that used by Arrays.sort(Object[]), which offers guaranteed
|
|
* nlog(n) performance. This implementation dumps the list into an array,
|
|
* sorts the array, and then iterates over the list setting each element from
|
|
* the array.
|
|
*
|
|
* @param l the List to sort
|
|
* @exception ClassCastException if some items are not mutually comparable
|
|
* @exception UnsupportedOperationException if the List is not modifiable
|
|
*/
|
|
public static void sort(List l)
|
|
{
|
|
Object[] a = l.toArray();
|
|
Arrays.sort(a);
|
|
ListIterator i = l.listIterator();
|
|
for (int pos = 0; pos < a.length; pos++)
|
|
{
|
|
i.next();
|
|
i.set(a[pos]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sort a list according to a specified Comparator. The list must be
|
|
* modifiable, but can be of fixed size. The sort algorithm is precisely that
|
|
* used by Arrays.sort(Object[], Comparator), which offers guaranteed
|
|
* nlog(n) performance. This implementation dumps the list into an array,
|
|
* sorts the array, and then iterates over the list setting each element from
|
|
* the array.
|
|
*
|
|
* @param l the List to sort
|
|
* @param c the Comparator specifying the ordering for the elements
|
|
* @exception ClassCastException if c will not compare some pair of items
|
|
* @exception UnsupportedOperationException if the List is not modifiable
|
|
*/
|
|
public static void sort(List l, Comparator c)
|
|
{
|
|
Object[] a = l.toArray();
|
|
Arrays.sort(a, c);
|
|
ListIterator i = l.listIterator();
|
|
for (int pos = 0; pos < a.length; pos++)
|
|
{
|
|
i.next();
|
|
i.set(a[pos]);
|
|
}
|
|
}
|
|
|
|
// All the methods from here on in require doc-comments.
|
|
|
|
public static Collection synchronizedCollection(Collection c)
|
|
{
|
|
return new SynchronizedCollection(c);
|
|
}
|
|
public static List synchronizedList(List l)
|
|
{
|
|
return new SynchronizedList(l);
|
|
}
|
|
public static Map synchronizedMap(Map m)
|
|
{
|
|
return new SynchronizedMap(m);
|
|
}
|
|
public static Set synchronizedSet(Set s)
|
|
{
|
|
return new SynchronizedSet(s);
|
|
}
|
|
public static SortedMap synchronizedSortedMap(SortedMap m)
|
|
{
|
|
return new SynchronizedSortedMap(m);
|
|
}
|
|
public static SortedSet synchronizedSortedSet(SortedSet s)
|
|
{
|
|
return new SynchronizedSortedSet(s);
|
|
}
|
|
public static Collection unmodifiableCollection(Collection c)
|
|
{
|
|
return new UnmodifiableCollection(c);
|
|
}
|
|
public static List unmodifiableList(List l)
|
|
{
|
|
return new UnmodifiableList(l);
|
|
}
|
|
public static Map unmodifiableMap(Map m)
|
|
{
|
|
return new UnmodifiableMap(m);
|
|
}
|
|
public static Set unmodifiableSet(Set s)
|
|
{
|
|
return new UnmodifiableSet(s);
|
|
}
|
|
public static SortedMap unmodifiableSortedMap(SortedMap m)
|
|
{
|
|
return new UnmodifiableSortedMap(m);
|
|
}
|
|
public static SortedSet unmodifiableSortedSet(SortedSet s)
|
|
{
|
|
return new UnmodifiableSortedSet(s);
|
|
}
|
|
|
|
// Sun's spec will need to be checked for the precise names of these
|
|
// classes, for serializability's sake. However, from what I understand,
|
|
// serialization is broken for these classes anyway.
|
|
|
|
// Note: although this code is largely uncommented, it is all very
|
|
// mechanical and there's nothing really worth commenting.
|
|
// When serialization of these classes works, we'll need doc-comments on
|
|
// them to document the serialized form.
|
|
|
|
private static class UnmodifiableIterator implements Iterator
|
|
{
|
|
private Iterator i;
|
|
|
|
public UnmodifiableIterator(Iterator i)
|
|
{
|
|
this.i = i;
|
|
}
|
|
|
|
public Object next()
|
|
{
|
|
return i.next();
|
|
}
|
|
public boolean hasNext()
|
|
{
|
|
return i.hasNext();
|
|
}
|
|
public void remove()
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
}
|
|
|
|
private static class UnmodifiableListIterator extends UnmodifiableIterator
|
|
implements ListIterator
|
|
{
|
|
// This is stored both here and in the superclass, to avoid excessive
|
|
// casting.
|
|
private ListIterator li;
|
|
|
|
public UnmodifiableListIterator(ListIterator li)
|
|
{
|
|
super(li);
|
|
this.li = li;
|
|
}
|
|
|
|
public boolean hasPrevious()
|
|
{
|
|
return li.hasPrevious();
|
|
}
|
|
public Object previous()
|
|
{
|
|
return li.previous();
|
|
}
|
|
public int nextIndex()
|
|
{
|
|
return li.nextIndex();
|
|
}
|
|
public int previousIndex()
|
|
{
|
|
return li.previousIndex();
|
|
}
|
|
public void add(Object o)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public void set(Object o)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
}
|
|
|
|
private static class UnmodifiableCollection implements Collection,
|
|
Serializable
|
|
{
|
|
Collection c;
|
|
|
|
public UnmodifiableCollection(Collection c)
|
|
{
|
|
this.c = c;
|
|
}
|
|
|
|
public boolean add(Object o)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public boolean addAll(Collection c)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public void clear()
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public boolean contains(Object o)
|
|
{
|
|
return c.contains(o);
|
|
}
|
|
public boolean containsAll(Collection c1)
|
|
{
|
|
return c.containsAll(c1);
|
|
}
|
|
public boolean isEmpty()
|
|
{
|
|
return c.isEmpty();
|
|
}
|
|
public Iterator iterator()
|
|
{
|
|
return new UnmodifiableIterator(c.iterator());
|
|
}
|
|
public boolean remove(Object o)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public boolean removeAll(Collection c)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public boolean retainAll(Collection c)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public int size()
|
|
{
|
|
return c.size();
|
|
}
|
|
public Object[] toArray()
|
|
{
|
|
return c.toArray();
|
|
}
|
|
public Object[] toArray(Object[]a)
|
|
{
|
|
return c.toArray(a);
|
|
}
|
|
public String toString()
|
|
{
|
|
return c.toString();
|
|
}
|
|
}
|
|
|
|
private static class UnmodifiableList extends UnmodifiableCollection
|
|
implements List
|
|
{
|
|
// This is stored both here and in the superclass, to avoid excessive
|
|
// casting.
|
|
List l;
|
|
|
|
public UnmodifiableList(List l)
|
|
{
|
|
super(l);
|
|
this.l = l;
|
|
}
|
|
|
|
public void add(int index, Object o)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public boolean addAll(int index, Collection c)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public boolean equals(Object o)
|
|
{
|
|
return l.equals(o);
|
|
}
|
|
public Object get(int index)
|
|
{
|
|
return l.get(index);
|
|
}
|
|
public int hashCode()
|
|
{
|
|
return l.hashCode();
|
|
}
|
|
public int indexOf(Object o)
|
|
{
|
|
return l.indexOf(o);
|
|
}
|
|
public int lastIndexOf(Object o)
|
|
{
|
|
return l.lastIndexOf(o);
|
|
}
|
|
public ListIterator listIterator()
|
|
{
|
|
return new UnmodifiableListIterator(l.listIterator());
|
|
}
|
|
public ListIterator listIterator(int index)
|
|
{
|
|
return new UnmodifiableListIterator(l.listIterator(index));
|
|
}
|
|
public Object remove(int index)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public Object set(int index, Object o)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public List subList(int fromIndex, int toIndex)
|
|
{
|
|
return new UnmodifiableList(l.subList(fromIndex, toIndex));
|
|
}
|
|
}
|
|
|
|
private static class UnmodifiableSet extends UnmodifiableCollection
|
|
implements Set
|
|
{
|
|
public UnmodifiableSet(Set s)
|
|
{
|
|
super(s);
|
|
}
|
|
public boolean equals(Object o)
|
|
{
|
|
return c.equals(o);
|
|
}
|
|
public int hashCode()
|
|
{
|
|
return c.hashCode();
|
|
}
|
|
}
|
|
|
|
private static class UnmodifiableSortedSet extends UnmodifiableSet
|
|
implements SortedSet
|
|
{
|
|
// This is stored both here and in the superclass, to avoid excessive
|
|
// casting.
|
|
private SortedSet ss;
|
|
|
|
public UnmodifiableSortedSet(SortedSet ss)
|
|
{
|
|
super(ss);
|
|
this.ss = ss;
|
|
}
|
|
|
|
public Comparator comparator()
|
|
{
|
|
return ss.comparator();
|
|
}
|
|
public Object first()
|
|
{
|
|
return ss.first();
|
|
}
|
|
public Object last()
|
|
{
|
|
return ss.last();
|
|
}
|
|
public SortedSet headSet(Object toElement)
|
|
{
|
|
return new UnmodifiableSortedSet(ss.headSet(toElement));
|
|
}
|
|
public SortedSet tailSet(Object fromElement)
|
|
{
|
|
return new UnmodifiableSortedSet(ss.tailSet(fromElement));
|
|
}
|
|
public SortedSet subSet(Object fromElement, Object toElement)
|
|
{
|
|
return new UnmodifiableSortedSet(ss.subSet(fromElement, toElement));
|
|
}
|
|
}
|
|
|
|
private static class UnmodifiableMap implements Map, Serializable
|
|
{
|
|
Map m;
|
|
|
|
public UnmodifiableMap(Map m)
|
|
{
|
|
this.m = m;
|
|
}
|
|
|
|
public void clear()
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public boolean containsKey(Object key)
|
|
{
|
|
return m.containsKey(key);
|
|
}
|
|
public boolean containsValue(Object value)
|
|
{
|
|
return m.containsValue(value);
|
|
}
|
|
|
|
// This is one of the ickiest cases of nesting I've ever seen. It just
|
|
// means "return an UnmodifiableSet, except that the iterator() method
|
|
// returns an UnmodifiableIterator whos next() method returns an
|
|
// unmodifiable wrapper around its normal return value".
|
|
public Set entrySet()
|
|
{
|
|
return new UnmodifiableSet(m.entrySet())
|
|
{
|
|
public Iterator iterator()
|
|
{
|
|
return new UnmodifiableIterator(c.iterator())
|
|
{
|
|
public Object next()
|
|
{
|
|
final Map.Entry e = (Map.Entry) super.next();
|
|
return new Map.Entry()
|
|
{
|
|
public Object getKey()
|
|
{
|
|
return e.getKey();
|
|
}
|
|
public Object getValue()
|
|
{
|
|
return e.getValue();
|
|
}
|
|
public Object setValue(Object value)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public int hashCode()
|
|
{
|
|
return e.hashCode();
|
|
}
|
|
public boolean equals(Object o)
|
|
{
|
|
return e.equals(o);
|
|
}
|
|
};
|
|
}
|
|
};
|
|
}
|
|
};
|
|
}
|
|
public boolean equals(Object o)
|
|
{
|
|
return m.equals(o);
|
|
}
|
|
public Object get(Object key)
|
|
{
|
|
return m.get(key);
|
|
}
|
|
public Object put(Object key, Object value)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public int hashCode()
|
|
{
|
|
return m.hashCode();
|
|
}
|
|
public boolean isEmpty()
|
|
{
|
|
return m.isEmpty();
|
|
}
|
|
public Set keySet()
|
|
{
|
|
return new UnmodifiableSet(m.keySet());
|
|
}
|
|
public void putAll(Map m)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public Object remove(Object o)
|
|
{
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
public int size()
|
|
{
|
|
return m.size();
|
|
}
|
|
public Collection values()
|
|
{
|
|
return new UnmodifiableCollection(m.values());
|
|
}
|
|
public String toString()
|
|
{
|
|
return m.toString();
|
|
}
|
|
}
|
|
|
|
private static class UnmodifiableSortedMap extends UnmodifiableMap
|
|
implements SortedMap
|
|
{
|
|
// This is stored both here and in the superclass, to avoid excessive
|
|
// casting.
|
|
private SortedMap sm;
|
|
|
|
public UnmodifiableSortedMap(SortedMap sm)
|
|
{
|
|
super(sm);
|
|
this.sm = sm;
|
|
}
|
|
|
|
public Comparator comparator()
|
|
{
|
|
return sm.comparator();
|
|
}
|
|
public Object firstKey()
|
|
{
|
|
return sm.firstKey();
|
|
}
|
|
public Object lastKey()
|
|
{
|
|
return sm.lastKey();
|
|
}
|
|
public SortedMap headMap(Object toKey)
|
|
{
|
|
return new UnmodifiableSortedMap(sm.headMap(toKey));
|
|
}
|
|
public SortedMap tailMap(Object fromKey)
|
|
{
|
|
return new UnmodifiableSortedMap(sm.tailMap(fromKey));
|
|
}
|
|
public SortedMap subMap(Object fromKey, Object toKey)
|
|
{
|
|
return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey));
|
|
}
|
|
}
|
|
|
|
// All the "Synchronized" wrapper objects include a "sync" field which
|
|
// specifies what object to synchronize on. That way, nested wrappers such as
|
|
// UnmodifiableMap.keySet synchronize on the right things.
|
|
|
|
private static class SynchronizedIterator implements Iterator
|
|
{
|
|
Object sync;
|
|
private Iterator i;
|
|
|
|
public SynchronizedIterator(Object sync, Iterator i)
|
|
{
|
|
this.sync = sync;
|
|
this.i = i;
|
|
}
|
|
|
|
public Object next()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return i.next();
|
|
}
|
|
}
|
|
public boolean hasNext()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return i.hasNext();
|
|
}
|
|
}
|
|
public void remove()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
i.remove();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class SynchronizedListIterator extends SynchronizedIterator
|
|
implements ListIterator
|
|
{
|
|
// This is stored both here and in the superclass, to avoid excessive
|
|
// casting.
|
|
private ListIterator li;
|
|
|
|
public SynchronizedListIterator(Object sync, ListIterator li)
|
|
{
|
|
super(sync, li);
|
|
this.li = li;
|
|
}
|
|
|
|
public boolean hasPrevious()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return li.hasPrevious();
|
|
}
|
|
}
|
|
public Object previous()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return li.previous();
|
|
}
|
|
}
|
|
public int nextIndex()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return li.nextIndex();
|
|
}
|
|
}
|
|
public int previousIndex()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return li.previousIndex();
|
|
}
|
|
}
|
|
public void add(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
li.add(o);
|
|
}
|
|
}
|
|
public void set(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
li.set(o);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class SynchronizedCollection implements Collection,
|
|
Serializable
|
|
{
|
|
Object sync;
|
|
Collection c;
|
|
|
|
public SynchronizedCollection(Collection c)
|
|
{
|
|
this.sync = this;
|
|
this.c = c;
|
|
}
|
|
public SynchronizedCollection(Object sync, Collection c)
|
|
{
|
|
this.c = c;
|
|
this.sync = sync;
|
|
}
|
|
|
|
public boolean add(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.add(o);
|
|
}
|
|
}
|
|
public boolean addAll(Collection col)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.addAll(col);
|
|
}
|
|
}
|
|
public void clear()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
c.clear();
|
|
}
|
|
}
|
|
public boolean contains(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.contains(o);
|
|
}
|
|
}
|
|
public boolean containsAll(Collection c1)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.containsAll(c1);
|
|
}
|
|
}
|
|
public boolean isEmpty()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.isEmpty();
|
|
}
|
|
}
|
|
public Iterator iterator()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedIterator(sync, c.iterator());
|
|
}
|
|
}
|
|
public boolean remove(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.remove(o);
|
|
}
|
|
}
|
|
public boolean removeAll(Collection col)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.removeAll(col);
|
|
}
|
|
}
|
|
public boolean retainAll(Collection col)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.retainAll(col);
|
|
}
|
|
}
|
|
public int size()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.size();
|
|
}
|
|
}
|
|
public Object[] toArray()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.toArray();
|
|
}
|
|
}
|
|
public Object[] toArray(Object[]a)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.toArray(a);
|
|
}
|
|
}
|
|
public String toString()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.toString();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class SynchronizedList extends SynchronizedCollection
|
|
implements List
|
|
{
|
|
// This is stored both here and in the superclass, to avoid excessive
|
|
// casting.
|
|
List l;
|
|
|
|
public SynchronizedList(Object sync, List l)
|
|
{
|
|
super(sync, l);
|
|
this.l = l;
|
|
}
|
|
public SynchronizedList(List l)
|
|
{
|
|
super(l);
|
|
this.l = l;
|
|
}
|
|
|
|
public void add(int index, Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
l.add(index, o);
|
|
}
|
|
}
|
|
public boolean addAll(int index, Collection c)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.addAll(index, c);
|
|
}
|
|
}
|
|
public boolean equals(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.equals(o);
|
|
}
|
|
}
|
|
public Object get(int index)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.get(index);
|
|
}
|
|
}
|
|
public int hashCode()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.hashCode();
|
|
}
|
|
}
|
|
public int indexOf(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.indexOf(o);
|
|
}
|
|
}
|
|
public int lastIndexOf(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.lastIndexOf(o);
|
|
}
|
|
}
|
|
public ListIterator listIterator()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedListIterator(sync, l.listIterator());
|
|
}
|
|
}
|
|
public ListIterator listIterator(int index)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedListIterator(sync, l.listIterator(index));
|
|
}
|
|
}
|
|
public Object remove(int index)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.remove(index);
|
|
}
|
|
}
|
|
public boolean remove(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.remove(o);
|
|
}
|
|
}
|
|
public Object set(int index, Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return l.set(index, o);
|
|
}
|
|
}
|
|
public List subList(int fromIndex, int toIndex)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedList(l.subList(fromIndex, toIndex));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class SynchronizedSet extends SynchronizedCollection
|
|
implements Set
|
|
{
|
|
public SynchronizedSet(Object sync, Set s)
|
|
{
|
|
super(sync, s);
|
|
}
|
|
public SynchronizedSet(Set s)
|
|
{
|
|
super(s);
|
|
}
|
|
|
|
public boolean equals(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.equals(o);
|
|
}
|
|
}
|
|
public int hashCode()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return c.hashCode();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class SynchronizedSortedSet extends SynchronizedSet
|
|
implements SortedSet
|
|
{
|
|
// This is stored both here and in the superclass, to avoid excessive
|
|
// casting.
|
|
private SortedSet ss;
|
|
|
|
public SynchronizedSortedSet(Object sync, SortedSet ss)
|
|
{
|
|
super(sync, ss);
|
|
this.ss = ss;
|
|
}
|
|
public SynchronizedSortedSet(SortedSet ss)
|
|
{
|
|
super(ss);
|
|
this.ss = ss;
|
|
}
|
|
|
|
public Comparator comparator()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return ss.comparator();
|
|
}
|
|
}
|
|
public Object first()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return ss.first();
|
|
}
|
|
}
|
|
public Object last()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return ss.last();
|
|
}
|
|
}
|
|
public SortedSet headSet(Object toElement)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedSortedSet(sync, ss.headSet(toElement));
|
|
}
|
|
}
|
|
public SortedSet tailSet(Object fromElement)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedSortedSet(sync, ss.tailSet(fromElement));
|
|
}
|
|
}
|
|
public SortedSet subSet(Object fromElement, Object toElement)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedSortedSet(sync,
|
|
ss.subSet(fromElement, toElement));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class SynchronizedMap implements Map, Serializable
|
|
{
|
|
Object sync;
|
|
Map m;
|
|
|
|
public SynchronizedMap(Object sync, Map m)
|
|
{
|
|
this.sync = sync;
|
|
this.m = m;
|
|
}
|
|
public SynchronizedMap(Map m)
|
|
{
|
|
this.m = m;
|
|
this.sync = this;
|
|
}
|
|
|
|
public void clear()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
m.clear();
|
|
}
|
|
}
|
|
public boolean containsKey(Object key)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.containsKey(key);
|
|
}
|
|
}
|
|
public boolean containsValue(Object value)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.containsValue(value);
|
|
}
|
|
}
|
|
|
|
// This is one of the ickiest cases of nesting I've ever seen. It just
|
|
// means "return a SynchronizedSet, except that the iterator() method
|
|
// returns an SynchronizedIterator whos next() method returns a
|
|
// synchronized wrapper around its normal return value".
|
|
public Set entrySet()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedSet(sync, m.entrySet())
|
|
{
|
|
public Iterator iterator()
|
|
{
|
|
synchronized(SynchronizedMap.this.sync)
|
|
{
|
|
return new SynchronizedIterator(SynchronizedMap.this.sync,
|
|
c.iterator())
|
|
{
|
|
public Object next()
|
|
{
|
|
synchronized(SynchronizedMap.this.sync)
|
|
{
|
|
final Map.Entry e = (Map.Entry) super.next();
|
|
return new Map.Entry()
|
|
{
|
|
public Object getKey()
|
|
{
|
|
synchronized(SynchronizedMap.this.sync)
|
|
{
|
|
return e.getKey();
|
|
}
|
|
}
|
|
public Object getValue()
|
|
{
|
|
synchronized(SynchronizedMap.this.sync)
|
|
{
|
|
return e.getValue();
|
|
}
|
|
}
|
|
public Object setValue(Object value)
|
|
{
|
|
synchronized(SynchronizedMap.this.sync)
|
|
{
|
|
return e.setValue(value);
|
|
}
|
|
}
|
|
public int hashCode()
|
|
{
|
|
synchronized(SynchronizedMap.this.sync)
|
|
{
|
|
return e.hashCode();
|
|
}
|
|
}
|
|
public boolean equals(Object o)
|
|
{
|
|
synchronized(SynchronizedMap.this.sync)
|
|
{
|
|
return e.equals(o);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
public boolean equals(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.equals(o);
|
|
}
|
|
}
|
|
public Object get(Object key)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.get(key);
|
|
}
|
|
}
|
|
public Object put(Object key, Object value)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.put(key, value);
|
|
}
|
|
}
|
|
public int hashCode()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.hashCode();
|
|
}
|
|
}
|
|
public boolean isEmpty()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.isEmpty();
|
|
}
|
|
}
|
|
public Set keySet()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedSet(sync, m.keySet());
|
|
}
|
|
}
|
|
public void putAll(Map map)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
m.putAll(map);
|
|
}
|
|
}
|
|
public Object remove(Object o)
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.remove(o);
|
|
}
|
|
}
|
|
|
|
public int size()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.size();
|
|
}
|
|
}
|
|
public Collection values()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return new SynchronizedCollection(sync, m.values());
|
|
}
|
|
}
|
|
public String toString()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return m.toString();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class SynchronizedSortedMap extends SynchronizedMap
|
|
implements SortedMap
|
|
{
|
|
// This is stored both here and in the superclass, to avoid excessive
|
|
// casting.
|
|
private SortedMap sm;
|
|
|
|
public SynchronizedSortedMap(Object sync, SortedMap sm)
|
|
{
|
|
super(sync, sm);
|
|
this.sm = sm;
|
|
}
|
|
public SynchronizedSortedMap(SortedMap sm)
|
|
{
|
|
super(sm);
|
|
this.sm = sm;
|
|
}
|
|
|
|
public Comparator comparator()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return sm.comparator();
|
|
}
|
|
}
|
|
public Object firstKey()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return sm.firstKey();
|
|
}
|
|
}
|
|
public Object lastKey()
|
|
{
|
|
synchronized(sync)
|
|
{
|
|
return sm.lastKey();
|
|
}
|
|
}
|
|
public SortedMap headMap(Object toKey)
|
|
{
|
|
return new SynchronizedSortedMap(sync, sm.headMap(toKey));
|
|
}
|
|
public SortedMap tailMap(Object fromKey)
|
|
{
|
|
return new SynchronizedSortedMap(sync, sm.tailMap(fromKey));
|
|
}
|
|
public SortedMap subMap(Object fromKey, Object toKey)
|
|
{
|
|
return new SynchronizedSortedMap(sync, sm.subMap(fromKey, toKey));
|
|
}
|
|
}
|
|
}
|