• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
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 static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.collect.CollectPreconditions.checkNonnegative;
22 import static com.google.common.collect.ObjectArrays.checkElementNotNull;
23 import static java.util.Objects.requireNonNull;
24 
25 import com.google.common.annotations.GwtCompatible;
26 import com.google.common.annotations.J2ktIncompatible;
27 import com.google.common.annotations.VisibleForTesting;
28 import com.google.common.primitives.Ints;
29 import com.google.errorprone.annotations.CanIgnoreReturnValue;
30 import com.google.errorprone.annotations.concurrent.LazyInit;
31 import com.google.j2objc.annotations.RetainedWith;
32 import java.io.InvalidObjectException;
33 import java.io.ObjectInputStream;
34 import java.io.Serializable;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.Iterator;
39 import java.util.Set;
40 import java.util.SortedSet;
41 import java.util.stream.Collector;
42 import javax.annotation.CheckForNull;
43 import org.checkerframework.checker.nullness.qual.Nullable;
44 
45 /**
46  * A {@link Set} whose contents will never change, with many other important properties detailed at
47  * {@link ImmutableCollection}.
48  *
49  * @since 2.0
50  */
51 @GwtCompatible(serializable = true, emulated = true)
52 @SuppressWarnings("serial") // we're overriding default serialization
53 @ElementTypesAreNonnullByDefault
54 public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements Set<E> {
55 
56   /**
57    * Returns a {@code Collector} that accumulates the input elements into a new {@code
58    * ImmutableSet}. Elements appear in the resulting set in the encounter order of the stream; if
59    * the stream contains duplicates (according to {@link Object#equals(Object)}), only the first
60    * duplicate in encounter order will appear in the result.
61    */
62   @SuppressWarnings({"AndroidJdkLibsChecker", "Java7ApiChecker"})
63   @IgnoreJRERequirement // Users will use this only if they're already using streams.
toImmutableSet()64   static <E> Collector<E, ?, ImmutableSet<E>> toImmutableSet() {
65     return CollectCollectors.toImmutableSet();
66   }
67 
68   /**
69    * Returns the empty immutable set. Preferred over {@link Collections#emptySet} for code
70    * consistency, and because the return type conveys the immutability guarantee.
71    *
72    * <p><b>Performance note:</b> the instance returned is a singleton.
73    */
74   @SuppressWarnings({"unchecked"}) // fully variant implementation (never actually produces any Es)
of()75   public static <E> ImmutableSet<E> of() {
76     return (ImmutableSet<E>) RegularImmutableSet.EMPTY;
77   }
78 
79   /**
80    * Returns an immutable set containing {@code element}. Preferred over {@link
81    * Collections#singleton} for code consistency, {@code null} rejection, and because the return
82    * type conveys the immutability guarantee.
83    */
of(E element)84   public static <E> ImmutableSet<E> of(E element) {
85     return new SingletonImmutableSet<E>(element);
86   }
87 
88   /**
89    * Returns an immutable set containing the given elements, minus duplicates, in the order each was
90    * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except
91    * the first are ignored.
92    */
of(E e1, E e2)93   public static <E> ImmutableSet<E> of(E e1, E e2) {
94     return construct(2, e1, e2);
95   }
96 
97   /**
98    * Returns an immutable set containing the given elements, minus duplicates, in the order each was
99    * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except
100    * the first are ignored.
101    */
of(E e1, E e2, E e3)102   public static <E> ImmutableSet<E> of(E e1, E e2, E e3) {
103     return construct(3, e1, e2, e3);
104   }
105 
106   /**
107    * Returns an immutable set containing the given elements, minus duplicates, in the order each was
108    * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except
109    * the first are ignored.
110    */
of(E e1, E e2, E e3, E e4)111   public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4) {
112     return construct(4, e1, e2, e3, e4);
113   }
114 
115   /**
116    * Returns an immutable set containing the given elements, minus duplicates, in the order each was
117    * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except
118    * the first are ignored.
119    */
of(E e1, E e2, E e3, E e4, E e5)120   public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5) {
121     return construct(5, e1, e2, e3, e4, e5);
122   }
123 
124   /**
125    * Returns an immutable set containing the given elements, minus duplicates, in the order each was
126    * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except
127    * the first are ignored.
128    *
129    * <p>The array {@code others} must not be longer than {@code Integer.MAX_VALUE - 6}.
130    *
131    * @since 3.0 (source-compatible since 2.0)
132    */
133   @SafeVarargs // For Eclipse. For internal javac we have disabled this pointless type of warning.
of(E e1, E e2, E e3, E e4, E e5, E e6, E... others)134   public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) {
135     checkArgument(
136         others.length <= Integer.MAX_VALUE - 6, "the total number of elements must fit in an int");
137     final int paramCount = 6;
138     Object[] elements = new Object[paramCount + others.length];
139     elements[0] = e1;
140     elements[1] = e2;
141     elements[2] = e3;
142     elements[3] = e4;
143     elements[4] = e5;
144     elements[5] = e6;
145     System.arraycopy(others, 0, elements, paramCount, others.length);
146     return construct(elements.length, elements);
147   }
148 
149   /**
150    * Constructs an {@code ImmutableSet} from the first {@code n} elements of the specified array. If
151    * {@code k} is the size of the returned {@code ImmutableSet}, then the unique elements of {@code
152    * elements} will be in the first {@code k} positions, and {@code elements[i] == null} for {@code
153    * k <= i < n}.
154    *
155    * <p>After this method returns, {@code elements} will contain no duplicates, but {@code elements}
156    * may be the real array backing the returned set, so do not modify it further.
157    *
158    * <p>{@code elements} may contain only values of type {@code E}.
159    *
160    * @throws NullPointerException if any of the first {@code n} elements of {@code elements} is null
161    */
construct(int n, @Nullable Object... elements)162   private static <E> ImmutableSet<E> construct(int n, @Nullable Object... elements) {
163     switch (n) {
164       case 0:
165         return of();
166       case 1:
167         @SuppressWarnings("unchecked") // safe; elements contains only E's
168         // requireNonNull is safe because the first `n` elements are non-null.
169         E elem = (E) requireNonNull(elements[0]);
170         return of(elem);
171       default:
172         // continue below to handle the general case
173     }
174     int tableSize = chooseTableSize(n);
175     Object[] table = new Object[tableSize];
176     int mask = tableSize - 1;
177     int hashCode = 0;
178     int uniques = 0;
179     for (int i = 0; i < n; i++) {
180       Object element = checkElementNotNull(elements[i], i);
181       int hash = element.hashCode();
182       for (int j = Hashing.smear(hash); ; j++) {
183         int index = j & mask;
184         Object value = table[index];
185         if (value == null) {
186           // Came to an empty slot. Put the element here.
187           elements[uniques++] = element;
188           table[index] = element;
189           hashCode += hash;
190           break;
191         } else if (value.equals(element)) {
192           break;
193         }
194       }
195     }
196     Arrays.fill(elements, uniques, n, null);
197     if (uniques == 1) {
198       // There is only one element or elements are all duplicates
199       @SuppressWarnings("unchecked") // we are careful to only pass in E
200       // requireNonNull is safe because the first `uniques` elements are non-null.
201       E element = (E) requireNonNull(elements[0]);
202       return new SingletonImmutableSet<E>(element);
203     } else if (chooseTableSize(uniques) < tableSize / 2) {
204       // Resize the table when the array includes too many duplicates.
205       return construct(uniques, elements);
206     } else {
207       @Nullable
208       Object[] uniqueElements =
209           shouldTrim(uniques, elements.length) ? Arrays.copyOf(elements, uniques) : elements;
210       return new RegularImmutableSet<E>(uniqueElements, hashCode, table, mask, uniques);
211     }
212   }
213 
shouldTrim(int actualUnique, int expectedUnique)214   private static boolean shouldTrim(int actualUnique, int expectedUnique) {
215     return actualUnique < (expectedUnique >> 1) + (expectedUnique >> 2);
216   }
217 
218   // We use power-of-2 tables, and this is the highest int that's a power of 2
219   static final int MAX_TABLE_SIZE = Ints.MAX_POWER_OF_TWO;
220 
221   // Represents how tightly we can pack things, as a maximum.
222   private static final double DESIRED_LOAD_FACTOR = 0.7;
223 
224   // If the set has this many elements, it will "max out" the table size
225   private static final int CUTOFF = (int) (MAX_TABLE_SIZE * DESIRED_LOAD_FACTOR);
226 
227   /**
228    * Returns an array size suitable for the backing array of a hash table that uses open addressing
229    * with linear probing in its implementation. The returned size is the smallest power of two that
230    * can hold setSize elements with the desired load factor. Always returns at least setSize + 2.
231    */
232   @VisibleForTesting
chooseTableSize(int setSize)233   static int chooseTableSize(int setSize) {
234     setSize = Math.max(setSize, 2);
235     // Correct the size for open addressing to match desired load factor.
236     if (setSize < CUTOFF) {
237       // Round up to the next highest power of 2.
238       int tableSize = Integer.highestOneBit(setSize - 1) << 1;
239       while (tableSize * DESIRED_LOAD_FACTOR < setSize) {
240         tableSize <<= 1;
241       }
242       return tableSize;
243     }
244 
245     // The table can't be completely full or we'll get infinite reprobes
246     checkArgument(setSize < MAX_TABLE_SIZE, "collection too large");
247     return MAX_TABLE_SIZE;
248   }
249 
250   /**
251    * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order
252    * each appears first in the source collection.
253    *
254    * <p><b>Performance note:</b> This method will sometimes recognize that the actual copy operation
255    * is unnecessary; for example, {@code copyOf(copyOf(anArrayList))} will copy the data only once.
256    * This reduces the expense of habitually making defensive copies at API boundaries. However, the
257    * precise conditions for skipping the copy operation are undefined.
258    *
259    * @throws NullPointerException if any of {@code elements} is null
260    * @since 7.0 (source-compatible since 2.0)
261    */
262   public static <E> ImmutableSet<E> copyOf(Collection<? extends E> elements) {
263     /*
264      * TODO(lowasser): consider checking for ImmutableAsList here
265      * TODO(lowasser): consider checking for Multiset here
266      */
267     // Don't refer to ImmutableSortedSet by name so it won't pull in all that code
268     if (elements instanceof ImmutableSet && !(elements instanceof SortedSet)) {
269       @SuppressWarnings("unchecked") // all supported methods are covariant
270       ImmutableSet<E> set = (ImmutableSet<E>) elements;
271       if (!set.isPartialView()) {
272         return set;
273       }
274     }
275     Object[] array = elements.toArray();
276     return construct(array.length, array);
277   }
278 
279   /**
280    * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order
281    * each appears first in the source iterable. This method iterates over {@code elements} only
282    * once.
283    *
284    * <p><b>Performance note:</b> This method will sometimes recognize that the actual copy operation
285    * is unnecessary; for example, {@code copyOf(copyOf(anArrayList))} should copy the data only
286    * once. This reduces the expense of habitually making defensive copies at API boundaries.
287    * However, the precise conditions for skipping the copy operation are undefined.
288    *
289    * @throws NullPointerException if any of {@code elements} is null
290    */
291   public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
292     return (elements instanceof Collection)
293         ? copyOf((Collection<? extends E>) elements)
294         : copyOf(elements.iterator());
295   }
296 
297   /**
298    * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order
299    * each appears first in the source iterator.
300    *
301    * @throws NullPointerException if any of {@code elements} is null
302    */
303   public static <E> ImmutableSet<E> copyOf(Iterator<? extends E> elements) {
304     // We special-case for 0 or 1 elements, but anything further is madness.
305     if (!elements.hasNext()) {
306       return of();
307     }
308     E first = elements.next();
309     if (!elements.hasNext()) {
310       return of(first);
311     } else {
312       return new ImmutableSet.Builder<E>().add(first).addAll(elements).build();
313     }
314   }
315 
316   /**
317    * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order
318    * each appears first in the source array.
319    *
320    * @throws NullPointerException if any of {@code elements} is null
321    * @since 3.0
322    */
323   public static <E> ImmutableSet<E> copyOf(E[] elements) {
324     switch (elements.length) {
325       case 0:
326         return of();
327       case 1:
328         return of(elements[0]);
329       default:
330         return construct(elements.length, elements.clone());
331     }
332   }
333 
334   ImmutableSet() {}
335 
336   /** Returns {@code true} if the {@code hashCode()} method runs quickly. */
337   boolean isHashCodeFast() {
338     return false;
339   }
340 
341   @Override
342   public boolean equals(@CheckForNull Object object) {
343     if (object == this) {
344       return true;
345     }
346     if (object instanceof ImmutableSet
347         && isHashCodeFast()
348         && ((ImmutableSet<?>) object).isHashCodeFast()
349         && hashCode() != object.hashCode()) {
350       return false;
351     }
352     return Sets.equalsImpl(this, object);
353   }
354 
355   @Override
356   public int hashCode() {
357     return Sets.hashCodeImpl(this);
358   }
359 
360   // This declaration is needed to make Set.iterator() and
361   // ImmutableCollection.iterator() consistent.
362   @Override
363   public abstract UnmodifiableIterator<E> iterator();
364 
365   @LazyInit @RetainedWith @CheckForNull private transient ImmutableList<E> asList;
366 
367   @Override
368   public ImmutableList<E> asList() {
369     ImmutableList<E> result = asList;
370     return (result == null) ? asList = createAsList() : result;
371   }
372 
373   ImmutableList<E> createAsList() {
374     return ImmutableList.asImmutableList(toArray());
375   }
376 
377   /*
378    * This class is used to serialize all ImmutableSet instances, except for
379    * ImmutableEnumSet/ImmutableSortedSet, regardless of implementation type. It
380    * captures their "logical contents" and they are reconstructed using public
381    * static factories. This is necessary to ensure that the existence of a
382    * particular implementation type is an implementation detail.
383    */
384   @J2ktIncompatible // serialization
385   private static class SerializedForm implements Serializable {
386     final Object[] elements;
387 
388     SerializedForm(Object[] elements) {
389       this.elements = elements;
390     }
391 
392     Object readResolve() {
393       return copyOf(elements);
394     }
395 
396     private static final long serialVersionUID = 0;
397   }
398 
399   @Override
400   @J2ktIncompatible // serialization
401   Object writeReplace() {
402     return new SerializedForm(toArray());
403   }
404 
405   @J2ktIncompatible // serialization
406   private void readObject(ObjectInputStream stream) throws InvalidObjectException {
407     throw new InvalidObjectException("Use SerializedForm");
408   }
409 
410   /**
411    * Returns a new builder. The generated builder is equivalent to the builder created by the {@link
412    * Builder} constructor.
413    */
414   public static <E> Builder<E> builder() {
415     return new Builder<E>();
416   }
417 
418   /**
419    * Returns a new builder, expecting the specified number of distinct elements to be added.
420    *
421    * <p>If {@code expectedSize} is exactly the number of distinct elements added to the builder
422    * before {@link Builder#build} is called, the builder is likely to perform better than an unsized
423    * {@link #builder()} would have.
424    *
425    * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to,
426    * but not exactly, the number of distinct elements added to the builder.
427    *
428    * @since 23.1
429    */
430   public static <E> Builder<E> builderWithExpectedSize(int expectedSize) {
431     checkNonnegative(expectedSize, "expectedSize");
432     return new Builder<E>(expectedSize);
433   }
434 
435   /**
436    * A builder for creating {@code ImmutableSet} instances. Example:
437    *
438    * <pre>{@code
439    * static final ImmutableSet<Color> GOOGLE_COLORS =
440    *     ImmutableSet.<Color>builder()
441    *         .addAll(WEBSAFE_COLORS)
442    *         .add(new Color(0, 191, 255))
443    *         .build();
444    * }</pre>
445    *
446    * <p>Elements appear in the resulting set in the same order they were first added to the builder.
447    *
448    * <p>Building does not change the state of the builder, so it is still possible to add more
449    * elements and to build again.
450    *
451    * @since 2.0
452    */
453   public static class Builder<E> extends ImmutableCollection.ArrayBasedBuilder<E> {
454     @VisibleForTesting @CheckForNull @Nullable Object[] hashTable;
455     private int hashCode;
456 
457     /**
458      * Creates a new builder. The returned builder is equivalent to the builder generated by {@link
459      * ImmutableSet#builder}.
460      */
461     public Builder() {
462       super(DEFAULT_INITIAL_CAPACITY);
463     }
464 
465     Builder(int capacity) {
466       super(capacity);
467       this.hashTable = new @Nullable Object[chooseTableSize(capacity)];
468     }
469 
470     /**
471      * Adds {@code element} to the {@code ImmutableSet}. If the {@code ImmutableSet} already
472      * contains {@code element}, then {@code add} has no effect (only the previously added element
473      * is retained).
474      *
475      * @param element the element to add
476      * @return this {@code Builder} object
477      * @throws NullPointerException if {@code element} is null
478      */
479     @CanIgnoreReturnValue
480     @Override
481     public Builder<E> add(E element) {
482       checkNotNull(element);
483       if (hashTable != null && chooseTableSize(size) <= hashTable.length) {
484         addDeduping(element);
485         return this;
486       } else {
487         hashTable = null;
488         super.add(element);
489         return this;
490       }
491     }
492 
493     /**
494      * Adds each element of {@code elements} to the {@code ImmutableSet}, ignoring duplicate
495      * elements (only the first duplicate element is added).
496      *
497      * @param elements the elements to add
498      * @return this {@code Builder} object
499      * @throws NullPointerException if {@code elements} is null or contains a null element
500      */
501     @Override
502     @CanIgnoreReturnValue
503     public Builder<E> add(E... elements) {
504       if (hashTable != null) {
505         for (E e : elements) {
506           add(e);
507         }
508       } else {
509         super.add(elements);
510       }
511       return this;
512     }
513 
514     private void addDeduping(E element) {
515       requireNonNull(hashTable); // safe because we check for null before calling this method
516       int mask = hashTable.length - 1;
517       int hash = element.hashCode();
518       for (int i = Hashing.smear(hash); ; i++) {
519         i &= mask;
520         Object previous = hashTable[i];
521         if (previous == null) {
522           hashTable[i] = element;
523           hashCode += hash;
524           super.add(element);
525           return;
526         } else if (previous.equals(element)) {
527           return;
528         }
529       }
530     }
531 
532     /**
533      * Adds each element of {@code elements} to the {@code ImmutableSet}, ignoring duplicate
534      * elements (only the first duplicate element is added).
535      *
536      * @param elements the {@code Iterable} to add to the {@code ImmutableSet}
537      * @return this {@code Builder} object
538      * @throws NullPointerException if {@code elements} is null or contains a null element
539      */
540     @CanIgnoreReturnValue
541     @Override
542     public Builder<E> addAll(Iterable<? extends E> elements) {
543       checkNotNull(elements);
544       if (hashTable != null) {
545         for (E e : elements) {
546           add(e);
547         }
548       } else {
549         super.addAll(elements);
550       }
551       return this;
552     }
553 
554     /**
555      * Adds each element of {@code elements} to the {@code ImmutableSet}, ignoring duplicate
556      * elements (only the first duplicate element is added).
557      *
558      * @param elements the elements to add to the {@code ImmutableSet}
559      * @return this {@code Builder} object
560      * @throws NullPointerException if {@code elements} is null or contains a null element
561      */
562     @CanIgnoreReturnValue
563     @Override
564     public Builder<E> addAll(Iterator<? extends E> elements) {
565       checkNotNull(elements);
566       while (elements.hasNext()) {
567         add(elements.next());
568       }
569       return this;
570     }
571 
572     @CanIgnoreReturnValue
573     @SuppressWarnings("unchecked") // ArrayBasedBuilder stores its elements as Object.
574     Builder<E> combine(Builder<E> other) {
575       if (hashTable != null) {
576         for (int i = 0; i < other.size; ++i) {
577           // requireNonNull is safe because the first `size` elements are non-null.
578           add((E) requireNonNull(other.contents[i]));
579         }
580       } else {
581         addAll(other.contents, other.size);
582       }
583       return this;
584     }
585 
586     /**
587      * Returns a newly-created {@code ImmutableSet} based on the contents of the {@code Builder}.
588      */
589     @SuppressWarnings("unchecked")
590     @Override
591     public ImmutableSet<E> build() {
592       switch (size) {
593         case 0:
594           return of();
595         case 1:
596           /*
597            * requireNonNull is safe because we ensure that the first `size` elements have been
598            * populated.
599            */
600           return (ImmutableSet<E>) of(requireNonNull(contents[0]));
601         default:
602           ImmutableSet<E> result;
603           if (hashTable != null && chooseTableSize(size) == hashTable.length) {
604             @Nullable
605             Object[] uniqueElements =
606                 shouldTrim(size, contents.length) ? Arrays.copyOf(contents, size) : contents;
607             result =
608                 new RegularImmutableSet<E>(
609                     uniqueElements, hashCode, hashTable, hashTable.length - 1, size);
610           } else {
611             result = construct(size, contents);
612             // construct has the side effect of deduping contents, so we update size
613             // accordingly.
614             size = result.size();
615           }
616           forceCopy = true;
617           hashTable = null;
618           return result;
619       }
620     }
621   }
622 
623   private static final long serialVersionUID = 0xdecaf;
624 }
625