| /* 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. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| 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 |