Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2007 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.collect;
     18 
     19 import com.google.common.annotations.GwtCompatible;
     20 import static com.google.common.base.Preconditions.checkNotNull;
     21 
     22 import java.io.Serializable;
     23 import java.util.ArrayList;
     24 import java.util.Arrays;
     25 import java.util.Collection;
     26 import java.util.Collections;
     27 import java.util.HashSet;
     28 import java.util.Iterator;
     29 import java.util.List;
     30 import java.util.Set;
     31 
     32 import javax.annotation.Nullable;
     33 
     34 /**
     35  * A high-performance, immutable {@code Set} with reliable, user-specified
     36  * iteration order. Does not permit null elements.
     37  *
     38  * <p>Unlike {@link Collections#unmodifiableSet}, which is a <i>view</i> of a
     39  * separate collection that can still change, an instance of this class contains
     40  * its own private data and will <i>never</i> change. This class is convenient
     41  * for {@code public static final} sets ("constant sets") and also lets you
     42  * easily make a "defensive copy" of a set provided to your class by a caller.
     43  *
     44  * <p><b>Warning:</b> Like most sets, an {@code ImmutableSet} will not function
     45  * correctly if an element is modified after being placed in the set. For this
     46  * reason, and to avoid general confusion, it is strongly recommended to place
     47  * only immutable objects into this collection.
     48  *
     49  * <p>This class has been observed to perform significantly better than {@link
     50  * HashSet} for objects with very fast {@link Object#hashCode} implementations
     51  * (as a well-behaved immutable object should). While this class's factory
     52  * methods create hash-based instances, the {@link ImmutableSortedSet} subclass
     53  * performs binary searches instead.
     54  *
     55  * <p><b>Note</b>: Although this class is not final, it cannot be subclassed
     56  * outside its package as it has no public or protected constructors. Thus,
     57  * instances of this type are guaranteed to be immutable.
     58  *
     59  * @see ImmutableList
     60  * @see ImmutableMap
     61  * @author Kevin Bourrillion
     62  * @author Nick Kralevich
     63  * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
     64  */
     65 @GwtCompatible(serializable = true)
     66 @SuppressWarnings("serial") // we're overriding default serialization
     67 public abstract class ImmutableSet<E> extends ImmutableCollection<E>
     68     implements Set<E> {
     69   /**
     70    * Returns the empty immutable set. This set behaves and performs comparably
     71    * to {@link Collections#emptySet}, and is preferable mainly for consistency
     72    * and maintainability of your code.
     73    */
     74   // Casting to any type is safe because the set will never hold any elements.
     75   @SuppressWarnings({"unchecked"})
     76   public static <E> ImmutableSet<E> of() {
     77     // BEGIN android-changed
     78     return (ImmutableSet) EmptyImmutableSet.INSTANCE;
     79     // END android-changed
     80   }
     81 
     82   /**
     83    * Returns an immutable set containing a single element. This set behaves and
     84    * performs comparably to {@link Collections#singleton}, but will not accept
     85    * a null element. It is preferable mainly for consistency and
     86    * maintainability of your code.
     87    */
     88   public static <E> ImmutableSet<E> of(E element) {
     89     return new SingletonImmutableSet<E>(element);
     90   }
     91 
     92   /**
     93    * Returns an immutable set containing the given elements, in order. Repeated
     94    * occurrences of an element (according to {@link Object#equals}) after the
     95    * first are ignored.
     96    *
     97    * @throws NullPointerException if any element is null
     98    */
     99   @SuppressWarnings("unchecked")
    100   public static <E> ImmutableSet<E> of(E e1, E e2) {
    101     return create(e1, e2);
    102   }
    103 
    104   /**
    105    * Returns an immutable set containing the given elements, in order. Repeated
    106    * occurrences of an element (according to {@link Object#equals}) after the
    107    * first are ignored.
    108    *
    109    * @throws NullPointerException if any element is null
    110    */
    111   @SuppressWarnings("unchecked")
    112   public static <E> ImmutableSet<E> of(E e1, E e2, E e3) {
    113     return create(e1, e2, e3);
    114   }
    115 
    116   /**
    117    * Returns an immutable set containing the given elements, in order. Repeated
    118    * occurrences of an element (according to {@link Object#equals}) after the
    119    * first are ignored.
    120    *
    121    * @throws NullPointerException if any element is null
    122    */
    123   @SuppressWarnings("unchecked")
    124   public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4) {
    125     return create(e1, e2, e3, e4);
    126   }
    127 
    128   /**
    129    * Returns an immutable set containing the given elements, in order. Repeated
    130    * occurrences of an element (according to {@link Object#equals}) after the
    131    * first are ignored.
    132    *
    133    * @throws NullPointerException if any element is null
    134    */
    135   @SuppressWarnings("unchecked")
    136   public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5) {
    137     return create(e1, e2, e3, e4, e5);
    138   }
    139 
    140   /**
    141    * Returns an immutable set containing the given elements, in order. Repeated
    142    * occurrences of an element (according to {@link Object#equals}) after the
    143    * first are ignored (but too many of these may result in the set being
    144    * sized inappropriately).
    145    *
    146    * @throws NullPointerException if any of {@code elements} is null
    147    */
    148   public static <E> ImmutableSet<E> of(E... elements) {
    149     checkNotNull(elements); // for GWT
    150     switch (elements.length) {
    151       case 0:
    152         return of();
    153       case 1:
    154         return of(elements[0]);
    155       default:
    156         return create(elements);
    157     }
    158   }
    159 
    160   /**
    161    * Returns an immutable set containing the given elements, in order. Repeated
    162    * occurrences of an element (according to {@link Object#equals}) after the
    163    * first are ignored (but too many of these may result in the set being
    164    * sized inappropriately). This method iterates over {@code elements} at most
    165    * once.
    166    *
    167    * <p>Note that if {@code s} is a {@code Set<String>}, then {@code
    168    * ImmutableSet.copyOf(s)} returns an {@code ImmutableSet<String>} containing
    169    * each of the strings in {@code s}, while {@code ImmutableSet.of(s)} returns
    170    * a {@code ImmutableSet<Set<String>>} containing one element (the given set
    171    * itself).
    172    *
    173    * <p><b>Note:</b> Despite what the method name suggests, if {@code elements}
    174    * is an {@code ImmutableSet} (but not an {@code ImmutableSortedSet}), no copy
    175    * will actually be performed, and the given set itself will be returned.
    176    *
    177    * @throws NullPointerException if any of {@code elements} is null
    178    */
    179   public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
    180     if (elements instanceof ImmutableSet
    181         && !(elements instanceof ImmutableSortedSet)) {
    182       @SuppressWarnings("unchecked") // all supported methods are covariant
    183       ImmutableSet<E> set = (ImmutableSet<E>) elements;
    184       return set;
    185     }
    186     return copyOfInternal(Collections2.toCollection(elements));
    187   }
    188 
    189   /**
    190    * Returns an immutable set containing the given elements, in order. Repeated
    191    * occurrences of an element (according to {@link Object#equals}) after the
    192    * first are ignored.
    193    *
    194    * @throws NullPointerException if any of {@code elements} is null
    195    */
    196   public static <E> ImmutableSet<E> copyOf(Iterator<? extends E> elements) {
    197     Collection<E> list = Lists.newArrayList(elements);
    198     return copyOfInternal(list);
    199   }
    200 
    201   private static <E> ImmutableSet<E> copyOfInternal(
    202       Collection<? extends E> collection) {
    203     // TODO: Support concurrent collections that change while this method is
    204     // running.
    205     switch (collection.size()) {
    206       case 0:
    207         return of();
    208       case 1:
    209         // TODO: Remove "ImmutableSet.<E>" when eclipse bug is fixed.
    210         return ImmutableSet.<E>of(collection.iterator().next());
    211       default:
    212         return create(collection, collection.size());
    213     }
    214   }
    215 
    216   ImmutableSet() {}
    217 
    218   /** Returns {@code true} if the {@code hashCode()} method runs quickly. */
    219   boolean isHashCodeFast() {
    220     return false;
    221   }
    222 
    223   @Override public boolean equals(@Nullable Object object) {
    224     if (object == this) {
    225       return true;
    226     }
    227     if (object instanceof ImmutableSet
    228         && isHashCodeFast()
    229         && ((ImmutableSet<?>) object).isHashCodeFast()
    230         && hashCode() != object.hashCode()) {
    231       return false;
    232     }
    233     return Collections2.setEquals(this, object);
    234   }
    235 
    236   @Override public int hashCode() {
    237     int hashCode = 0;
    238     for (Object o : this) {
    239       hashCode += o.hashCode();
    240     }
    241     return hashCode;
    242   }
    243 
    244   // This declaration is needed to make Set.iterator() and
    245   // ImmutableCollection.iterator() consistent.
    246   @Override public abstract UnmodifiableIterator<E> iterator();
    247 
    248   private static <E> ImmutableSet<E> create(E... elements) {
    249     return create(Arrays.asList(elements), elements.length);
    250   }
    251 
    252   private static <E> ImmutableSet<E> create(
    253       Iterable<? extends E> iterable, int count) {
    254     // count is always the (nonzero) number of elements in the iterable
    255     int tableSize = Hashing.chooseTableSize(count);
    256     Object[] table = new Object[tableSize];
    257     int mask = tableSize - 1;
    258 
    259     List<E> elements = new ArrayList<E>(count);
    260     int hashCode = 0;
    261 
    262     for (E element : iterable) {
    263       checkNotNull(element); // for GWT
    264       int hash = element.hashCode();
    265       for (int i = Hashing.smear(hash); true; i++) {
    266         int index = i & mask;
    267         Object value = table[index];
    268         if (value == null) {
    269           // Came to an empty bucket. Put the element here.
    270           table[index] = element;
    271           elements.add(element);
    272           hashCode += hash;
    273           break;
    274         } else if (value.equals(element)) {
    275           break; // Found a duplicate. Nothing to do.
    276         }
    277       }
    278     }
    279 
    280     if (elements.size() == 1) {
    281       // The iterable contained only duplicates of the same element.
    282       return new SingletonImmutableSet<E>(elements.get(0), hashCode);
    283     } else if (tableSize > Hashing.chooseTableSize(elements.size())) {
    284       // Resize the table when the iterable includes too many duplicates.
    285       return create(elements, elements.size());
    286     } else {
    287       return new RegularImmutableSet<E>(
    288           elements.toArray(), hashCode, table, mask);
    289     }
    290   }
    291 
    292   abstract static class ArrayImmutableSet<E> extends ImmutableSet<E> {
    293     // the elements (two or more) in the desired order.
    294     final transient Object[] elements;
    295 
    296     ArrayImmutableSet(Object[] elements) {
    297       this.elements = elements;
    298     }
    299 
    300     public int size() {
    301       return elements.length;
    302     }
    303 
    304     @Override public boolean isEmpty() {
    305       return false;
    306     }
    307 
    308     /*
    309      * The cast is safe because the only way to create an instance is via the
    310      * create() method above, which only permits elements of type E.
    311      */
    312     @SuppressWarnings("unchecked")
    313     @Override public UnmodifiableIterator<E> iterator() {
    314       return (UnmodifiableIterator<E>) Iterators.forArray(elements);
    315     }
    316 
    317     @Override public Object[] toArray() {
    318       Object[] array = new Object[size()];
    319       Platform.unsafeArrayCopy(elements, 0, array, 0, size());
    320       return array;
    321     }
    322 
    323     @Override public <T> T[] toArray(T[] array) {
    324       int size = size();
    325       if (array.length < size) {
    326         array = ObjectArrays.newArray(array, size);
    327       } else if (array.length > size) {
    328         array[size] = null;
    329       }
    330       Platform.unsafeArrayCopy(elements, 0, array, 0, size);
    331       return array;
    332     }
    333 
    334     @Override public boolean containsAll(Collection<?> targets) {
    335       if (targets == this) {
    336         return true;
    337       }
    338       if (!(targets instanceof ArrayImmutableSet)) {
    339         return super.containsAll(targets);
    340       }
    341       if (targets.size() > size()) {
    342         return false;
    343       }
    344       for (Object target : ((ArrayImmutableSet<?>) targets).elements) {
    345         if (!contains(target)) {
    346           return false;
    347         }
    348       }
    349       return true;
    350     }
    351 
    352     @Override ImmutableList<E> createAsList() {
    353       return new ImmutableAsList<E>(elements, this);
    354     }
    355   }
    356 
    357   /** such as ImmutableMap.keySet() */
    358   abstract static class TransformedImmutableSet<D, E> extends ImmutableSet<E> {
    359     final D[] source;
    360     final int hashCode;
    361 
    362     TransformedImmutableSet(D[] source, int hashCode) {
    363       this.source = source;
    364       this.hashCode = hashCode;
    365     }
    366 
    367     abstract E transform(D element);
    368 
    369     public int size() {
    370       return source.length;
    371     }
    372 
    373     @Override public boolean isEmpty() {
    374       return false;
    375     }
    376 
    377     @Override public UnmodifiableIterator<E> iterator() {
    378       return new AbstractIterator<E>() {
    379         int index = 0;
    380         @Override protected E computeNext() {
    381           return index < source.length
    382               ? transform(source[index++])
    383               : endOfData();
    384         }
    385       };
    386     }
    387 
    388     @Override public Object[] toArray() {
    389       return toArray(new Object[size()]);
    390     }
    391 
    392     @Override public <T> T[] toArray(T[] array) {
    393       int size = size();
    394       if (array.length < size) {
    395         array = ObjectArrays.newArray(array, size);
    396       } else if (array.length > size) {
    397         array[size] = null;
    398       }
    399 
    400       // Writes will produce ArrayStoreException when the toArray() doc requires.
    401       Object[] objectArray = array;
    402       for (int i = 0; i < source.length; i++) {
    403         objectArray[i] = transform(source[i]);
    404       }
    405       return array;
    406     }
    407 
    408     @Override public final int hashCode() {
    409       return hashCode;
    410     }
    411 
    412     @Override boolean isHashCodeFast() {
    413       return true;
    414     }
    415   }
    416 
    417   /*
    418    * This class is used to serialize all ImmutableSet instances, except for
    419    * ImmutableEnumSet/ImmutableSortedSet, regardless of implementation type. It
    420    * captures their "logical contents" and they are reconstructed using public
    421    * static factories. This is necessary to ensure that the existence of a
    422    * particular implementation type is an implementation detail.
    423    */
    424   private static class SerializedForm implements Serializable {
    425     final Object[] elements;
    426     SerializedForm(Object[] elements) {
    427       this.elements = elements;
    428     }
    429     Object readResolve() {
    430       return of(elements);
    431     }
    432     private static final long serialVersionUID = 0;
    433   }
    434 
    435   @Override Object writeReplace() {
    436     return new SerializedForm(toArray());
    437   }
    438 
    439   /**
    440    * Returns a new builder. The generated builder is equivalent to the builder
    441    * created by the {@link Builder} constructor.
    442    */
    443   public static <E> Builder<E> builder() {
    444     return new Builder<E>();
    445   }
    446 
    447   /**
    448    * A builder for creating immutable set instances, especially
    449    * {@code public static final} sets ("constant sets").
    450    *
    451    * <p>Example:
    452    * <pre>{@code
    453    *   public static final ImmutableSet<Color> GOOGLE_COLORS
    454    *       = new ImmutableSet.Builder<Color>()
    455    *           .addAll(WEBSAFE_COLORS)
    456    *           .add(new Color(0, 191, 255))
    457    *           .build();}</pre>
    458    *
    459    * <p>Builder instances can be reused - it is safe to call {@link #build}
    460    * multiple times to build multiple sets in series. Each set
    461    * is a superset of the set created before it.
    462    */
    463   public static class Builder<E> extends ImmutableCollection.Builder<E> {
    464     // accessed directly by ImmutableSortedSet
    465     final ArrayList<E> contents = Lists.newArrayList();
    466 
    467     /**
    468      * Creates a new builder. The returned builder is equivalent to the builder
    469      * generated by {@link ImmutableSet#builder}.
    470      */
    471     public Builder() {}
    472 
    473     /**
    474      * Adds {@code element} to the {@code ImmutableSet}.  If the {@code
    475      * ImmutableSet} already contains {@code element}, then {@code add} has no
    476      * effect (only the previously added element is retained).
    477      *
    478      * @param element the element to add
    479      * @return this {@code Builder} object
    480      * @throws NullPointerException if {@code element} is null
    481      */
    482     @Override public Builder<E> add(E element) {
    483       contents.add(checkNotNull(element));
    484       return this;
    485     }
    486 
    487     /**
    488      * Adds each element of {@code elements} to the {@code ImmutableSet},
    489      * ignoring duplicate elements (only the first duplicate element is added).
    490      *
    491      * @param elements the elements to add
    492      * @return this {@code Builder} object
    493      * @throws NullPointerException if {@code elements} is null or contains a
    494      *     null element
    495      */
    496     @Override public Builder<E> add(E... elements) {
    497       checkNotNull(elements); // for GWT
    498       contents.ensureCapacity(contents.size() + elements.length);
    499       super.add(elements);
    500       return this;
    501     }
    502 
    503     /**
    504      * Adds each element of {@code elements} to the {@code ImmutableSet},
    505      * ignoring duplicate elements (only the first duplicate element is added).
    506      *
    507      * @param elements the {@code Iterable} to add to the {@code ImmutableSet}
    508      * @return this {@code Builder} object
    509      * @throws NullPointerException if {@code elements} is null or contains a
    510      *     null element
    511      */
    512     @Override public Builder<E> addAll(Iterable<? extends E> elements) {
    513       if (elements instanceof Collection) {
    514         Collection<?> collection = (Collection<?>) elements;
    515         contents.ensureCapacity(contents.size() + collection.size());
    516       }
    517       super.addAll(elements);
    518       return this;
    519     }
    520 
    521     /**
    522      * Adds each element of {@code elements} to the {@code ImmutableSet},
    523      * ignoring duplicate elements (only the first duplicate element is added).
    524      *
    525      * @param elements the elements to add to the {@code ImmutableSet}
    526      * @return this {@code Builder} object
    527      * @throws NullPointerException if {@code elements} is null or contains a
    528      *     null element
    529      */
    530     @Override public Builder<E> addAll(Iterator<? extends E> elements) {
    531       super.addAll(elements);
    532       return this;
    533     }
    534 
    535     /**
    536      * Returns a newly-created {@code ImmutableSet} based on the contents of
    537      * the {@code Builder}.
    538      */
    539     @Override public ImmutableSet<E> build() {
    540       return copyOf(contents);
    541     }
    542   }
    543 }
    544