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