| /* Collections.java -- Utility class with methods to operate on collections | |
| Copyright (C) 1998, 1999, 2000, 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; | |
| /** | |
| * 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. | |
| * <p> | |
| * | |
| * All methods which take a collection throw a {@link NullPointerException} if | |
| * that collection is null. Algorithms which can change a collection may, but | |
| * are not required, to throw the {@link UnsupportedOperationException} that | |
| * the underlying collection would throw during an attempt at modification. | |
| * For example, | |
| * <code>Collections.singleton("").addAll(Collections.EMPTY_SET)<code> | |
| * does not throw a exception, even though addAll is an unsupported operation | |
| * on a singleton; the reason for this is that addAll did not attempt to | |
| * modify the set. | |
| * | |
| * @author Original author unknown | |
| * @author Bryce McKinlay | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| * @see Collection | |
| * @see Set | |
| * @see List | |
| * @see Map | |
| * @see Arrays | |
| * @since 1.2 | |
| * @status updated to 1.4 | |
| */ | |
| public class Collections | |
| { | |
| /** | |
| * Constant used to decide cutoff for when a non-RandomAccess list should | |
| * be treated as sequential-access. Basically, quadratic behavior is | |
| * acceptible for small lists when the overhead is so small in the first | |
| * place. I arbitrarily set it to 16, so it may need some tuning. | |
| */ | |
| private static final int LARGE_LIST_SIZE = 16; | |
| /** | |
| * Determines if a list should be treated as a sequential-access one. | |
| * Rather than the old method of JDK 1.3 of assuming only instanceof | |
| * AbstractSequentialList should be sequential, this uses the new method | |
| * of JDK 1.4 of assuming anything that does NOT implement RandomAccess | |
| * and exceeds a large (unspecified) size should be sequential. | |
| * | |
| * @param l the list to check | |
| * @return true if it should be treated as sequential-access | |
| */ | |
| private static boolean isSequential(List l) | |
| { | |
| return ! (l instanceof RandomAccess) && l.size() > LARGE_LIST_SIZE; | |
| } | |
| /** | |
| * This class is non-instantiable. | |
| */ | |
| private Collections() | |
| { | |
| } | |
| /** | |
| * An immutable, serializable, empty Set. | |
| * @see Serializable | |
| */ | |
| public static final Set EMPTY_SET = new EmptySet(); | |
| private static final Iterator EMPTY_ITERATOR = new Iterator() | |
| { | |
| public boolean hasNext() | |
| { | |
| return false; | |
| } | |
| public Object next() | |
| { | |
| throw new NoSuchElementException(); | |
| } | |
| public void remove() | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| }; | |
| /** | |
| * The implementation of {@link #EMPTY_SET}. This class name is required | |
| * for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class EmptySet extends AbstractSet | |
| implements Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 1582296315990362920L; | |
| /** | |
| * A private constructor adds overhead. | |
| */ | |
| EmptySet() | |
| { | |
| } | |
| /** | |
| * The size: always 0! | |
| */ | |
| public int size() | |
| { | |
| return 0; | |
| } | |
| /** | |
| * Returns an iterator that does not iterate. | |
| */ | |
| public Iterator iterator() | |
| { | |
| return EMPTY_ITERATOR; | |
| } | |
| } // class EmptySet | |
| /** | |
| * An immutable, serializable, empty List, which implements RandomAccess. | |
| * @see Serializable | |
| * @see RandomAccess | |
| */ | |
| public static final List EMPTY_LIST = new EmptyList(); | |
| /** | |
| * The implementation of {@link #EMPTY_LIST}. This class name is required | |
| * for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class EmptyList extends AbstractList | |
| implements Serializable, RandomAccess | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 8842843931221139166L; | |
| /** | |
| * A private constructor adds overhead. | |
| */ | |
| EmptyList() | |
| { | |
| } | |
| /** | |
| * The size is always 0. | |
| */ | |
| public int size() | |
| { | |
| return 0; | |
| } | |
| /** | |
| * No matter the index, it is out of bounds. | |
| */ | |
| public Object get(int index) | |
| { | |
| throw new IndexOutOfBoundsException(); | |
| } | |
| /** | |
| * Returns an iterator that does not iterate. Optional, but avoids | |
| * allocation of an iterator in AbstractList. | |
| */ | |
| public Iterator iterator() | |
| { | |
| return EMPTY_ITERATOR; | |
| } | |
| } // class EmptyList | |
| /** | |
| * An immutable, serializable, empty Map. | |
| * @see Serializable | |
| */ | |
| public static final Map EMPTY_MAP = new EmptyMap(); | |
| /** | |
| * The implementation of {@link #EMPTY_MAP}. This class name is required | |
| * for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class EmptyMap extends AbstractMap | |
| implements Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 6428348081105594320L; | |
| /** | |
| * A private constructor adds overhead. | |
| */ | |
| EmptyMap() | |
| { | |
| } | |
| /** | |
| * There are no entries. | |
| */ | |
| public Set entrySet() | |
| { | |
| return EMPTY_SET; | |
| } | |
| /** | |
| * Size is always 0. | |
| */ | |
| public int size() | |
| { | |
| return 0; | |
| } | |
| /** | |
| * No entries. Technically, EMPTY_SET, while more specific than a general | |
| * Collection, will work. Besides, that's what the JDK uses! | |
| */ | |
| public Collection values() | |
| { | |
| return EMPTY_SET; | |
| } | |
| } // class EmptyMap | |
| /** | |
| * 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 code is also used in Arrays (for sort as well as search). | |
| */ | |
| static final int compare(Object o1, Object o2, Comparator c) | |
| { | |
| return c == null ? ((Comparable) o1).compareTo(o2) : c.compare(o1, o2); | |
| } | |
| /** | |
| * 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 behavior 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. | |
| * <p> | |
| * | |
| * This algorithm behaves in log(n) time for {@link RandomAccess} lists, | |
| * and uses a linear search with O(n) link traversals and log(n) comparisons | |
| * with {@link AbstractSequentialList} lists. 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 | |
| * @return 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 | |
| * @throws ClassCastException if key could not be compared with one of the | |
| * elements of l | |
| * @throws NullPointerException if a null element has compareTo called | |
| * @see #sort(List) | |
| */ | |
| public static int binarySearch(List l, Object key) | |
| { | |
| return binarySearch(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 behavior 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. If the comparator is null, the elements' natural ordering is used. | |
| * <p> | |
| * | |
| * This algorithm behaves in log(n) time for {@link RandomAccess} lists, | |
| * and uses a linear search with O(n) link traversals and log(n) comparisons | |
| * with {@link AbstractSequentialList} lists. 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 | |
| * @return 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 | |
| * @throws ClassCastException if key could not be compared with one of the | |
| * elements of l | |
| * @throws NullPointerException if a null element is compared with natural | |
| * ordering (only possible when c is null) | |
| * @see #sort(List, Comparator) | |
| */ | |
| public static int binarySearch(List l, Object key, Comparator c) | |
| { | |
| int pos = 0; | |
| int low = 0; | |
| int hi = l.size() - 1; | |
| // We use a linear search with log(n) comparisons using an iterator | |
| // if the list is sequential-access. | |
| if (isSequential(l)) | |
| { | |
| ListIterator itr = l.listIterator(); | |
| int i = 0; | |
| while (low <= hi) | |
| { | |
| pos = (low + hi) >> 1; | |
| if (i < pos) | |
| for ( ; i != pos; i++, itr.next()); | |
| else | |
| for ( ; i != pos; i--, itr.previous()); | |
| final int d = compare(key, itr.next(), c); | |
| if (d == 0) | |
| return pos; | |
| else if (d < 0) | |
| hi = pos - 1; | |
| else | |
| // This gets the insertion point right on the last loop | |
| low = ++pos; | |
| } | |
| } | |
| else | |
| { | |
| 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 | |
| // This gets the insertion point right on the last loop | |
| low = ++pos; | |
| } | |
| } | |
| // If we failed to find it, we do the same whichever search we did. | |
| return -pos - 1; | |
| } | |
| /** | |
| * 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 | |
| * @throws IndexOutOfBoundsException if the destination list is shorter | |
| * than the source list (the destination will be unmodified) | |
| * @throws UnsupportedOperationException if dest.listIterator() does not | |
| * support the set operation | |
| */ | |
| public static void copy(List dest, List source) | |
| { | |
| int pos = source.size(); | |
| if (dest.size() < pos) | |
| throw new IndexOutOfBoundsException("Source does not fit in dest"); | |
| Iterator i1 = source.iterator(); | |
| ListIterator i2 = dest.listIterator(); | |
| while (--pos >= 0) | |
| { | |
| i2.next(); | |
| i2.set(i1.next()); | |
| } | |
| } | |
| /** | |
| * 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 | |
| * @return 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. | |
| * @throws 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); | |
| } | |
| } | |
| /** | |
| * Returns the starting index where the specified sublist first occurs | |
| * in a larger list, or -1 if there is no matching position. If | |
| * <code>target.size() > source.size()</code>, this returns -1, | |
| * otherwise this implementation uses brute force, checking for | |
| * <code>source.sublist(i, i + target.size()).equals(target)</code> | |
| * for all possible i. | |
| * | |
| * @param source the list to search | |
| * @param target the sublist to search for | |
| * @return the index where found, or -1 | |
| * @since 1.4 | |
| */ | |
| public static int indexOfSubList(List source, List target) | |
| { | |
| int ssize = source.size(); | |
| for (int i = 0, j = target.size(); j <= ssize; i++, j++) | |
| if (source.subList(i, j).equals(target)) | |
| return i; | |
| return -1; | |
| } | |
| /** | |
| * Returns the starting index where the specified sublist last occurs | |
| * in a larger list, or -1 if there is no matching position. If | |
| * <code>target.size() > source.size()</code>, this returns -1, | |
| * otherwise this implementation uses brute force, checking for | |
| * <code>source.sublist(i, i + target.size()).equals(target)</code> | |
| * for all possible i. | |
| * | |
| * @param source the list to search | |
| * @param target the sublist to search for | |
| * @return the index where found, or -1 | |
| * @since 1.4 | |
| */ | |
| public static int lastIndexOfSubList(List source, List target) | |
| { | |
| int ssize = source.size(); | |
| for (int i = ssize - target.size(), j = ssize; i >= 0; i--, j--) | |
| if (source.subList(i, j).equals(target)) | |
| return i; | |
| return -1; | |
| } | |
| /** | |
| * Returns an array list holding the elements visited by a given | |
| * Enumeration. This method exists for interoperability between legacy | |
| * APIs and the new Collection API. | |
| * | |
| * @param e the enumeration to put in a list | |
| * @return a list containing the enumeration elements | |
| * @see ArrayList | |
| * @since 1.4 | |
| */ | |
| public static List list(Enumeration e) | |
| { | |
| List l = new ArrayList(); | |
| while (e.hasMoreElements()) | |
| l.add(e.nextElement()); | |
| return l; | |
| } | |
| /** | |
| * 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 | |
| * @return 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) | |
| { | |
| return max(c, null); | |
| } | |
| /** | |
| * 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, or null for natural | |
| * ordering | |
| * @return the maximum element of c | |
| * @throws NoSuchElementException if c is empty | |
| * @throws ClassCastException if elements in c are not mutually comparable | |
| * @throws NullPointerException if null is compared by natural ordering | |
| * (only possible when order is null) | |
| */ | |
| 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 (compare(max, o, order) < 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 | |
| * @return the minimum element of c | |
| * @throws NoSuchElementException if c is empty | |
| * @throws ClassCastException if elements in c are not mutually comparable | |
| * @throws NullPointerException if null.compareTo is called | |
| */ | |
| public static Object min(Collection c) | |
| { | |
| return min(c, null); | |
| } | |
| /** | |
| * 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, or null for natural | |
| * ordering | |
| * @return the minimum element of c | |
| * @throws NoSuchElementException if c is empty | |
| * @throws ClassCastException if elements in c are not mutually comparable | |
| * @throws NullPointerException if null is compared by natural ordering | |
| * (only possible when order is null) | |
| */ | |
| 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 (compare(min, o, order) > 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, and | |
| * implements RandomAccess. You can use it in tandem with List.addAll for | |
| * fast list construction. | |
| * | |
| * @param n the number of times to repeat the object | |
| * @param o the object to repeat | |
| * @return a List consisting of n copies of o | |
| * @throws IllegalArgumentException if n < 0 | |
| * @see List#addAll(Collection) | |
| * @see Serializable | |
| * @see RandomAccess | |
| */ | |
| public static List nCopies(final int n, final Object o) | |
| { | |
| return new CopiesList(n, o); | |
| } | |
| /** | |
| * The implementation of {@link #nCopies(int, Object)}. This class name | |
| * is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class CopiesList extends AbstractList | |
| implements Serializable, RandomAccess | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 2739099268398711800L; | |
| /** | |
| * The count of elements in this list. | |
| * @serial the list size | |
| */ | |
| private final int n; | |
| /** | |
| * The repeated list element. | |
| * @serial the list contents | |
| */ | |
| private final Object element; | |
| /** | |
| * Constructs the list. | |
| * | |
| * @param n the count | |
| * @param o the object | |
| * @throws IllegalArgumentException if n < 0 | |
| */ | |
| CopiesList(int n, Object o) | |
| { | |
| if (n < 0) | |
| throw new IllegalArgumentException(); | |
| this.n = n; | |
| element = o; | |
| } | |
| /** | |
| * The size is fixed. | |
| */ | |
| public int size() | |
| { | |
| return n; | |
| } | |
| /** | |
| * The same element is returned. | |
| */ | |
| public Object get(int index) | |
| { | |
| if (index < 0 || index >= n) | |
| throw new IndexOutOfBoundsException(); | |
| return element; | |
| } | |
| // The remaining methods are optional, but provide a performance | |
| // advantage by not allocating unnecessary iterators in AbstractList. | |
| /** | |
| * This list only contains one element. | |
| */ | |
| public boolean contains(Object o) | |
| { | |
| return n > 0 && equals(o, element); | |
| } | |
| /** | |
| * The index is either 0 or -1. | |
| */ | |
| public int indexOf(Object o) | |
| { | |
| return (n > 0 && equals(o, element)) ? 0 : -1; | |
| } | |
| /** | |
| * The index is either n-1 or -1. | |
| */ | |
| public int lastIndexOf(Object o) | |
| { | |
| return equals(o, element) ? n - 1 : -1; | |
| } | |
| /** | |
| * A subList is just another CopiesList. | |
| */ | |
| public List subList(int from, int to) | |
| { | |
| if (from < 0 || to > n) | |
| throw new IndexOutOfBoundsException(); | |
| return new CopiesList(to - from, element); | |
| } | |
| /** | |
| * The array is easy. | |
| */ | |
| public Object[] toArray() | |
| { | |
| Object[] a = new Object[n]; | |
| Arrays.fill(a, element); | |
| return a; | |
| } | |
| /** | |
| * The string is easy to generate. | |
| */ | |
| public String toString() | |
| { | |
| StringBuffer r = new StringBuffer("{"); | |
| for (int i = n - 1; --i > 0; ) | |
| r.append(element).append(", "); | |
| r.append(element).append("}"); | |
| return r.toString(); | |
| } | |
| } // class CopiesList | |
| /** | |
| * Replace all instances of one object with another in the specified list. | |
| * The list does not change size. An element e is replaced if | |
| * <code>oldval == null ? e == null : oldval.equals(e)</code>. | |
| * | |
| * @param list the list to iterate over | |
| * @param oldval the element to replace | |
| * @param newval the new value for the element | |
| * @return true if a replacement occurred | |
| * @throws UnsupportedOperationException if the list iterator does not allow | |
| * for the set operation | |
| * @throws ClassCastException newval is of a type which cannot be added | |
| * to the list | |
| * @throws IllegalArgumentException some other aspect of newval stops | |
| * it being added to the list | |
| * @since 1.4 | |
| */ | |
| public static boolean replaceAll(List list, Object oldval, Object newval) | |
| { | |
| ListIterator itr = list.listIterator(); | |
| boolean replace_occured = false; | |
| for (int i = list.size(); --i >= 0; ) | |
| if (AbstractCollection.equals(oldval, itr.next())) | |
| { | |
| itr.set(newval); | |
| replace_occured = true; | |
| } | |
| return replace_occured; | |
| } | |
| /** | |
| * Reverse a given list. This method works in linear time. | |
| * | |
| * @param l the list to reverse | |
| * @throws UnsupportedOperationException if l.listIterator() does not | |
| * support the set operation | |
| */ | |
| public static void reverse(List l) | |
| { | |
| ListIterator i1 = l.listIterator(); | |
| int pos1 = 1; | |
| 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. In | |
| * other words, this sorts Comparable objects opposite of how their | |
| * compareTo method would sort. This makes it easy to sort into reverse | |
| * order, by simply passing Collections.reverseOrder() to the sort method. | |
| * The return value of this method is Serializable. | |
| * | |
| * @return a comparator that imposes reverse natural ordering | |
| * @see Comparable | |
| * @see Serializable | |
| */ | |
| public static Comparator reverseOrder() | |
| { | |
| return rcInstance; | |
| } | |
| /** | |
| * The object for {@link #reverseOrder()}. | |
| */ | |
| static private final ReverseComparator rcInstance = new ReverseComparator(); | |
| /** | |
| * The implementation of {@link #reverseOrder()}. This class name | |
| * is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class ReverseComparator | |
| implements Comparator, Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| static private final long serialVersionUID = 7207038068494060240L; | |
| /** | |
| * A private constructor adds overhead. | |
| */ | |
| ReverseComparator() | |
| { | |
| } | |
| /** | |
| * Compare two objects in reverse natural order. | |
| * | |
| * @param a the first object | |
| * @param b the second object | |
| * @return <, ==, or > 0 according to b.compareTo(a) | |
| */ | |
| public int compare(Object a, Object b) | |
| { | |
| return ((Comparable) b).compareTo(a); | |
| } | |
| } | |
| /** | |
| * Rotate the elements in a list by a specified distance. After calling this | |
| * method, the element now at index <code>i</code> was formerly at index | |
| * <code>(i - distance) mod list.size()</code>. The list size is unchanged. | |
| * <p> | |
| * | |
| * For example, suppose a list contains <code>[t, a, n, k, s]</code>. After | |
| * either <code>Collections.rotate(l, 4)</code> or | |
| * <code>Collections.rotate(l, -1)</code>, the new contents are | |
| * <code>[s, t, a, n, k]</code>. This can be applied to sublists to rotate | |
| * just a portion of the list. For example, to move element <code>a</code> | |
| * forward two positions in the original example, use | |
| * <code>Collections.rotate(l.subList(1, 3+1), -1)</code>, which will | |
| * result in <code>[t, n, k, a, s]</code>. | |
| * <p> | |
| * | |
| * If the list is small or implements {@link RandomAccess}, the | |
| * implementation exchanges the first element to its destination, then the | |
| * displaced element, and so on until a circuit has been completed. The | |
| * process is repeated if needed on the second element, and so forth, until | |
| * all elements have been swapped. For large non-random lists, the | |
| * implementation breaks the list into two sublists at index | |
| * <code>-distance mod size</code>, calls {@link #reverse(List)} on the | |
| * pieces, then reverses the overall list. | |
| * | |
| * @param list the list to rotate | |
| * @param distance the distance to rotate by; unrestricted in value | |
| * @throws UnsupportedOperationException if the list does not support set | |
| * @since 1.4 | |
| */ | |
| public static void rotate(List list, int distance) | |
| { | |
| int size = list.size(); | |
| distance %= size; | |
| if (distance == 0) | |
| return; | |
| if (distance < 0) | |
| distance += size; | |
| if (isSequential(list)) | |
| { | |
| reverse(list); | |
| reverse(list.subList(0, distance)); | |
| reverse(list.subList(distance, size)); | |
| } | |
| else | |
| { | |
| // Determine the least common multiple of distance and size, as there | |
| // are (distance / LCM) loops to cycle through. | |
| int a = size; | |
| int lcm = distance; | |
| int b = a % lcm; | |
| while (b != 0) | |
| { | |
| a = lcm; | |
| lcm = b; | |
| b = a % lcm; | |
| } | |
| // Now, make the swaps. We must take the remainder every time through | |
| // the inner loop so that we don't overflow i to negative values. | |
| while (--lcm >= 0) | |
| { | |
| Object o = list.get(lcm); | |
| for (int i = lcm + distance; i != lcm; i = (i + distance) % size) | |
| o = list.set(i, o); | |
| list.set(lcm, o); | |
| } | |
| } | |
| } | |
| /** | |
| * Shuffle a list according to a default 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 practice the results are merely very | |
| * close to perfect. | |
| * <p> | |
| * | |
| * This method operates in linear time. To do this on large lists which do | |
| * not implement {@link RandomAccess}, a temporary array is used to acheive | |
| * this speed, since it would be quadratic access otherwise. | |
| * | |
| * @param l the list to shuffle | |
| * @throws 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 occurring: 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. To do this on large lists which do | |
| * not implement {@link RandomAccess}, a temporary array is used to acheive | |
| * this speed, since it would be quadratic access otherwise. | |
| * | |
| * @param l the list to shuffle | |
| * @param r the source of randomness to use for the shuffle | |
| * @throws UnsupportedOperationException if l.listIterator() does not | |
| * support the set operation | |
| */ | |
| public static void shuffle(List l, Random r) | |
| { | |
| int lsize = l.size(); | |
| ListIterator i = l.listIterator(lsize); | |
| boolean sequential = isSequential(l); | |
| Object[] a = null; // stores a copy of the list for the sequential case | |
| if (sequential) | |
| a = l.toArray(); | |
| 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 desired element. | |
| Object o; | |
| if (sequential) | |
| { | |
| o = a[swap]; | |
| a[swap] = i.previous(); | |
| } | |
| else | |
| o = l.set(swap, 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 | |
| * @return an immutable Set containing only o | |
| * @see Serializable | |
| */ | |
| public static Set singleton(Object o) | |
| { | |
| return new SingletonSet(o); | |
| } | |
| /** | |
| * The implementation of {@link #singleton(Object)}. This class name | |
| * is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class SingletonSet extends AbstractSet | |
| implements Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 3193687207550431679L; | |
| /** | |
| * The single element; package visible for use in nested class. | |
| * @serial the singleton | |
| */ | |
| final Object element; | |
| /** | |
| * Construct a singleton. | |
| * @param o the element | |
| */ | |
| SingletonSet(Object o) | |
| { | |
| element = o; | |
| } | |
| /** | |
| * The size: always 1! | |
| */ | |
| public int size() | |
| { | |
| return 1; | |
| } | |
| /** | |
| * Returns an iterator over the lone element. | |
| */ | |
| public Iterator iterator() | |
| { | |
| return new Iterator() | |
| { | |
| private boolean hasNext = true; | |
| public boolean hasNext() | |
| { | |
| return hasNext; | |
| } | |
| public Object next() | |
| { | |
| if (hasNext) | |
| { | |
| hasNext = false; | |
| return element; | |
| } | |
| else | |
| throw new NoSuchElementException(); | |
| } | |
| public void remove() | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| }; | |
| } | |
| // The remaining methods are optional, but provide a performance | |
| // advantage by not allocating unnecessary iterators in AbstractSet. | |
| /** | |
| * The set only contains one element. | |
| */ | |
| public boolean contains(Object o) | |
| { | |
| return equals(o, element); | |
| } | |
| /** | |
| * This is true if the other collection only contains the element. | |
| */ | |
| public boolean containsAll(Collection c) | |
| { | |
| Iterator i = c.iterator(); | |
| int pos = c.size(); | |
| while (--pos >= 0) | |
| if (! equals(i.next(), element)) | |
| return false; | |
| return true; | |
| } | |
| /** | |
| * The hash is just that of the element. | |
| */ | |
| public int hashCode() | |
| { | |
| return hashCode(element); | |
| } | |
| /** | |
| * Returning an array is simple. | |
| */ | |
| public Object[] toArray() | |
| { | |
| return new Object[] {element}; | |
| } | |
| /** | |
| * Obvious string. | |
| */ | |
| public String toString() | |
| { | |
| return "[" + element + "]"; | |
| } | |
| } // class SingletonSet | |
| /** | |
| * Obtain an immutable List consisting of a single element. The return value | |
| * of this method is Serializable, and implements RandomAccess. | |
| * | |
| * @param o the single element | |
| * @return an immutable List containing only o | |
| * @see Serializable | |
| * @see RandomAccess | |
| * @since 1.3 | |
| */ | |
| public static List singletonList(Object o) | |
| { | |
| return new SingletonList(o); | |
| } | |
| /** | |
| * The implementation of {@link #singletonList(Object)}. This class name | |
| * is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class SingletonList extends AbstractList | |
| implements Serializable, RandomAccess | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 3093736618740652951L; | |
| /** | |
| * The single element. | |
| * @serial the singleton | |
| */ | |
| private final Object element; | |
| /** | |
| * Construct a singleton. | |
| * @param o the element | |
| */ | |
| SingletonList(Object o) | |
| { | |
| element = o; | |
| } | |
| /** | |
| * The size: always 1! | |
| */ | |
| public int size() | |
| { | |
| return 1; | |
| } | |
| /** | |
| * Only index 0 is valid. | |
| */ | |
| public Object get(int index) | |
| { | |
| if (index == 0) | |
| return element; | |
| throw new IndexOutOfBoundsException(); | |
| } | |
| // The remaining methods are optional, but provide a performance | |
| // advantage by not allocating unnecessary iterators in AbstractList. | |
| /** | |
| * The set only contains one element. | |
| */ | |
| public boolean contains(Object o) | |
| { | |
| return equals(o, element); | |
| } | |
| /** | |
| * This is true if the other collection only contains the element. | |
| */ | |
| public boolean containsAll(Collection c) | |
| { | |
| Iterator i = c.iterator(); | |
| int pos = c.size(); | |
| while (--pos >= 0) | |
| if (! equals(i.next(), element)) | |
| return false; | |
| return true; | |
| } | |
| /** | |
| * Speed up the hashcode computation. | |
| */ | |
| public int hashCode() | |
| { | |
| return 31 + hashCode(element); | |
| } | |
| /** | |
| * Either the list has it or not. | |
| */ | |
| public int indexOf(Object o) | |
| { | |
| return equals(o, element) ? 0 : -1; | |
| } | |
| /** | |
| * Either the list has it or not. | |
| */ | |
| public int lastIndexOf(Object o) | |
| { | |
| return equals(o, element) ? 0 : -1; | |
| } | |
| /** | |
| * Sublists are limited in scope. | |
| */ | |
| public List subList(int from, int to) | |
| { | |
| if (from == to && (to == 0 || to == 1)) | |
| return EMPTY_LIST; | |
| if (from == 0 && to == 1) | |
| return this; | |
| if (from > to) | |
| throw new IllegalArgumentException(); | |
| throw new IndexOutOfBoundsException(); | |
| } | |
| /** | |
| * Returning an array is simple. | |
| */ | |
| public Object[] toArray() | |
| { | |
| return new Object[] {element}; | |
| } | |
| /** | |
| * Obvious string. | |
| */ | |
| public String toString() | |
| { | |
| return "[" + element + "]"; | |
| } | |
| } // class SingletonList | |
| /** | |
| * 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 | |
| * @return an immutable Map containing only the single key-value pair | |
| * @see Serializable | |
| * @since 1.3 | |
| */ | |
| public static Map singletonMap(Object key, Object value) | |
| { | |
| return new SingletonMap(key, value); | |
| } | |
| /** | |
| * The implementation of {@link #singletonMap(Object)}. This class name | |
| * is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class SingletonMap extends AbstractMap | |
| implements Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -6979724477215052911L; | |
| /** | |
| * The single key. | |
| * @serial the singleton key | |
| */ | |
| private final Object k; | |
| /** | |
| * The corresponding value. | |
| * @serial the singleton value | |
| */ | |
| private final Object v; | |
| /** | |
| * Cache the entry set. | |
| */ | |
| private transient Set entries; | |
| /** | |
| * Construct a singleton. | |
| * @param key the key | |
| * @param value the value | |
| */ | |
| SingletonMap(Object key, Object value) | |
| { | |
| k = key; | |
| v = value; | |
| } | |
| /** | |
| * There is a single immutable entry. | |
| */ | |
| public Set entrySet() | |
| { | |
| if (entries == null) | |
| entries = singleton(new BasicMapEntry(k, v) | |
| { | |
| public Object setValue(Object o) | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| }); | |
| return entries; | |
| } | |
| // The remaining methods are optional, but provide a performance | |
| // advantage by not allocating unnecessary iterators in AbstractMap. | |
| /** | |
| * Single entry. | |
| */ | |
| public boolean containsKey(Object key) | |
| { | |
| return equals(key, k); | |
| } | |
| /** | |
| * Single entry. | |
| */ | |
| public boolean containsValue(Object value) | |
| { | |
| return equals(value, v); | |
| } | |
| /** | |
| * Single entry. | |
| */ | |
| public Object get(Object key) | |
| { | |
| return equals(key, k) ? v : null; | |
| } | |
| /** | |
| * Calculate the hashcode directly. | |
| */ | |
| public int hashCode() | |
| { | |
| return hashCode(k) ^ hashCode(v); | |
| } | |
| /** | |
| * Return the keyset. | |
| */ | |
| public Set keySet() | |
| { | |
| if (keys == null) | |
| keys = singleton(k); | |
| return keys; | |
| } | |
| /** | |
| * The size: always 1! | |
| */ | |
| public int size() | |
| { | |
| return 1; | |
| } | |
| /** | |
| * Return the values. Technically, a singleton, while more specific than | |
| * a general Collection, will work. Besides, that's what the JDK uses! | |
| */ | |
| public Collection values() | |
| { | |
| if (values == null) | |
| values = singleton(v); | |
| return values; | |
| } | |
| /** | |
| * Obvious string. | |
| */ | |
| public String toString() | |
| { | |
| return "{" + k + "=" + v + "}"; | |
| } | |
| } // class SingletonMap | |
| /** | |
| * 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 | |
| * @throws ClassCastException if some items are not mutually comparable | |
| * @throws UnsupportedOperationException if the List is not modifiable | |
| * @throws NullPointerException if some element is null | |
| * @see Arrays#sort(Object[]) | |
| */ | |
| public static void sort(List l) | |
| { | |
| sort(l, null); | |
| } | |
| /** | |
| * 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, or | |
| * null for natural ordering | |
| * @throws ClassCastException if c will not compare some pair of items | |
| * @throws UnsupportedOperationException if the List is not modifiable | |
| * @throws NullPointerException if null is compared by natural ordering | |
| * (only possible when c is null) | |
| * @see Arrays#sort(Object[], Comparator) | |
| */ | |
| public static void sort(List l, Comparator c) | |
| { | |
| Object[] a = l.toArray(); | |
| Arrays.sort(a, c); | |
| ListIterator i = l.listIterator(a.length); | |
| for (int pos = a.length; --pos >= 0; ) | |
| { | |
| i.previous(); | |
| i.set(a[pos]); | |
| } | |
| } | |
| /** | |
| * Swaps the elements at the specified positions within the list. Equal | |
| * positions have no effect. | |
| * | |
| * @param l the list to work on | |
| * @param i the first index to swap | |
| * @param j the second index | |
| * @throws UnsupportedOperationException if list.set is not supported | |
| * @throws IndexOutOfBoundsException if either i or j is < 0 or >= | |
| * list.size() | |
| * @since 1.4 | |
| */ | |
| public static void swap(List l, int i, int j) | |
| { | |
| l.set(i, l.set(j, l.get(i))); | |
| } | |
| /** | |
| * Returns a synchronized (thread-safe) collection wrapper backed by the | |
| * given collection. Notice that element access through the iterators | |
| * is thread-safe, but if the collection can be structurally modified | |
| * (adding or removing elements) then you should synchronize around the | |
| * iteration to avoid non-deterministic behavior:<br> | |
| * <pre> | |
| * Collection c = Collections.synchronizedCollection(new Collection(...)); | |
| * ... | |
| * synchronized (c) | |
| * { | |
| * Iterator i = c.iterator(); | |
| * while (i.hasNext()) | |
| * foo(i.next()); | |
| * } | |
| * </pre><p> | |
| * | |
| * Since the collection might be a List or a Set, and those have incompatible | |
| * equals and hashCode requirements, this relies on Object's implementation | |
| * rather than passing those calls on to the wrapped collection. The returned | |
| * Collection implements Serializable, but can only be serialized if | |
| * the collection it wraps is likewise Serializable. | |
| * | |
| * @param c the collection to wrap | |
| * @return a synchronized view of the collection | |
| * @see Serializable | |
| */ | |
| public static Collection synchronizedCollection(Collection c) | |
| { | |
| return new SynchronizedCollection(c); | |
| } | |
| /** | |
| * The implementation of {@link #synchronizedCollection(Collection)}. This | |
| * class name is required for compatibility with Sun's JDK serializability. | |
| * Package visible, so that collections such as the one for | |
| * Hashtable.values() can specify which object to synchronize on. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| static class SynchronizedCollection | |
| implements Collection, Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 3053995032091335093L; | |
| /** | |
| * The wrapped collection. Package visible for use by subclasses. | |
| * @serial the real collection | |
| */ | |
| final Collection c; | |
| /** | |
| * The object to synchronize on. When an instance is created via public | |
| * methods, it will be this; but other uses like SynchronizedMap.values() | |
| * must specify another mutex. Package visible for use by subclasses. | |
| * @serial the lock | |
| */ | |
| final Object mutex; | |
| /** | |
| * Wrap a given collection. | |
| * @param c the collection to wrap | |
| * @throws NullPointerException if c is null | |
| */ | |
| SynchronizedCollection(Collection c) | |
| { | |
| this.c = c; | |
| mutex = this; | |
| if (c == null) | |
| throw new NullPointerException(); | |
| } | |
| /** | |
| * Called only by trusted code to specify the mutex as well as the | |
| * collection. | |
| * @param sync the mutex | |
| * @param c the collection | |
| */ | |
| SynchronizedCollection(Object sync, Collection c) | |
| { | |
| this.c = c; | |
| mutex = sync; | |
| } | |
| public boolean add(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.add(o); | |
| } | |
| } | |
| public boolean addAll(Collection col) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.addAll(col); | |
| } | |
| } | |
| public void clear() | |
| { | |
| synchronized (mutex) | |
| { | |
| c.clear(); | |
| } | |
| } | |
| public boolean contains(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.contains(o); | |
| } | |
| } | |
| public boolean containsAll(Collection c1) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.containsAll(c1); | |
| } | |
| } | |
| public boolean isEmpty() | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.isEmpty(); | |
| } | |
| } | |
| public Iterator iterator() | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedIterator(mutex, c.iterator()); | |
| } | |
| } | |
| public boolean remove(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.remove(o); | |
| } | |
| } | |
| public boolean removeAll(Collection col) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.removeAll(col); | |
| } | |
| } | |
| public boolean retainAll(Collection col) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.retainAll(col); | |
| } | |
| } | |
| public int size() | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.size(); | |
| } | |
| } | |
| public Object[] toArray() | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.toArray(); | |
| } | |
| } | |
| public Object[] toArray(Object[] a) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.toArray(a); | |
| } | |
| } | |
| public String toString() | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.toString(); | |
| } | |
| } | |
| } // class SynchronizedCollection | |
| /** | |
| * The implementation of the various iterator methods in the | |
| * synchronized classes. These iterators must "sync" on the same object | |
| * as the collection they iterate over. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class SynchronizedIterator implements Iterator | |
| { | |
| /** | |
| * The object to synchronize on. Package visible for use by subclass. | |
| */ | |
| final Object mutex; | |
| /** | |
| * The wrapped iterator. | |
| */ | |
| private final Iterator i; | |
| /** | |
| * Only trusted code creates a wrapper, with the specified sync. | |
| * @param sync the mutex | |
| * @param i the wrapped iterator | |
| */ | |
| SynchronizedIterator(Object sync, Iterator i) | |
| { | |
| this.i = i; | |
| mutex = sync; | |
| } | |
| public Object next() | |
| { | |
| synchronized (mutex) | |
| { | |
| return i.next(); | |
| } | |
| } | |
| public boolean hasNext() | |
| { | |
| synchronized (mutex) | |
| { | |
| return i.hasNext(); | |
| } | |
| } | |
| public void remove() | |
| { | |
| synchronized (mutex) | |
| { | |
| i.remove(); | |
| } | |
| } | |
| } // class SynchronizedIterator | |
| /** | |
| * Returns a synchronized (thread-safe) list wrapper backed by the | |
| * given list. Notice that element access through the iterators | |
| * is thread-safe, but if the list can be structurally modified | |
| * (adding or removing elements) then you should synchronize around the | |
| * iteration to avoid non-deterministic behavior:<br> | |
| * <pre> | |
| * List l = Collections.synchronizedList(new List(...)); | |
| * ... | |
| * synchronized (l) | |
| * { | |
| * Iterator i = l.iterator(); | |
| * while (i.hasNext()) | |
| * foo(i.next()); | |
| * } | |
| * </pre><p> | |
| * | |
| * The returned List implements Serializable, but can only be serialized if | |
| * the list it wraps is likewise Serializable. In addition, if the wrapped | |
| * list implements RandomAccess, this does too. | |
| * | |
| * @param l the list to wrap | |
| * @return a synchronized view of the list | |
| * @see Serializable | |
| * @see RandomAccess | |
| */ | |
| public static List synchronizedList(List l) | |
| { | |
| if (l instanceof RandomAccess) | |
| return new SynchronizedRandomAccessList(l); | |
| return new SynchronizedList(l); | |
| } | |
| /** | |
| * The implementation of {@link #synchronizedList(List)} for sequential | |
| * lists. This class name is required for compatibility with Sun's JDK | |
| * serializability. Package visible, so that lists such as Vector.subList() | |
| * can specify which object to synchronize on. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| static class SynchronizedList extends SynchronizedCollection | |
| implements List | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -7754090372962971524L; | |
| /** | |
| * The wrapped list; stored both here and in the superclass to avoid | |
| * excessive casting. Package visible for use by subclass. | |
| * @serial the wrapped list | |
| */ | |
| final List list; | |
| /** | |
| * Wrap a given list. | |
| * @param l the list to wrap | |
| * @throws NullPointerException if l is null | |
| */ | |
| SynchronizedList(List l) | |
| { | |
| super(l); | |
| list = l; | |
| } | |
| /** | |
| * Called only by trusted code to specify the mutex as well as the list. | |
| * @param sync the mutex | |
| * @param l the list | |
| */ | |
| SynchronizedList(Object sync, List l) | |
| { | |
| super(sync, l); | |
| list = l; | |
| } | |
| public void add(int index, Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| list.add(index, o); | |
| } | |
| } | |
| public boolean addAll(int index, Collection c) | |
| { | |
| synchronized (mutex) | |
| { | |
| return list.addAll(index, c); | |
| } | |
| } | |
| public boolean equals(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return list.equals(o); | |
| } | |
| } | |
| public Object get(int index) | |
| { | |
| synchronized (mutex) | |
| { | |
| return list.get(index); | |
| } | |
| } | |
| public int hashCode() | |
| { | |
| synchronized (mutex) | |
| { | |
| return list.hashCode(); | |
| } | |
| } | |
| public int indexOf(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return list.indexOf(o); | |
| } | |
| } | |
| public int lastIndexOf(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return list.lastIndexOf(o); | |
| } | |
| } | |
| public ListIterator listIterator() | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedListIterator(mutex, list.listIterator()); | |
| } | |
| } | |
| public ListIterator listIterator(int index) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedListIterator(mutex, list.listIterator(index)); | |
| } | |
| } | |
| public Object remove(int index) | |
| { | |
| synchronized (mutex) | |
| { | |
| return list.remove(index); | |
| } | |
| } | |
| public Object set(int index, Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return list.set(index, o); | |
| } | |
| } | |
| public List subList(int fromIndex, int toIndex) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedList(mutex, list.subList(fromIndex, toIndex)); | |
| } | |
| } | |
| } // class SynchronizedList | |
| /** | |
| * The implementation of {@link #synchronizedList(List)} for random-access | |
| * lists. This class name is required for compatibility with Sun's JDK | |
| * serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class SynchronizedRandomAccessList | |
| extends SynchronizedList implements RandomAccess | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 1530674583602358482L; | |
| /** | |
| * Wrap a given list. | |
| * @param l the list to wrap | |
| * @throws NullPointerException if l is null | |
| */ | |
| SynchronizedRandomAccessList(List l) | |
| { | |
| super(l); | |
| } | |
| /** | |
| * Called only by trusted code to specify the mutex as well as the | |
| * collection. | |
| * @param sync the mutex | |
| * @param l the list | |
| */ | |
| SynchronizedRandomAccessList(Object sync, List l) | |
| { | |
| super(sync, l); | |
| } | |
| public List subList(int fromIndex, int toIndex) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedRandomAccessList(mutex, | |
| list.subList(fromIndex, | |
| toIndex)); | |
| } | |
| } | |
| } // class SynchronizedRandomAccessList | |
| /** | |
| * The implementation of {@link SynchronizedList#listIterator()}. This | |
| * iterator must "sync" on the same object as the list it iterates over. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class SynchronizedListIterator | |
| extends SynchronizedIterator implements ListIterator | |
| { | |
| /** | |
| * The wrapped iterator, stored both here and in the superclass to | |
| * avoid excessive casting. | |
| */ | |
| private final ListIterator li; | |
| /** | |
| * Only trusted code creates a wrapper, with the specified sync. | |
| * @param sync the mutex | |
| * @param li the wrapped iterator | |
| */ | |
| SynchronizedListIterator(Object sync, ListIterator li) | |
| { | |
| super(sync, li); | |
| this.li = li; | |
| } | |
| public void add(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| li.add(o); | |
| } | |
| } | |
| public boolean hasPrevious() | |
| { | |
| synchronized (mutex) | |
| { | |
| return li.hasPrevious(); | |
| } | |
| } | |
| public int nextIndex() | |
| { | |
| synchronized (mutex) | |
| { | |
| return li.nextIndex(); | |
| } | |
| } | |
| public Object previous() | |
| { | |
| synchronized (mutex) | |
| { | |
| return li.previous(); | |
| } | |
| } | |
| public int previousIndex() | |
| { | |
| synchronized (mutex) | |
| { | |
| return li.previousIndex(); | |
| } | |
| } | |
| public void set(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| li.set(o); | |
| } | |
| } | |
| } // class SynchronizedListIterator | |
| /** | |
| * Returns a synchronized (thread-safe) map wrapper backed by the given | |
| * map. Notice that element access through the collection views and their | |
| * iterators are thread-safe, but if the map can be structurally modified | |
| * (adding or removing elements) then you should synchronize around the | |
| * iteration to avoid non-deterministic behavior:<br> | |
| * <pre> | |
| * Map m = Collections.synchronizedMap(new Map(...)); | |
| * ... | |
| * Set s = m.keySet(); // safe outside a synchronized block | |
| * synchronized (m) // synch on m, not s | |
| * { | |
| * Iterator i = s.iterator(); | |
| * while (i.hasNext()) | |
| * foo(i.next()); | |
| * } | |
| * </pre><p> | |
| * | |
| * The returned Map implements Serializable, but can only be serialized if | |
| * the map it wraps is likewise Serializable. | |
| * | |
| * @param m the map to wrap | |
| * @return a synchronized view of the map | |
| * @see Serializable | |
| */ | |
| public static Map synchronizedMap(Map m) | |
| { | |
| return new SynchronizedMap(m); | |
| } | |
| /** | |
| * The implementation of {@link #synchronizedMap(Map)}. This | |
| * class name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class SynchronizedMap implements Map, Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 1978198479659022715L; | |
| /** | |
| * The wrapped map. | |
| * @serial the real map | |
| */ | |
| private final Map m; | |
| /** | |
| * The object to synchronize on. When an instance is created via public | |
| * methods, it will be this; but other uses like | |
| * SynchronizedSortedMap.subMap() must specify another mutex. Package | |
| * visible for use by subclass. | |
| * @serial the lock | |
| */ | |
| final Object mutex; | |
| /** | |
| * Cache the entry set. | |
| */ | |
| private transient Set entries; | |
| /** | |
| * Cache the key set. | |
| */ | |
| private transient Set keys; | |
| /** | |
| * Cache the value collection. | |
| */ | |
| private transient Collection values; | |
| /** | |
| * Wrap a given map. | |
| * @param m the map to wrap | |
| * @throws NullPointerException if m is null | |
| */ | |
| SynchronizedMap(Map m) | |
| { | |
| this.m = m; | |
| mutex = this; | |
| if (m == null) | |
| throw new NullPointerException(); | |
| } | |
| /** | |
| * Called only by trusted code to specify the mutex as well as the map. | |
| * @param sync the mutex | |
| * @param m the map | |
| */ | |
| SynchronizedMap(Object sync, Map m) | |
| { | |
| this.m = m; | |
| mutex = sync; | |
| } | |
| public void clear() | |
| { | |
| synchronized (mutex) | |
| { | |
| m.clear(); | |
| } | |
| } | |
| public boolean containsKey(Object key) | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.containsKey(key); | |
| } | |
| } | |
| public boolean containsValue(Object value) | |
| { | |
| synchronized (mutex) | |
| { | |
| 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 whose next() method returns a | |
| // synchronized wrapper around its normal return value". | |
| public Set entrySet() | |
| { | |
| // Define this here to spare some nesting. | |
| class SynchronizedMapEntry implements Map.Entry | |
| { | |
| final Map.Entry e; | |
| SynchronizedMapEntry(Object o) | |
| { | |
| e = (Map.Entry) o; | |
| } | |
| public boolean equals(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return e.equals(o); | |
| } | |
| } | |
| public Object getKey() | |
| { | |
| synchronized (mutex) | |
| { | |
| return e.getKey(); | |
| } | |
| } | |
| public Object getValue() | |
| { | |
| synchronized (mutex) | |
| { | |
| return e.getValue(); | |
| } | |
| } | |
| public int hashCode() | |
| { | |
| synchronized (mutex) | |
| { | |
| return e.hashCode(); | |
| } | |
| } | |
| public Object setValue(Object value) | |
| { | |
| synchronized (mutex) | |
| { | |
| return e.setValue(value); | |
| } | |
| } | |
| public String toString() | |
| { | |
| synchronized (mutex) | |
| { | |
| return e.toString(); | |
| } | |
| } | |
| } // class SynchronizedMapEntry | |
| // Now the actual code. | |
| if (entries == null) | |
| synchronized (mutex) | |
| { | |
| entries = new SynchronizedSet(mutex, m.entrySet()) | |
| { | |
| public Iterator iterator() | |
| { | |
| synchronized (super.mutex) | |
| { | |
| return new SynchronizedIterator(super.mutex, c.iterator()) | |
| { | |
| public Object next() | |
| { | |
| synchronized (super.mutex) | |
| { | |
| return new SynchronizedMapEntry(super.next()); | |
| } | |
| } | |
| }; | |
| } | |
| } | |
| }; | |
| } | |
| return entries; | |
| } | |
| public boolean equals(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.equals(o); | |
| } | |
| } | |
| public Object get(Object key) | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.get(key); | |
| } | |
| } | |
| public int hashCode() | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.hashCode(); | |
| } | |
| } | |
| public boolean isEmpty() | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.isEmpty(); | |
| } | |
| } | |
| public Set keySet() | |
| { | |
| if (keys == null) | |
| synchronized (mutex) | |
| { | |
| keys = new SynchronizedSet(mutex, m.keySet()); | |
| } | |
| return keys; | |
| } | |
| public Object put(Object key, Object value) | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.put(key, value); | |
| } | |
| } | |
| public void putAll(Map map) | |
| { | |
| synchronized (mutex) | |
| { | |
| m.putAll(map); | |
| } | |
| } | |
| public Object remove(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.remove(o); | |
| } | |
| } | |
| public int size() | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.size(); | |
| } | |
| } | |
| public String toString() | |
| { | |
| synchronized (mutex) | |
| { | |
| return m.toString(); | |
| } | |
| } | |
| public Collection values() | |
| { | |
| if (values == null) | |
| synchronized (mutex) | |
| { | |
| values = new SynchronizedCollection(mutex, m.values()); | |
| } | |
| return values; | |
| } | |
| } // class SynchronizedMap | |
| /** | |
| * Returns a synchronized (thread-safe) set wrapper backed by the given | |
| * set. Notice that element access through the iterator is thread-safe, but | |
| * if the set can be structurally modified (adding or removing elements) | |
| * then you should synchronize around the iteration to avoid | |
| * non-deterministic behavior:<br> | |
| * <pre> | |
| * Set s = Collections.synchronizedSet(new Set(...)); | |
| * ... | |
| * synchronized (s) | |
| * { | |
| * Iterator i = s.iterator(); | |
| * while (i.hasNext()) | |
| * foo(i.next()); | |
| * } | |
| * </pre><p> | |
| * | |
| * The returned Set implements Serializable, but can only be serialized if | |
| * the set it wraps is likewise Serializable. | |
| * | |
| * @param s the set to wrap | |
| * @return a synchronized view of the set | |
| * @see Serializable | |
| */ | |
| public static Set synchronizedSet(Set s) | |
| { | |
| return new SynchronizedSet(s); | |
| } | |
| /** | |
| * The implementation of {@link #synchronizedSet(Set)}. This class | |
| * name is required for compatibility with Sun's JDK serializability. | |
| * Package visible, so that sets such as Hashtable.keySet() | |
| * can specify which object to synchronize on. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| static class SynchronizedSet extends SynchronizedCollection | |
| implements Set | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 487447009682186044L; | |
| /** | |
| * Wrap a given set. | |
| * @param s the set to wrap | |
| * @throws NullPointerException if s is null | |
| */ | |
| SynchronizedSet(Set s) | |
| { | |
| super(s); | |
| } | |
| /** | |
| * Called only by trusted code to specify the mutex as well as the set. | |
| * @param sync the mutex | |
| * @param s the set | |
| */ | |
| SynchronizedSet(Object sync, Set s) | |
| { | |
| super(sync, s); | |
| } | |
| public boolean equals(Object o) | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.equals(o); | |
| } | |
| } | |
| public int hashCode() | |
| { | |
| synchronized (mutex) | |
| { | |
| return c.hashCode(); | |
| } | |
| } | |
| } // class SynchronizedSet | |
| /** | |
| * Returns a synchronized (thread-safe) sorted map wrapper backed by the | |
| * given map. Notice that element access through the collection views, | |
| * subviews, and their iterators are thread-safe, but if the map can be | |
| * structurally modified (adding or removing elements) then you should | |
| * synchronize around the iteration to avoid non-deterministic behavior:<br> | |
| * <pre> | |
| * SortedMap m = Collections.synchronizedSortedMap(new SortedMap(...)); | |
| * ... | |
| * Set s = m.keySet(); // safe outside a synchronized block | |
| * SortedMap m2 = m.headMap(foo); // safe outside a synchronized block | |
| * Set s2 = m2.keySet(); // safe outside a synchronized block | |
| * synchronized (m) // synch on m, not m2, s or s2 | |
| * { | |
| * Iterator i = s.iterator(); | |
| * while (i.hasNext()) | |
| * foo(i.next()); | |
| * i = s2.iterator(); | |
| * while (i.hasNext()) | |
| * bar(i.next()); | |
| * } | |
| * </pre><p> | |
| * | |
| * The returned SortedMap implements Serializable, but can only be | |
| * serialized if the map it wraps is likewise Serializable. | |
| * | |
| * @param m the sorted map to wrap | |
| * @return a synchronized view of the sorted map | |
| * @see Serializable | |
| */ | |
| public static SortedMap synchronizedSortedMap(SortedMap m) | |
| { | |
| return new SynchronizedSortedMap(m); | |
| } | |
| /** | |
| * The implementation of {@link #synchronizedSortedMap(SortedMap)}. This | |
| * class name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class SynchronizedSortedMap extends SynchronizedMap | |
| implements SortedMap | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -8798146769416483793L; | |
| /** | |
| * The wrapped map; stored both here and in the superclass to avoid | |
| * excessive casting. | |
| * @serial the wrapped map | |
| */ | |
| private final SortedMap sm; | |
| /** | |
| * Wrap a given map. | |
| * @param sm the map to wrap | |
| * @throws NullPointerException if sm is null | |
| */ | |
| SynchronizedSortedMap(SortedMap sm) | |
| { | |
| super(sm); | |
| this.sm = sm; | |
| } | |
| /** | |
| * Called only by trusted code to specify the mutex as well as the map. | |
| * @param sync the mutex | |
| * @param sm the map | |
| */ | |
| SynchronizedSortedMap(Object sync, SortedMap sm) | |
| { | |
| super(sync, sm); | |
| this.sm = sm; | |
| } | |
| public Comparator comparator() | |
| { | |
| synchronized (mutex) | |
| { | |
| return sm.comparator(); | |
| } | |
| } | |
| public Object firstKey() | |
| { | |
| synchronized (mutex) | |
| { | |
| return sm.firstKey(); | |
| } | |
| } | |
| public SortedMap headMap(Object toKey) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedSortedMap(mutex, sm.headMap(toKey)); | |
| } | |
| } | |
| public Object lastKey() | |
| { | |
| synchronized (mutex) | |
| { | |
| return sm.lastKey(); | |
| } | |
| } | |
| public SortedMap subMap(Object fromKey, Object toKey) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedSortedMap(mutex, sm.subMap(fromKey, toKey)); | |
| } | |
| } | |
| public SortedMap tailMap(Object fromKey) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedSortedMap(mutex, sm.tailMap(fromKey)); | |
| } | |
| } | |
| } // class SynchronizedSortedMap | |
| /** | |
| * Returns a synchronized (thread-safe) sorted set wrapper backed by the | |
| * given set. Notice that element access through the iterator and through | |
| * subviews are thread-safe, but if the set can be structurally modified | |
| * (adding or removing elements) then you should synchronize around the | |
| * iteration to avoid non-deterministic behavior:<br> | |
| * <pre> | |
| * SortedSet s = Collections.synchronizedSortedSet(new SortedSet(...)); | |
| * ... | |
| * SortedSet s2 = s.headSet(foo); // safe outside a synchronized block | |
| * synchronized (s) // synch on s, not s2 | |
| * { | |
| * Iterator i = s2.iterator(); | |
| * while (i.hasNext()) | |
| * foo(i.next()); | |
| * } | |
| * </pre><p> | |
| * | |
| * The returned SortedSet implements Serializable, but can only be | |
| * serialized if the set it wraps is likewise Serializable. | |
| * | |
| * @param s the sorted set to wrap | |
| * @return a synchronized view of the sorted set | |
| * @see Serializable | |
| */ | |
| public static SortedSet synchronizedSortedSet(SortedSet s) | |
| { | |
| return new SynchronizedSortedSet(s); | |
| } | |
| /** | |
| * The implementation of {@link #synchronizedSortedSet(SortedSet)}. This | |
| * class name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class SynchronizedSortedSet extends SynchronizedSet | |
| implements SortedSet | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 8695801310862127406L; | |
| /** | |
| * The wrapped set; stored both here and in the superclass to avoid | |
| * excessive casting. | |
| * @serial the wrapped set | |
| */ | |
| private final SortedSet ss; | |
| /** | |
| * Wrap a given set. | |
| * @param ss the set to wrap | |
| * @throws NullPointerException if ss is null | |
| */ | |
| SynchronizedSortedSet(SortedSet ss) | |
| { | |
| super(ss); | |
| this.ss = ss; | |
| } | |
| /** | |
| * Called only by trusted code to specify the mutex as well as the set. | |
| * @param sync the mutex | |
| * @param l the list | |
| */ | |
| SynchronizedSortedSet(Object sync, SortedSet ss) | |
| { | |
| super(sync, ss); | |
| this.ss = ss; | |
| } | |
| public Comparator comparator() | |
| { | |
| synchronized (mutex) | |
| { | |
| return ss.comparator(); | |
| } | |
| } | |
| public Object first() | |
| { | |
| synchronized (mutex) | |
| { | |
| return ss.first(); | |
| } | |
| } | |
| public SortedSet headSet(Object toElement) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedSortedSet(mutex, ss.headSet(toElement)); | |
| } | |
| } | |
| public Object last() | |
| { | |
| synchronized (mutex) | |
| { | |
| return ss.last(); | |
| } | |
| } | |
| public SortedSet subSet(Object fromElement, Object toElement) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedSortedSet(mutex, | |
| ss.subSet(fromElement, toElement)); | |
| } | |
| } | |
| public SortedSet tailSet(Object fromElement) | |
| { | |
| synchronized (mutex) | |
| { | |
| return new SynchronizedSortedSet(mutex, ss.tailSet(fromElement)); | |
| } | |
| } | |
| } // class SynchronizedSortedSet | |
| /** | |
| * Returns an unmodifiable view of the given collection. This allows | |
| * "read-only" access, although changes in the backing collection show up | |
| * in this view. Attempts to modify the collection directly or via iterators | |
| * will fail with {@link UnsupportedOperationException}. | |
| * <p> | |
| * | |
| * Since the collection might be a List or a Set, and those have incompatible | |
| * equals and hashCode requirements, this relies on Object's implementation | |
| * rather than passing those calls on to the wrapped collection. The returned | |
| * Collection implements Serializable, but can only be serialized if | |
| * the collection it wraps is likewise Serializable. | |
| * | |
| * @param c the collection to wrap | |
| * @return a read-only view of the collection | |
| * @see Serializable | |
| */ | |
| public static Collection unmodifiableCollection(Collection c) | |
| { | |
| return new UnmodifiableCollection(c); | |
| } | |
| /** | |
| * The implementation of {@link #unmodifiableCollection(Collection)}. This | |
| * class name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class UnmodifiableCollection | |
| implements Collection, Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 1820017752578914078L; | |
| /** | |
| * The wrapped collection. Package visible for use by subclasses. | |
| * @serial the real collection | |
| */ | |
| final Collection c; | |
| /** | |
| * Wrap a given collection. | |
| * @param c the collection to wrap | |
| * @throws NullPointerException if c is null | |
| */ | |
| UnmodifiableCollection(Collection c) | |
| { | |
| this.c = c; | |
| if (c == null) | |
| throw new NullPointerException(); | |
| } | |
| 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(); | |
| } | |
| } // class UnmodifiableCollection | |
| /** | |
| * The implementation of the various iterator methods in the | |
| * unmodifiable classes. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class UnmodifiableIterator implements Iterator | |
| { | |
| /** | |
| * The wrapped iterator. | |
| */ | |
| private final Iterator i; | |
| /** | |
| * Only trusted code creates a wrapper. | |
| * @param i the wrapped iterator | |
| */ | |
| UnmodifiableIterator(Iterator i) | |
| { | |
| this.i = i; | |
| } | |
| public Object next() | |
| { | |
| return i.next(); | |
| } | |
| public boolean hasNext() | |
| { | |
| return i.hasNext(); | |
| } | |
| public void remove() | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| } // class UnmodifiableIterator | |
| /** | |
| * Returns an unmodifiable view of the given list. This allows | |
| * "read-only" access, although changes in the backing list show up | |
| * in this view. Attempts to modify the list directly, via iterators, or | |
| * via sublists, will fail with {@link UnsupportedOperationException}. | |
| * <p> | |
| * | |
| * The returned List implements Serializable, but can only be serialized if | |
| * the list it wraps is likewise Serializable. In addition, if the wrapped | |
| * list implements RandomAccess, this does too. | |
| * | |
| * @param l the list to wrap | |
| * @return a read-only view of the list | |
| * @see Serializable | |
| * @see RandomAccess | |
| */ | |
| public static List unmodifiableList(List l) | |
| { | |
| if (l instanceof RandomAccess) | |
| return new UnmodifiableRandomAccessList(l); | |
| return new UnmodifiableList(l); | |
| } | |
| /** | |
| * The implementation of {@link #unmodifiableList(List)} for sequential | |
| * lists. This class name is required for compatibility with Sun's JDK | |
| * serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class UnmodifiableList extends UnmodifiableCollection | |
| implements List | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -283967356065247728L; | |
| /** | |
| * The wrapped list; stored both here and in the superclass to avoid | |
| * excessive casting. Package visible for use by subclass. | |
| * @serial the wrapped list | |
| */ | |
| final List list; | |
| /** | |
| * Wrap a given list. | |
| * @param l the list to wrap | |
| * @throws NullPointerException if l is null | |
| */ | |
| UnmodifiableList(List l) | |
| { | |
| super(l); | |
| list = 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 list.equals(o); | |
| } | |
| public Object get(int index) | |
| { | |
| return list.get(index); | |
| } | |
| public int hashCode() | |
| { | |
| return list.hashCode(); | |
| } | |
| public int indexOf(Object o) | |
| { | |
| return list.indexOf(o); | |
| } | |
| public int lastIndexOf(Object o) | |
| { | |
| return list.lastIndexOf(o); | |
| } | |
| public ListIterator listIterator() | |
| { | |
| return new UnmodifiableListIterator(list.listIterator()); | |
| } | |
| public ListIterator listIterator(int index) | |
| { | |
| return new UnmodifiableListIterator(list.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 unmodifiableList(list.subList(fromIndex, toIndex)); | |
| } | |
| } // class UnmodifiableList | |
| /** | |
| * The implementation of {@link #unmodifiableList(List)} for random-access | |
| * lists. This class name is required for compatibility with Sun's JDK | |
| * serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class UnmodifiableRandomAccessList | |
| extends UnmodifiableList implements RandomAccess | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -2542308836966382001L; | |
| /** | |
| * Wrap a given list. | |
| * @param l the list to wrap | |
| * @throws NullPointerException if l is null | |
| */ | |
| UnmodifiableRandomAccessList(List l) | |
| { | |
| super(l); | |
| } | |
| } // class UnmodifiableRandomAccessList | |
| /** | |
| * The implementation of {@link UnmodifiableList#listIterator()}. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class UnmodifiableListIterator | |
| extends UnmodifiableIterator implements ListIterator | |
| { | |
| /** | |
| * The wrapped iterator, stored both here and in the superclass to | |
| * avoid excessive casting. | |
| */ | |
| private final ListIterator li; | |
| /** | |
| * Only trusted code creates a wrapper. | |
| * @param li the wrapped iterator | |
| */ | |
| UnmodifiableListIterator(ListIterator li) | |
| { | |
| super(li); | |
| this.li = li; | |
| } | |
| public void add(Object o) | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| public boolean hasPrevious() | |
| { | |
| return li.hasPrevious(); | |
| } | |
| public int nextIndex() | |
| { | |
| return li.nextIndex(); | |
| } | |
| public Object previous() | |
| { | |
| return li.previous(); | |
| } | |
| public int previousIndex() | |
| { | |
| return li.previousIndex(); | |
| } | |
| public void set(Object o) | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| } // class UnmodifiableListIterator | |
| /** | |
| * Returns an unmodifiable view of the given map. This allows "read-only" | |
| * access, although changes in the backing map show up in this view. | |
| * Attempts to modify the map directly, or via collection views or their | |
| * iterators will fail with {@link UnsupportedOperationException}. | |
| * <p> | |
| * | |
| * The returned Map implements Serializable, but can only be serialized if | |
| * the map it wraps is likewise Serializable. | |
| * | |
| * @param m the map to wrap | |
| * @return a read-only view of the map | |
| * @see Serializable | |
| */ | |
| public static Map unmodifiableMap(Map m) | |
| { | |
| return new UnmodifiableMap(m); | |
| } | |
| /** | |
| * The implementation of {@link #unmodifiableMap(Map)}. This | |
| * class name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class UnmodifiableMap implements Map, Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -1034234728574286014L; | |
| /** | |
| * The wrapped map. | |
| * @serial the real map | |
| */ | |
| private final Map m; | |
| /** | |
| * Cache the entry set. | |
| */ | |
| private transient Set entries; | |
| /** | |
| * Cache the key set. | |
| */ | |
| private transient Set keys; | |
| /** | |
| * Cache the value collection. | |
| */ | |
| private transient Collection values; | |
| /** | |
| * Wrap a given map. | |
| * @param m the map to wrap | |
| * @throws NullPointerException if m is null | |
| */ | |
| UnmodifiableMap(Map m) | |
| { | |
| this.m = m; | |
| if (m == null) | |
| throw new NullPointerException(); | |
| } | |
| public void clear() | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| public boolean containsKey(Object key) | |
| { | |
| return m.containsKey(key); | |
| } | |
| public boolean containsValue(Object value) | |
| { | |
| return m.containsValue(value); | |
| } | |
| public Set entrySet() | |
| { | |
| if (entries == null) | |
| entries = new UnmodifiableEntrySet(m.entrySet()); | |
| return entries; | |
| } | |
| /** | |
| * The implementation of {@link UnmodifiableMap#entrySet()}. This class | |
| * name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static final class UnmodifiableEntrySet extends UnmodifiableSet | |
| implements Serializable | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = 7854390611657943733L; | |
| /** | |
| * Wrap a given set. | |
| * @param s the set to wrap | |
| */ | |
| UnmodifiableEntrySet(Set s) | |
| { | |
| super(s); | |
| } | |
| // The iterator must return unmodifiable map entries. | |
| public Iterator iterator() | |
| { | |
| return new UnmodifiableIterator(c.iterator()) | |
| { | |
| public Object next() | |
| { | |
| final Map.Entry e = (Map.Entry) super.next(); | |
| return new Map.Entry() | |
| { | |
| public boolean equals(Object o) | |
| { | |
| return e.equals(o); | |
| } | |
| public Object getKey() | |
| { | |
| return e.getKey(); | |
| } | |
| public Object getValue() | |
| { | |
| return e.getValue(); | |
| } | |
| public int hashCode() | |
| { | |
| return e.hashCode(); | |
| } | |
| public Object setValue(Object value) | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| public String toString() | |
| { | |
| return e.toString(); | |
| } | |
| }; | |
| } | |
| }; | |
| } | |
| } // class UnmodifiableEntrySet | |
| 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() | |
| { | |
| if (keys == null) | |
| keys = new UnmodifiableSet(m.keySet()); | |
| return keys; | |
| } | |
| public void putAll(Map m) | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| public Object remove(Object o) | |
| { | |
| throw new UnsupportedOperationException(); | |
| } | |
| public int size() | |
| { | |
| return m.size(); | |
| } | |
| public String toString() | |
| { | |
| return m.toString(); | |
| } | |
| public Collection values() | |
| { | |
| if (values == null) | |
| values = new UnmodifiableCollection(m.values()); | |
| return values; | |
| } | |
| } // class UnmodifiableMap | |
| /** | |
| * Returns an unmodifiable view of the given set. This allows | |
| * "read-only" access, although changes in the backing set show up | |
| * in this view. Attempts to modify the set directly or via iterators | |
| * will fail with {@link UnsupportedOperationException}. | |
| * <p> | |
| * | |
| * The returned Set implements Serializable, but can only be serialized if | |
| * the set it wraps is likewise Serializable. | |
| * | |
| * @param s the set to wrap | |
| * @return a read-only view of the set | |
| * @see Serializable | |
| */ | |
| public static Set unmodifiableSet(Set s) | |
| { | |
| return new UnmodifiableSet(s); | |
| } | |
| /** | |
| * The implementation of {@link #unmodifiableSet(Set)}. This class | |
| * name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class UnmodifiableSet extends UnmodifiableCollection | |
| implements Set | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -9215047833775013803L; | |
| /** | |
| * Wrap a given set. | |
| * @param s the set to wrap | |
| * @throws NullPointerException if s is null | |
| */ | |
| UnmodifiableSet(Set s) | |
| { | |
| super(s); | |
| } | |
| public boolean equals(Object o) | |
| { | |
| return c.equals(o); | |
| } | |
| public int hashCode() | |
| { | |
| return c.hashCode(); | |
| } | |
| } // class UnmodifiableSet | |
| /** | |
| * Returns an unmodifiable view of the given sorted map. This allows | |
| * "read-only" access, although changes in the backing map show up in this | |
| * view. Attempts to modify the map directly, via subviews, via collection | |
| * views, or iterators, will fail with {@link UnsupportedOperationException}. | |
| * <p> | |
| * | |
| * The returned SortedMap implements Serializable, but can only be | |
| * serialized if the map it wraps is likewise Serializable. | |
| * | |
| * @param m the map to wrap | |
| * @return a read-only view of the map | |
| * @see Serializable | |
| */ | |
| public static SortedMap unmodifiableSortedMap(SortedMap m) | |
| { | |
| return new UnmodifiableSortedMap(m); | |
| } | |
| /** | |
| * The implementation of {@link #unmodifiableSortedMap(SortedMap)}. This | |
| * class name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class UnmodifiableSortedMap extends UnmodifiableMap | |
| implements SortedMap | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -8806743815996713206L; | |
| /** | |
| * The wrapped map; stored both here and in the superclass to avoid | |
| * excessive casting. | |
| * @serial the wrapped map | |
| */ | |
| private final SortedMap sm; | |
| /** | |
| * Wrap a given map. | |
| * @param sm the map to wrap | |
| * @throws NullPointerException if sm is null | |
| */ | |
| UnmodifiableSortedMap(SortedMap sm) | |
| { | |
| super(sm); | |
| this.sm = sm; | |
| } | |
| public Comparator comparator() | |
| { | |
| return sm.comparator(); | |
| } | |
| public Object firstKey() | |
| { | |
| return sm.firstKey(); | |
| } | |
| public SortedMap headMap(Object toKey) | |
| { | |
| return new UnmodifiableSortedMap(sm.headMap(toKey)); | |
| } | |
| public Object lastKey() | |
| { | |
| return sm.lastKey(); | |
| } | |
| public SortedMap subMap(Object fromKey, Object toKey) | |
| { | |
| return new UnmodifiableSortedMap(sm.subMap(fromKey, toKey)); | |
| } | |
| public SortedMap tailMap(Object fromKey) | |
| { | |
| return new UnmodifiableSortedMap(sm.tailMap(fromKey)); | |
| } | |
| } // class UnmodifiableSortedMap | |
| /** | |
| * Returns an unmodifiable view of the given sorted set. This allows | |
| * "read-only" access, although changes in the backing set show up | |
| * in this view. Attempts to modify the set directly, via subsets, or via | |
| * iterators, will fail with {@link UnsupportedOperationException}. | |
| * <p> | |
| * | |
| * The returns SortedSet implements Serializable, but can only be | |
| * serialized if the set it wraps is likewise Serializable. | |
| * | |
| * @param s the set to wrap | |
| * @return a read-only view of the set | |
| * @see Serializable | |
| */ | |
| public static SortedSet unmodifiableSortedSet(SortedSet s) | |
| { | |
| return new UnmodifiableSortedSet(s); | |
| } | |
| /** | |
| * The implementation of {@link #synchronizedSortedMap(SortedMap)}. This | |
| * class name is required for compatibility with Sun's JDK serializability. | |
| * | |
| * @author Eric Blake <ebb9@email.byu.edu> | |
| */ | |
| private static class UnmodifiableSortedSet extends UnmodifiableSet | |
| implements SortedSet | |
| { | |
| /** | |
| * Compatible with JDK 1.4. | |
| */ | |
| private static final long serialVersionUID = -4929149591599911165L; | |
| /** | |
| * The wrapped set; stored both here and in the superclass to avoid | |
| * excessive casting. | |
| * @serial the wrapped set | |
| */ | |
| private SortedSet ss; | |
| /** | |
| * Wrap a given set. | |
| * @param ss the set to wrap | |
| * @throws NullPointerException if ss is null | |
| */ | |
| UnmodifiableSortedSet(SortedSet ss) | |
| { | |
| super(ss); | |
| this.ss = ss; | |
| } | |
| public Comparator comparator() | |
| { | |
| return ss.comparator(); | |
| } | |
| public Object first() | |
| { | |
| return ss.first(); | |
| } | |
| public SortedSet headSet(Object toElement) | |
| { | |
| return new UnmodifiableSortedSet(ss.headSet(toElement)); | |
| } | |
| public Object last() | |
| { | |
| return ss.last(); | |
| } | |
| public SortedSet subSet(Object fromElement, Object toElement) | |
| { | |
| return new UnmodifiableSortedSet(ss.subSet(fromElement, toElement)); | |
| } | |
| public SortedSet tailSet(Object fromElement) | |
| { | |
| return new UnmodifiableSortedSet(ss.tailSet(fromElement)); | |
| } | |
| } // class UnmodifiableSortedSet | |
| } // class Collections |