All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.emul.java.util.Collections Maven / Gradle / Ivy

There is a newer version: 2.7.0.vaadin7
Show newest version
/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package java.util;

import static com.google.gwt.core.client.impl.Coercions.ensureInt;

import static com.google.gwt.core.shared.impl.InternalPreconditions.checkArgument;
import static com.google.gwt.core.shared.impl.InternalPreconditions.checkElementIndex;

import java.io.Serializable;

/**
 * Utility methods that operate on collections. [Sun
 * docs]
 */
public class Collections {

  private static final class LifoQueue extends AbstractQueue implements
      Serializable {

    private final Deque deque;

    LifoQueue(Deque deque) {
      this.deque = deque;
    }

    @Override
    public Iterator iterator() {
      return deque.iterator();
    }

    @Override
    public boolean offer(E e) {
      return deque.offerFirst(e);
    }

    @Override
    public E peek() {
      return deque.peekFirst();
    }

    @Override
    public E poll() {
      return deque.pollFirst();
    }

    @Override
    public int size() {
      return deque.size();
    }
  }

  private static final class EmptyList extends AbstractList implements
      RandomAccess, Serializable {
    @Override
    public boolean contains(Object object) {
      return false;
    }

    @Override
    public Object get(int location) {
      checkElementIndex(location, 0);
      return null;
    }

    @Override
    public Iterator iterator() {
      return emptyIterator();
    }

    @Override
    public ListIterator listIterator() {
      return emptyListIterator();
    }

    @Override
    public int size() {
      return 0;
    }
  }

  private static final class EmptyListIterator implements ListIterator {

    static final EmptyListIterator INSTANCE = new EmptyListIterator();

    @Override
    public void add(Object o) {
      throw new UnsupportedOperationException();
    }

    @Override
    public boolean hasNext() {
      return false;
    }

    @Override
    public boolean hasPrevious() {
      return false;
    }

    @Override
    public Object next() {
      throw new NoSuchElementException();
    }

    @Override
    public int nextIndex() {
      return 0;
    }

    @Override
    public Object previous() {
      throw new NoSuchElementException();
    }

    @Override
    public int previousIndex() {
      return -1;
    }

    @Override
    public void remove() {
      throw new IllegalStateException();
    }

    @Override
    public void set(Object o) {
      throw new IllegalStateException();
    }
  }

  private static final class EmptySet extends AbstractSet implements
      Serializable {
    @Override
    public boolean contains(Object object) {
      return false;
    }

    @Override
    public Iterator iterator() {
      return emptyIterator();
    }

    @Override
    public int size() {
      return 0;
    }
}

  private static final class EmptyMap extends AbstractMap implements
      Serializable {
    @Override
    public boolean containsKey(Object key) {
      return false;
    }

    @Override
    public boolean containsValue(Object value) {
      return false;
    }

    @Override
    public Set entrySet() {
      return EMPTY_SET;
    }

    @Override
    public Object get(Object key) {
      return null;
    }

    @Override
    public Set keySet() {
      return EMPTY_SET;
    }

    @Override
    public int size() {
      return 0;
    }

    @Override
    public Collection values() {
      return EMPTY_LIST;
    }
  }

  private static final class ReverseComparator implements Comparator> {
    static final ReverseComparator INSTANCE = new ReverseComparator();

    @Override
    public int compare(Comparable o1, Comparable o2) {
      return o2.compareTo(o1);
    }
  }

  private static final class SetFromMap extends AbstractSet
      implements Serializable {

    private final Map backingMap;
    private transient Set keySet;

    SetFromMap(Map map) {
      backingMap = map;
    }

    @Override
    public boolean add(E e) {
      return backingMap.put(e, Boolean.TRUE) == null;
    }

    @Override
    public void clear() {
      backingMap.clear();
    }

    @Override
    public boolean contains(Object o) {
      return backingMap.containsKey(o);
    }

    @Override
    public boolean equals(Object o) {
      return o == this || keySet().equals(o);
    }

    @Override
    public int hashCode() {
      return keySet().hashCode();
    }

    @Override
    public Iterator iterator() {
      return keySet().iterator();
    }

    @Override
    public boolean remove(Object o) {
      return backingMap.remove(o) != null;
    }

    @Override
    public int size() {
      return keySet().size();
    }

    @Override
    public String toString() {
      return keySet().toString();
    }

    /**
     * Lazy initialize keySet to avoid NPE after deserialization.
     */
    private Set keySet() {
      if (keySet == null) {
        keySet = backingMap.keySet();
      }
      return keySet;
    }
  }

  private static final class SingletonList extends AbstractList implements Serializable {
    private E element;

    public SingletonList(E element) {
      this.element = element;
    }

    public boolean contains(Object item) {
      return Objects.equals(element, item);
    }

    public E get(int index) {
      checkElementIndex(index, 1);
      return element;
    }

    public int size() {
      return 1;
    }
  }

  /*
   * TODO: make the unmodifiable collections serializable.
   */

  static class UnmodifiableCollection implements Collection {
    protected final Collection coll;

    public UnmodifiableCollection(Collection coll) {
      this.coll = coll;
    }

    public boolean add(T o) {
      throw new UnsupportedOperationException();
    }

    public boolean addAll(Collection c) {
      throw new UnsupportedOperationException();
    }

    public void clear() {
      throw new UnsupportedOperationException();
    }

    public boolean contains(Object o) {
      return coll.contains(o);
    }

    public boolean containsAll(Collection c) {
      return coll.containsAll(c);
    }

    public boolean isEmpty() {
      return coll.isEmpty();
    }

    public Iterator iterator() {
      return new UnmodifiableCollectionIterator(coll.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 coll.size();
    }

    public Object[] toArray() {
      return coll.toArray();
    }

    public  E[] toArray(E[] a) {
      return coll.toArray(a);
    }

    public String toString() {
      return coll.toString();
    }
  }

  static class UnmodifiableList extends UnmodifiableCollection implements
      List {
    private final List list;

    public UnmodifiableList(List list) {
      super(list);
      this.list = list;
    }

    public void add(int index, T element) {
      throw new UnsupportedOperationException();
    }

    public boolean addAll(int index, Collection c) {
      throw new UnsupportedOperationException();
    }

    @Override
    public boolean equals(Object o) {
      return list.equals(o);
    }

    public T get(int index) {
      return list.get(index);
    }

    @Override
    public int hashCode() {
      return list.hashCode();
    }

    public int indexOf(Object o) {
      return list.indexOf(o);
    }

    @Override
    public boolean isEmpty() {
      return list.isEmpty();
    }

    public int lastIndexOf(Object o) {
      return list.lastIndexOf(o);
    }

    public ListIterator listIterator() {
      return listIterator(0);
    }

    public ListIterator listIterator(int from) {
      return new UnmodifiableListIterator(list.listIterator(from));
    }

    public T remove(int index) {
      throw new UnsupportedOperationException();
    }

    public T set(int index, T element) {
      throw new UnsupportedOperationException();
    }

    public List subList(int fromIndex, int toIndex) {
      return new UnmodifiableList(list.subList(fromIndex, toIndex));
    }
  }

  static class UnmodifiableMap implements Map {

    static class UnmodifiableEntrySet extends
        UnmodifiableSet> {

      private static class UnmodifiableEntry implements Map.Entry {
        private Map.Entry entry;

        public UnmodifiableEntry(Map.Entry entry) {
          this.entry = entry;
        }

        @Override
        public boolean equals(Object o) {
          return entry.equals(o);
        }

        public K getKey() {
          return entry.getKey();
        }

        public V getValue() {
          return entry.getValue();
        }

        @Override
        public int hashCode() {
          return entry.hashCode();
        }

        public V setValue(V value) {
          throw new UnsupportedOperationException();
        }

        @Override
        public String toString() {
          return entry.toString();
        }
      }

      @SuppressWarnings("unchecked")
      public UnmodifiableEntrySet(
          Set> s) {
        super((Set>) s);
      }

      @Override
      public boolean contains(Object o) {
        return coll.contains(o);
      }

      @Override
      public boolean containsAll(Collection o) {
        return coll.containsAll(o);
      }

      @Override
      @SuppressWarnings("unchecked")
      public Iterator> iterator() {
        final Iterator> it = (Iterator>) coll.iterator();
        return new Iterator>() {
          public boolean hasNext() {
            return it.hasNext();
          }

          public Map.Entry next() {
            return new UnmodifiableEntry(it.next());
          }

          public void remove() {
            throw new UnsupportedOperationException();
          }
        };
      }

      @Override
      public Object[] toArray() {
        Object[] array = super.toArray();
        wrap(array, array.length);
        return array;
      }

      @Override
      @SuppressWarnings("unchecked")
      public  T[] toArray(T[] a) {
        Object[] result = super.toArray(a);
        wrap(result, coll.size());
        return (T[]) result;
      }

      /**
       * Wrap an array of Map.Entries as UnmodifiableEntries.
       *
       * @param array array to wrap
       * @param size number of entries to wrap
       */
      @SuppressWarnings("unchecked")
      private void wrap(Object[] array, int size) {
        for (int i = 0; i < size; ++i) {
          array[i] = new UnmodifiableEntry((Map.Entry) array[i]);
        }
      }
    }

    private transient UnmodifiableSet> entrySet;
    private transient UnmodifiableSet keySet;
    private final Map map;
    private transient UnmodifiableCollection values;

    public UnmodifiableMap(Map map) {
      this.map = map;
    }

    public void clear() {
      throw new UnsupportedOperationException();
    }

    public boolean containsKey(Object key) {
      return map.containsKey(key);
    }

    public boolean containsValue(Object val) {
      return map.containsValue(val);
    }

    public Set> entrySet() {
      if (entrySet == null) {
        entrySet = new UnmodifiableEntrySet(map.entrySet());
      }
      return entrySet;
    }

    @Override
    public boolean equals(Object o) {
      return map.equals(o);
    }

    public V get(Object key) {
      return map.get(key);
    }

    @Override
    public int hashCode() {
      return map.hashCode();
    }

    public boolean isEmpty() {
      return map.isEmpty();
    }

    public Set keySet() {
      if (keySet == null) {
        keySet = new UnmodifiableSet(map.keySet());
      }
      return keySet;
    }

    public V put(K key, V value) {
      throw new UnsupportedOperationException();
    }

    public void putAll(Map t) {
      throw new UnsupportedOperationException();
    }

    public V remove(Object key) {
      throw new UnsupportedOperationException();
    }

    public int size() {
      return map.size();
    }

    @Override
    public String toString() {
      return map.toString();
    }

    public Collection values() {
      if (values == null) {
        values = new UnmodifiableCollection(map.values());
      }
      return values;
    }
  }

  static class UnmodifiableRandomAccessList extends UnmodifiableList
      implements RandomAccess {
    public UnmodifiableRandomAccessList(List list) {
      super(list);
    }
  }

  static class UnmodifiableSet extends UnmodifiableCollection implements
      Set {
    public UnmodifiableSet(Set set) {
      super(set);
    }

    @Override
    public boolean equals(Object o) {
      return coll.equals(o);
    }

    @Override
    public int hashCode() {
      return coll.hashCode();
    }
  }

  static class UnmodifiableSortedMap extends UnmodifiableMap
      implements SortedMap {

    private SortedMap sortedMap;

    public UnmodifiableSortedMap(SortedMap sortedMap) {
      super(sortedMap);
      this.sortedMap = sortedMap;
    }

    public Comparator comparator() {
      return sortedMap.comparator();
    }

    @Override
    public boolean equals(Object o) {
      return sortedMap.equals(o);
    }

    public K firstKey() {
      return sortedMap.firstKey();
    }

    @Override
    public int hashCode() {
      return sortedMap.hashCode();
    }

    public SortedMap headMap(K toKey) {
      return new UnmodifiableSortedMap(sortedMap.headMap(toKey));
    }

    public K lastKey() {
      return sortedMap.lastKey();
    }

    public SortedMap subMap(K fromKey, K toKey) {
      return new UnmodifiableSortedMap(sortedMap.subMap(fromKey, toKey));
    }

    public SortedMap tailMap(K fromKey) {
      return new UnmodifiableSortedMap(sortedMap.tailMap(fromKey));
    }
  }

  static class UnmodifiableSortedSet extends UnmodifiableSet implements
      SortedSet {
    private SortedSet sortedSet;

    @SuppressWarnings("unchecked")
    public UnmodifiableSortedSet(SortedSet sortedSet) {
      super(sortedSet);
      this.sortedSet = (SortedSet) sortedSet;
    }

    public Comparator comparator() {
      return sortedSet.comparator();
    }

    @Override
    public boolean equals(Object o) {
      return sortedSet.equals(o);
    }

    public E first() {
      return sortedSet.first();
    }

    @Override
    public int hashCode() {
      return sortedSet.hashCode();
    }

    public SortedSet headSet(E toElement) {
      return new UnmodifiableSortedSet(sortedSet.headSet(toElement));
    }

    public E last() {
      return sortedSet.last();
    }

    public SortedSet subSet(E fromElement, E toElement) {
      return new UnmodifiableSortedSet(sortedSet.subSet(fromElement,
          toElement));
    }

    public SortedSet tailSet(E fromElement) {
      return new UnmodifiableSortedSet(sortedSet.tailSet(fromElement));
    }
  }

  private static class UnmodifiableCollectionIterator implements Iterator {
    private final Iterator it;

    private UnmodifiableCollectionIterator(Iterator it) {
      this.it = it;
    }

    public boolean hasNext() {
      return it.hasNext();
    }

    public T next() {
      return it.next();
    }

    public void remove() {
      throw new UnsupportedOperationException();
    }
  }

  private static class UnmodifiableListIterator extends
      UnmodifiableCollectionIterator implements ListIterator {
    private final ListIterator lit;

    private UnmodifiableListIterator(ListIterator lit) {
      super(lit);
      this.lit = lit;
    }

    public void add(T o) {
      throw new UnsupportedOperationException();
    }

    public boolean hasPrevious() {
      return lit.hasPrevious();
    }

    public int nextIndex() {
      return lit.nextIndex();
    }

    public T previous() {
      return lit.previous();
    }

    public int previousIndex() {
      return lit.previousIndex();
    }

    public void set(T o) {
      throw new UnsupportedOperationException();
    }
  }

  @SuppressWarnings("unchecked")
  public static final List EMPTY_LIST = new EmptyList();

  @SuppressWarnings("unchecked")
  public static final Map EMPTY_MAP = new EmptyMap();

  @SuppressWarnings("unchecked")
  public static final Set EMPTY_SET = new EmptySet();

  public static  boolean addAll(Collection c, T... a) {
    boolean result = false;
    for (T e : a) {
      result |= c.add(e);
    }
    return result;
  }

  public static  Queue asLifoQueue(Deque deque) {
    return new LifoQueue(deque);
  }

  /**
   * Perform a binary search on a sorted List, using natural ordering.
   *
   * 

* Note: The GWT implementation differs from the JDK implementation in that it * does not do an iterator-based binary search for Lists that do not implement * RandomAccess. *

* * @param sortedList object array to search * @param key value to search for * @return the index of an element with a matching value, or a negative number * which is the index of the next larger value (or just past the end * of the array if the searched value is larger than all elements in * the array) minus 1 (to ensure error returns are negative) * @throws ClassCastException if key is not comparable to * sortedList's elements. */ public static int binarySearch( final List> sortedList, final T key) { return binarySearch(sortedList, key, null); } /* * These methods are commented out because they cannot currently be * implemented in GWT. The signatures are included in case that changes. */ // public static Collection checkedCollection(Collection c, Class // type) { // // FUTURE: implement // return null; // } // // static List checkedList(List list, Class type) { // // FUTURE: implement // return null; // } // // public static Map checkedMap(Map list, Class keyType, // Class valueType) { // // FUTURE: implement // return null; // } // // public static Set checkedSet(Set list, Class type) { // // FUTURE: implement // return null; // } // // public static SortedMap checkedSortedMap(SortedMap m, // Class keyType, Class valueType) { // // FUTURE: implement // return null; // } // // public static SortedSet checkedSortedSet(SortedSet list, Class // type) { // // FUTURE: implement // return null; // } /** * Perform a binary search on a sorted List, using a user-specified comparison * function. * *

* Note: The GWT implementation differs from the JDK implementation in that it * does not do an iterator-based binary search for Lists that do not implement * RandomAccess. *

* * @param sortedList List to search * @param key value to search for * @param comparator comparision function, null indicates * natural ordering should be used. * @return the index of an element with a matching value, or a negative number * which is the index of the next larger value (or just past the end * of the array if the searched value is larger than all elements in * the array) minus 1 (to ensure error returns are negative) * @throws ClassCastException if key and * sortedList's elements cannot be compared by * comparator. */ public static int binarySearch(final List sortedList, final T key, Comparator comparator) { /* * TODO: This doesn't implement the "iterator-based binary search" described * in the JDK docs for non-RandomAccess Lists. Until GWT provides a * LinkedList, this shouldn't be an issue. */ if (comparator == null) { comparator = Comparators.natural(); } int low = 0; int high = sortedList.size() - 1; while (low <= high) { final int mid = low + ((high - low) >> 1); final T midVal = sortedList.get(mid); final int compareResult = comparator.compare(midVal, key); if (compareResult < 0) { low = mid + 1; } else if (compareResult > 0) { high = mid - 1; } else { // key found return mid; } } // key not found. return -low - 1; } public static void copy(List dest, List src) { // TODO(jat): optimize dest.addAll(src); } public static boolean disjoint(Collection c1, Collection c2) { Collection iterating = c1; Collection testing = c2; // See if one of these objects possibly implements a fast contains. if ((c1 instanceof Set) && !(c2 instanceof Set)) { iterating = c2; testing = c1; } for (Object o : iterating) { if (testing.contains(o)) { return false; } } return true; } @SuppressWarnings(value = {"unchecked", "cast"}) public static Iterator emptyIterator() { return (Iterator) EmptyListIterator.INSTANCE; } @SuppressWarnings(value = {"unchecked", "cast"}) public static List emptyList() { return (List) EMPTY_LIST; } @SuppressWarnings(value = {"unchecked", "cast"}) public static ListIterator emptyListIterator() { return (ListIterator) EmptyListIterator.INSTANCE; } @SuppressWarnings(value = {"unchecked", "cast"}) public static Map emptyMap() { return (Map) EMPTY_MAP; } @SuppressWarnings(value = {"unchecked", "cast"}) public static Set emptySet() { return (Set) EMPTY_SET; } public static Enumeration enumeration(Collection c) { final Iterator it = c.iterator(); return new Enumeration() { public boolean hasMoreElements() { return it.hasNext(); } public T nextElement() { return it.next(); } }; } public static void fill(List list, T obj) { for (ListIterator it = list.listIterator(); it.hasNext();) { it.next(); it.set(obj); } } public static int frequency(Collection c, Object o) { int count = 0; for (Object e : c) { if (Objects.equals(o, e)) { ++count; } } return count; } public static ArrayList list(Enumeration e) { ArrayList arrayList = new ArrayList(); while (e.hasMoreElements()) { arrayList.add(e.nextElement()); } return arrayList; } public static > T max( Collection coll) { return max(coll, null); } public static T max(Collection coll, Comparator comp) { if (comp == null) { comp = Comparators.natural(); } Iterator it = coll.iterator(); // Will throw NoSuchElementException if coll is empty. T max = it.next(); while (it.hasNext()) { T t = it.next(); if (comp.compare(t, max) > 0) { max = t; } } return max; } public static > T min( Collection coll) { return min(coll, null); } public static T min(Collection coll, Comparator comp) { return max(coll, reverseOrder(comp)); } public static Set newSetFromMap(Map map) { checkArgument(map.isEmpty(), "map is not empty"); return new SetFromMap(map); } public static List nCopies(int n, T o) { ArrayList list = new ArrayList(); for (int i = 0; i < n; ++i) { list.add(o); } return unmodifiableList(list); } public static boolean replaceAll(List list, T oldVal, T newVal) { boolean modified = false; for (ListIterator it = list.listIterator(); it.hasNext();) { T t = it.next(); if (Objects.equals(t, oldVal)) { it.set(newVal); modified = true; } } return modified; } public static void reverse(List l) { if (l instanceof RandomAccess) { for (int iFront = 0, iBack = l.size() - 1; iFront < iBack; ++iFront, --iBack) { Collections.swap(l, iFront, iBack); } } else { ListIterator head = l.listIterator(); ListIterator tail = l.listIterator(l.size()); while (head.nextIndex() < tail.previousIndex()) { T headElem = head.next(); T tailElem = tail.previous(); head.set(tailElem); tail.set(headElem); } } } @SuppressWarnings("unchecked") public static Comparator reverseOrder() { return (Comparator) ReverseComparator.INSTANCE; } public static Comparator reverseOrder(final Comparator cmp) { if (cmp == null) { return reverseOrder(); } return new Comparator() { public int compare(T t1, T t2) { return cmp.compare(t2, t1); } }; } public static Set singleton(T o) { HashSet set = new HashSet(1); set.add(o); return unmodifiableSet(set); } // TODO(tobyr) Is it worth creating custom singleton sets, lists, and maps? // More efficient at runtime, but more code bloat to download public static List singletonList(T o) { return new SingletonList(o); } public static Map singletonMap(K key, V value) { Map map = new HashMap(1); map.put(key, value); return unmodifiableMap(map); } public static void sort(List target) { sort(target, null); } @SuppressWarnings("unchecked") public static void sort(List target, Comparator c) { Object[] x = target.toArray(); Arrays.sort(x, (Comparator) c); replaceContents(target, x); } public static void swap(List list, int i, int j) { swapImpl(list, i, j); } public static Collection unmodifiableCollection( final Collection coll) { return new UnmodifiableCollection(coll); } public static List unmodifiableList(List list) { return (list instanceof RandomAccess) ? new UnmodifiableRandomAccessList(list) : new UnmodifiableList( list); } public static Map unmodifiableMap( final Map map) { return new UnmodifiableMap(map); } public static Set unmodifiableSet(Set set) { return new UnmodifiableSet(set); } public static SortedMap unmodifiableSortedMap( SortedMap map) { return new UnmodifiableSortedMap(map); } public static SortedSet unmodifiableSortedSet( SortedSet set) { return new UnmodifiableSortedSet(set); } /** * Computes hash code without preserving elements order (e.g. HashSet). */ static int hashCode(Iterable collection) { int hashCode = 0; for (T e : collection) { hashCode = hashCode + Objects.hashCode(e); hashCode = ensureInt(hashCode); // make sure we don't overflow } return hashCode; } /** * Computes hash code preserving collection order (e.g. ArrayList). */ static int hashCode(List list) { int hashCode = 1; for (T e : list) { hashCode = 31 * hashCode + Objects.hashCode(e); hashCode = ensureInt(hashCode); // make sure we don't overflow } return hashCode; } /** * Replace contents of a list from an array. * * @param element type * @param target list to replace contents from an array * @param x an Object array which can contain only T instances */ @SuppressWarnings("unchecked") private static void replaceContents(List target, Object[] x) { int size = target.size(); assert (x.length == size); for (int i = 0; i < size; i++) { target.set(i, (T) x[i]); } } private static void swapImpl(List list, int i, int j) { T t = list.get(i); list.set(i, list.get(j)); list.set(j, t); } }