Collections.java   [plain text]


/* Collections.java -- Utility class with methods to operate on collections
   Copyright (C) 1998, 1999, 2000, 2001, 2002 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 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();

  /**
   * 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.
     */
    // This is really cheating! I think it's perfectly valid, though.
    public Iterator iterator()
    {
      return EMPTY_LIST.iterator();
    }

    // The remaining methods are optional, but provide a performance
    // advantage by not allocating unnecessary iterators in AbstractSet.
    /**
     * The empty set never contains anything.
     */
    public boolean contains(Object o)
    {
      return false;
    }

    /**
     * This is true only if the given collection is also empty.
     */
    public boolean containsAll(Collection c)
    {
      return c.isEmpty();
    }

    /**
     * Equal only if the other set is empty.
     */
    public boolean equals(Object o)
    {
      return o instanceof Set && ((Set) o).isEmpty();
    }

    /**
     * The hashcode is always 0.
     */
    public int hashCode()
    {
      return 0;
    }

    /**
     * Always succeeds with false result.
     */
    public boolean remove(Object o)
    {
      return false;
    }

    /**
     * Always succeeds with false result.
     */
    public boolean removeAll(Collection c)
    {
      return false;
    }

    /**
     * Always succeeds with false result.
     */
    public boolean retainAll(Collection c)
    {
      return false;
    }

    /**
     * The array is always empty.
     */
    public Object[] toArray()
    {
      return new Object[0];
    }

    /**
     * We don't even need to use reflection!
     */
    public Object[] toArray(Object[] a)
    {
      if (a.length > 0)
        a[0] = null;
      return a;
    }

    /**
     * The string never changes.
     */
    public String toString()
    {
      return "[]";
    }
  } // 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();
    }

    // The remaining methods are optional, but provide a performance
    // advantage by not allocating unnecessary iterators in AbstractList.
    /**
     * Never contains anything.
     */
    public boolean contains(Object o)
    {
      return false;
    }

    /**
     * This is true only if the given collection is also empty.
     */
    public boolean containsAll(Collection c)
    {
      return c.isEmpty();
    }

    /**
     * Equal only if the other set is empty.
     */
    public boolean equals(Object o)
    {
      return o instanceof List && ((List) o).isEmpty();
    }

    /**
     * The hashcode is always 1.
     */
    public int hashCode()
    {
      return 1;
    }

    /**
     * Returns -1.
     */
    public int indexOf(Object o)
    {
      return -1;
    }

    /**
     * Returns -1.
     */
    public int lastIndexOf(Object o)
    {
      return -1;
    }

    /**
     * Always succeeds with false result.
     */
    public boolean remove(Object o)
    {
      return false;
    }

    /**
     * Always succeeds with false result.
     */
    public boolean removeAll(Collection c)
    {
      return false;
    }

    /**
     * Always succeeds with false result.
     */
    public boolean retainAll(Collection c)
    {
      return false;
    }

    /**
     * The array is always empty.
     */
    public Object[] toArray()
    {
      return new Object[0];
    }

    /**
     * We don't even need to use reflection!
     */
    public Object[] toArray(Object[] a)
    {
      if (a.length > 0)
        a[0] = null;
      return a;
    }

    /**
     * The string never changes.
     */
    public String toString()
    {
      return "[]";
    }
  } // 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;
    }

    // The remaining methods are optional, but provide a performance
    // advantage by not allocating unnecessary iterators in AbstractMap.
    /**
     * No entries!
     */
    public boolean containsKey(Object key)
    {
      return false;
    }

    /**
     * No entries!
     */
    public boolean containsValue(Object value)
    {
      return false;
    }

    /**
     * Equal to all empty maps.
     */
    public boolean equals(Object o)
    {
      return o instanceof Map && ((Map) o).isEmpty();
    }

    /**
     * No mappings, so this returns null.
     */
    public Object get(Object o)
    {
      return null;
    }

    /**
     * The hashcode is always 0.
     */
    public int hashCode()
    {
      return 0;
    }

    /**
     * No entries.
     */
    public Set keySet()
    {
      return EMPTY_SET;
    }

    /**
     * Remove always succeeds, with null result.
     */
    public Object remove(Object o)
    {
      return null;
    }

    /**
     * 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;
    }

    /**
     * The string never changes.
     */
    public String toString()
    {
      return "[]";
    }
  } // 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() &gt; 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() &gt; 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 ArrayList 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 ArrayList list(Enumeration e)
  {
    ArrayList 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 &lt; 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 &lt; 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 &lt;, ==, or &gt; 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 AbstractMap.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 &lt; 0 or &gt;=
   *         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