Coverage Summary for Class: ImmutableSet (com.google.common.collect)
| Class | Method, % | Line, % |
|---|---|---|
| ImmutableSet | 60% (15/25) | 61.2% (49/80) |
| ImmutableSet$Builder | 66.7% (8/12) | 60.5% (23/38) |
| ImmutableSet$Indexed | 0% (0/6) | 0% (0/10) |
| ImmutableSet$Indexed$1 | 0% (0/3) | 0% (0/3) |
| ImmutableSet$JdkBackedSetBuilderImpl | 0% (0/4) | 0% (0/15) |
| ImmutableSet$RegularSetBuilderImpl | 80% (8/10) | 83.1% (64/77) |
| ImmutableSet$SerializedForm | 0% (0/2) | 0% (0/3) |
| ImmutableSet$SetBuilderImpl | 50% (3/6) | 57.1% (12/21) |
| Total | 50% (34/68) | 59.9% (148/247) |
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 java.util.Objects.requireNonNull; 23 24 import com.google.common.annotations.Beta; 25 import com.google.common.annotations.GwtCompatible; 26 import com.google.common.annotations.VisibleForTesting; 27 import com.google.common.math.IntMath; 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.Serializable; 33 import java.math.RoundingMode; 34 import java.util.Arrays; 35 import java.util.Collection; 36 import java.util.Collections; 37 import java.util.EnumSet; 38 import java.util.Iterator; 39 import java.util.Set; 40 import java.util.SortedSet; 41 import java.util.Spliterator; 42 import java.util.function.Consumer; 43 import java.util.stream.Collector; 44 import javax.annotation.CheckForNull; 45 import org.checkerframework.checker.nullness.qual.Nullable; 46 47 /** 48 * A {@link Set} whose contents will never change, with many other important properties detailed at 49 * {@link ImmutableCollection}. 50 * 51 * @since 2.0 52 */ 53 @GwtCompatible(serializable = true, emulated = true) 54 @SuppressWarnings("serial") // we're overriding default serialization 55 @ElementTypesAreNonnullByDefault 56 public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements Set<E> { 57 static final int SPLITERATOR_CHARACTERISTICS = 58 ImmutableCollection.SPLITERATOR_CHARACTERISTICS | Spliterator.DISTINCT; 59 60 /** 61 * Returns a {@code Collector} that accumulates the input elements into a new {@code 62 * ImmutableSet}. Elements appear in the resulting set in the encounter order of the stream; if 63 * the stream contains duplicates (according to {@link Object#equals(Object)}), only the first 64 * duplicate in encounter order will appear in the result. 65 * 66 * @since 21.0 67 */ 68 public static <E> Collector<E, ?, ImmutableSet<E>> toImmutableSet() { 69 return CollectCollectors.toImmutableSet(); 70 } 71 72 /** 73 * Returns the empty immutable set. Preferred over {@link Collections#emptySet} for code 74 * consistency, and because the return type conveys the immutability guarantee. 75 * 76 * <p><b>Performance note:</b> the instance returned is a singleton. 77 */ 78 @SuppressWarnings({"unchecked"}) // fully variant implementation (never actually produces any Es) 79 public static <E> ImmutableSet<E> of() { 80 return (ImmutableSet<E>) RegularImmutableSet.EMPTY; 81 } 82 83 /** 84 * Returns an immutable set containing {@code element}. Preferred over {@link 85 * Collections#singleton} for code consistency, {@code null} rejection, and because the return 86 * type conveys the immutability guarantee. 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, minus duplicates, in the order each was 94 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 95 * the first are ignored. 96 */ 97 public static <E> ImmutableSet<E> of(E e1, E e2) { 98 return construct(2, 2, e1, e2); 99 } 100 101 /** 102 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 103 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 104 * the first are ignored. 105 */ 106 public static <E> ImmutableSet<E> of(E e1, E e2, E e3) { 107 return construct(3, 3, e1, e2, e3); 108 } 109 110 /** 111 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 112 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 113 * the first are ignored. 114 */ 115 public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4) { 116 return construct(4, 4, e1, e2, e3, e4); 117 } 118 119 /** 120 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 121 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 122 * the first are ignored. 123 */ 124 public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5) { 125 return construct(5, 5, e1, e2, e3, e4, e5); 126 } 127 128 /** 129 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 130 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 131 * the first are ignored. 132 * 133 * <p>The array {@code others} must not be longer than {@code Integer.MAX_VALUE - 6}. 134 * 135 * @since 3.0 (source-compatible since 2.0) 136 */ 137 @SafeVarargs // For Eclipse. For internal javac we have disabled this pointless type of warning. 138 public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) { 139 checkArgument( 140 others.length <= Integer.MAX_VALUE - 6, "the total number of elements must fit in an int"); 141 final int paramCount = 6; 142 Object[] elements = new Object[paramCount + others.length]; 143 elements[0] = e1; 144 elements[1] = e2; 145 elements[2] = e3; 146 elements[3] = e4; 147 elements[4] = e5; 148 elements[5] = e6; 149 System.arraycopy(others, 0, elements, paramCount, others.length); 150 return construct(elements.length, elements.length, elements); 151 } 152 153 /** 154 * Constructs an {@code ImmutableSet} from the first {@code n} elements of the specified array, 155 * which we have no particular reason to believe does or does not contain duplicates. If {@code k} 156 * is the size of the returned {@code ImmutableSet}, then the unique elements of {@code elements} 157 * will be in the first {@code k} positions, and {@code elements[i] == null} for {@code k <= i < 158 * n}. 159 * 160 * <p>This may modify {@code elements}. Additionally, if {@code n == elements.length} and {@code 161 * elements} contains no duplicates, {@code elements} may be used without copying in the returned 162 * {@code ImmutableSet}, in which case the caller must not modify it. 163 * 164 * <p>{@code elements} may contain only values of type {@code E}. 165 * 166 * @throws NullPointerException if any of the first {@code n} elements of {@code elements} is null 167 */ 168 private static <E> ImmutableSet<E> constructUnknownDuplication(int n, Object... elements) { 169 // Guess the size is "halfway between" all duplicates and no duplicates, on a log scale. 170 return construct( 171 n, 172 Math.max( 173 ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY, 174 IntMath.sqrt(n, RoundingMode.CEILING)), 175 elements); 176 } 177 178 /** 179 * Constructs an {@code ImmutableSet} from the first {@code n} elements of the specified array. If 180 * {@code k} is the size of the returned {@code ImmutableSet}, then the unique elements of {@code 181 * elements} will be in the first {@code k} positions, and {@code elements[i] == null} for {@code 182 * k <= i < n}. 183 * 184 * <p>This may modify {@code elements}. Additionally, if {@code n == elements.length} and {@code 185 * elements} contains no duplicates, {@code elements} may be used without copying in the returned 186 * {@code ImmutableSet}, in which case it may no longer be modified. 187 * 188 * <p>{@code elements} may contain only values of type {@code E}. 189 * 190 * @throws NullPointerException if any of the first {@code n} elements of {@code elements} is null 191 */ 192 private static <E> ImmutableSet<E> construct(int n, int expectedSize, Object... elements) { 193 switch (n) { 194 case 0: 195 return of(); 196 case 1: 197 @SuppressWarnings("unchecked") // safe; elements contains only E's 198 E elem = (E) elements[0]; 199 return of(elem); 200 default: 201 SetBuilderImpl<E> builder = new RegularSetBuilderImpl<E>(expectedSize); 202 for (int i = 0; i < n; i++) { 203 @SuppressWarnings("unchecked") 204 E e = (E) checkNotNull(elements[i]); 205 builder = builder.add(e); 206 } 207 return builder.review().build(); 208 } 209 } 210 211 /** 212 * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order 213 * each appears first in the source collection. 214 * 215 * <p><b>Performance note:</b> This method will sometimes recognize that the actual copy operation 216 * is unnecessary; for example, {@code copyOf(copyOf(anArrayList))} will copy the data only once. 217 * This reduces the expense of habitually making defensive copies at API boundaries. However, the 218 * precise conditions for skipping the copy operation are undefined. 219 * 220 * @throws NullPointerException if any of {@code elements} is null 221 * @since 7.0 (source-compatible since 2.0) 222 */ 223 public static <E> ImmutableSet<E> copyOf(Collection<? extends E> elements) { 224 /* 225 * TODO(lowasser): consider checking for ImmutableAsList here 226 * TODO(lowasser): consider checking for Multiset here 227 */ 228 // Don't refer to ImmutableSortedSet by name so it won't pull in all that code 229 if (elements instanceof ImmutableSet && !(elements instanceof SortedSet)) { 230 @SuppressWarnings("unchecked") // all supported methods are covariant 231 ImmutableSet<E> set = (ImmutableSet<E>) elements; 232 if (!set.isPartialView()) { 233 return set; 234 } 235 } else if (elements instanceof EnumSet) { 236 return copyOfEnumSet((EnumSet) elements); 237 } 238 Object[] array = elements.toArray(); 239 if (elements instanceof Set) { 240 // assume probably no duplicates (though it might be using different equality semantics) 241 return construct(array.length, array.length, array); 242 } else { 243 return constructUnknownDuplication(array.length, array); 244 } 245 } 246 247 /** 248 * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order 249 * each appears first in the source iterable. This method iterates over {@code elements} only 250 * once. 251 * 252 * <p><b>Performance note:</b> This method will sometimes recognize that the actual copy operation 253 * is unnecessary; for example, {@code copyOf(copyOf(anArrayList))} should copy the data only 254 * once. This reduces the expense of habitually making defensive copies at API boundaries. 255 * However, the precise conditions for skipping the copy operation are undefined. 256 * 257 * @throws NullPointerException if any of {@code elements} is null 258 */ 259 public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) { 260 return (elements instanceof Collection) 261 ? copyOf((Collection<? extends E>) elements) 262 : copyOf(elements.iterator()); 263 } 264 265 /** 266 * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order 267 * each appears first in the source iterator. 268 * 269 * @throws NullPointerException if any of {@code elements} is null 270 */ 271 public static <E> ImmutableSet<E> copyOf(Iterator<? extends E> elements) { 272 // We special-case for 0 or 1 elements, but anything further is madness. 273 if (!elements.hasNext()) { 274 return of(); 275 } 276 E first = elements.next(); 277 if (!elements.hasNext()) { 278 return of(first); 279 } else { 280 return new ImmutableSet.Builder<E>().add(first).addAll(elements).build(); 281 } 282 } 283 284 /** 285 * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order 286 * each appears first in the source array. 287 * 288 * @throws NullPointerException if any of {@code elements} is null 289 * @since 3.0 290 */ 291 public static <E> ImmutableSet<E> copyOf(E[] elements) { 292 switch (elements.length) { 293 case 0: 294 return of(); 295 case 1: 296 return of(elements[0]); 297 default: 298 return constructUnknownDuplication(elements.length, elements.clone()); 299 } 300 } 301 302 @SuppressWarnings("rawtypes") // necessary to compile against Java 8 303 private static ImmutableSet copyOfEnumSet(EnumSet enumSet) { 304 return ImmutableEnumSet.asImmutable(EnumSet.copyOf(enumSet)); 305 } 306 307 ImmutableSet() {} 308 309 /** Returns {@code true} if the {@code hashCode()} method runs quickly. */ 310 boolean isHashCodeFast() { 311 return false; 312 } 313 314 @Override 315 public boolean equals(@CheckForNull Object object) { 316 if (object == this) { 317 return true; 318 } 319 if (object instanceof ImmutableSet 320 && isHashCodeFast() 321 && ((ImmutableSet<?>) object).isHashCodeFast() 322 && hashCode() != object.hashCode()) { 323 return false; 324 } 325 return Sets.equalsImpl(this, object); 326 } 327 328 @Override 329 public int hashCode() { 330 return Sets.hashCodeImpl(this); 331 } 332 333 // This declaration is needed to make Set.iterator() and 334 // ImmutableCollection.iterator() consistent. 335 @Override 336 public abstract UnmodifiableIterator<E> iterator(); 337 338 @LazyInit @RetainedWith @CheckForNull private transient ImmutableList<E> asList; 339 340 @Override 341 public ImmutableList<E> asList() { 342 ImmutableList<E> result = asList; 343 return (result == null) ? asList = createAsList() : result; 344 } 345 346 ImmutableList<E> createAsList() { 347 return new RegularImmutableAsList<E>(this, toArray()); 348 } 349 350 abstract static class Indexed<E> extends ImmutableSet<E> { 351 abstract E get(int index); 352 353 @Override 354 public UnmodifiableIterator<E> iterator() { 355 return asList().iterator(); 356 } 357 358 @Override 359 public Spliterator<E> spliterator() { 360 return CollectSpliterators.indexed(size(), SPLITERATOR_CHARACTERISTICS, this::get); 361 } 362 363 @Override 364 public void forEach(Consumer<? super E> consumer) { 365 checkNotNull(consumer); 366 int n = size(); 367 for (int i = 0; i < n; i++) { 368 consumer.accept(get(i)); 369 } 370 } 371 372 @Override 373 int copyIntoArray(@Nullable Object[] dst, int offset) { 374 return asList().copyIntoArray(dst, offset); 375 } 376 377 @Override 378 ImmutableList<E> createAsList() { 379 return new ImmutableAsList<E>() { 380 @Override 381 public E get(int index) { 382 return Indexed.this.get(index); 383 } 384 385 @Override 386 Indexed<E> delegateCollection() { 387 return Indexed.this; 388 } 389 }; 390 } 391 } 392 393 /* 394 * This class is used to serialize all ImmutableSet instances, except for 395 * ImmutableEnumSet/ImmutableSortedSet, regardless of implementation type. It 396 * captures their "logical contents" and they are reconstructed using public 397 * static factories. This is necessary to ensure that the existence of a 398 * particular implementation type is an implementation detail. 399 */ 400 private static class SerializedForm implements Serializable { 401 final Object[] elements; 402 403 SerializedForm(Object[] elements) { 404 this.elements = elements; 405 } 406 407 Object readResolve() { 408 return copyOf(elements); 409 } 410 411 private static final long serialVersionUID = 0; 412 } 413 414 @Override 415 Object writeReplace() { 416 return new SerializedForm(toArray()); 417 } 418 419 /** 420 * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 421 * Builder} constructor. 422 */ 423 public static <E> Builder<E> builder() { 424 return new Builder<E>(); 425 } 426 427 /** 428 * Returns a new builder, expecting the specified number of distinct elements to be added. 429 * 430 * <p>If {@code expectedSize} is exactly the number of distinct elements added to the builder 431 * before {@link Builder#build} is called, the builder is likely to perform better than an unsized 432 * {@link #builder()} would have. 433 * 434 * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to, 435 * but not exactly, the number of distinct elements added to the builder. 436 * 437 * @since 23.1 438 */ 439 @Beta 440 public static <E> Builder<E> builderWithExpectedSize(int expectedSize) { 441 checkNonnegative(expectedSize, "expectedSize"); 442 return new Builder<E>(expectedSize); 443 } 444 445 /** 446 * A builder for creating {@code ImmutableSet} instances. Example: 447 * 448 * <pre>{@code 449 * static final ImmutableSet<Color> GOOGLE_COLORS = 450 * ImmutableSet.<Color>builder() 451 * .addAll(WEBSAFE_COLORS) 452 * .add(new Color(0, 191, 255)) 453 * .build(); 454 * }</pre> 455 * 456 * <p>Elements appear in the resulting set in the same order they were first added to the builder. 457 * 458 * <p>Building does not change the state of the builder, so it is still possible to add more 459 * elements and to build again. 460 * 461 * @since 2.0 462 */ 463 public static class Builder<E> extends ImmutableCollection.Builder<E> { 464 /* 465 * `impl` is null only for instances of the subclass, ImmutableSortedSet.Builder. That subclass 466 * overrides all the methods that access it here. Thus, all the methods here can safely assume 467 * that this field is non-null. 468 */ 469 @CheckForNull private SetBuilderImpl<E> impl; 470 boolean forceCopy; 471 472 public Builder() { 473 this(DEFAULT_INITIAL_CAPACITY); 474 } 475 476 Builder(int capacity) { 477 impl = new RegularSetBuilderImpl<E>(capacity); 478 } 479 480 Builder(@SuppressWarnings("unused") boolean subclass) { 481 this.impl = null; // unused 482 } 483 484 @VisibleForTesting 485 void forceJdk() { 486 requireNonNull(impl); // see the comment on the field 487 this.impl = new JdkBackedSetBuilderImpl<E>(impl); 488 } 489 490 final void copyIfNecessary() { 491 if (forceCopy) { 492 copy(); 493 forceCopy = false; 494 } 495 } 496 497 void copy() { 498 requireNonNull(impl); // see the comment on the field 499 impl = impl.copy(); 500 } 501 502 @Override 503 @CanIgnoreReturnValue 504 public Builder<E> add(E element) { 505 requireNonNull(impl); // see the comment on the field 506 checkNotNull(element); 507 copyIfNecessary(); 508 impl = impl.add(element); 509 return this; 510 } 511 512 @Override 513 @CanIgnoreReturnValue 514 public Builder<E> add(E... elements) { 515 super.add(elements); 516 return this; 517 } 518 519 /** 520 * Adds each element of {@code elements} to the {@code ImmutableSet}, ignoring duplicate 521 * elements (only the first duplicate element is added). 522 * 523 * @param elements the elements to add 524 * @return this {@code Builder} object 525 * @throws NullPointerException if {@code elements} is null or contains a null element 526 */ 527 @Override 528 @CanIgnoreReturnValue 529 public Builder<E> addAll(Iterable<? extends E> elements) { 530 super.addAll(elements); 531 return this; 532 } 533 534 @Override 535 @CanIgnoreReturnValue 536 public Builder<E> addAll(Iterator<? extends E> elements) { 537 super.addAll(elements); 538 return this; 539 } 540 541 Builder<E> combine(Builder<E> other) { 542 requireNonNull(impl); 543 requireNonNull(other.impl); 544 /* 545 * For discussion of requireNonNull, see the comment on the field. 546 * 547 * (And I don't believe there's any situation in which we call x.combine(y) when x is a plain 548 * ImmutableSet.Builder but y is an ImmutableSortedSet.Builder (or vice versa). Certainly 549 * ImmutableSortedSet.Builder.combine() is written as if its argument will never be a plain 550 * ImmutableSet.Builder: It casts immediately to ImmutableSortedSet.Builder.) 551 */ 552 copyIfNecessary(); 553 this.impl = this.impl.combine(other.impl); 554 return this; 555 } 556 557 @Override 558 public ImmutableSet<E> build() { 559 requireNonNull(impl); // see the comment on the field 560 forceCopy = true; 561 impl = impl.review(); 562 return impl.build(); 563 } 564 } 565 566 /** Swappable internal implementation of an ImmutableSet.Builder. */ 567 private abstract static class SetBuilderImpl<E> { 568 // The first `distinct` elements are non-null. 569 @Nullable E[] dedupedElements; 570 int distinct; 571 572 @SuppressWarnings("unchecked") 573 SetBuilderImpl(int expectedCapacity) { 574 this.dedupedElements = (@Nullable E[]) new @Nullable Object[expectedCapacity]; 575 this.distinct = 0; 576 } 577 578 /** Initializes this SetBuilderImpl with a copy of the deduped elements array from toCopy. */ 579 SetBuilderImpl(SetBuilderImpl<E> toCopy) { 580 this.dedupedElements = Arrays.copyOf(toCopy.dedupedElements, toCopy.dedupedElements.length); 581 this.distinct = toCopy.distinct; 582 } 583 584 /** 585 * Resizes internal data structures if necessary to store the specified number of distinct 586 * elements. 587 */ 588 private void ensureCapacity(int minCapacity) { 589 if (minCapacity > dedupedElements.length) { 590 int newCapacity = 591 ImmutableCollection.Builder.expandedCapacity(dedupedElements.length, minCapacity); 592 dedupedElements = Arrays.copyOf(dedupedElements, newCapacity); 593 } 594 } 595 596 /** Adds e to the insertion-order array of deduplicated elements. Calls ensureCapacity. */ 597 final void addDedupedElement(E e) { 598 ensureCapacity(distinct + 1); 599 dedupedElements[distinct++] = e; 600 } 601 602 /** 603 * Adds e to this SetBuilderImpl, returning the updated result. Only use the returned 604 * SetBuilderImpl, since we may switch implementations if e.g. hash flooding is detected. 605 */ 606 abstract SetBuilderImpl<E> add(E e); 607 608 /** Adds all the elements from the specified SetBuilderImpl to this SetBuilderImpl. */ 609 final SetBuilderImpl<E> combine(SetBuilderImpl<E> other) { 610 SetBuilderImpl<E> result = this; 611 for (int i = 0; i < other.distinct; i++) { 612 /* 613 * requireNonNull is safe because we ensure that the first `distinct` elements have been 614 * populated. 615 */ 616 result = result.add(requireNonNull(other.dedupedElements[i])); 617 } 618 return result; 619 } 620 621 /** 622 * Creates a new copy of this SetBuilderImpl. Modifications to that SetBuilderImpl will not 623 * affect this SetBuilderImpl or sets constructed from this SetBuilderImpl via build(). 624 */ 625 abstract SetBuilderImpl<E> copy(); 626 627 /** 628 * Call this before build(). Does a final check on the internal data structures, e.g. shrinking 629 * unnecessarily large structures or detecting previously unnoticed hash flooding. 630 */ 631 SetBuilderImpl<E> review() { 632 return this; 633 } 634 635 abstract ImmutableSet<E> build(); 636 } 637 638 // We use power-of-2 tables, and this is the highest int that's a power of 2 639 static final int MAX_TABLE_SIZE = Ints.MAX_POWER_OF_TWO; 640 641 // Represents how tightly we can pack things, as a maximum. 642 private static final double DESIRED_LOAD_FACTOR = 0.7; 643 644 // If the set has this many elements, it will "max out" the table size 645 private static final int CUTOFF = (int) (MAX_TABLE_SIZE * DESIRED_LOAD_FACTOR); 646 647 /** 648 * Returns an array size suitable for the backing array of a hash table that uses open addressing 649 * with linear probing in its implementation. The returned size is the smallest power of two that 650 * can hold setSize elements with the desired load factor. Always returns at least setSize + 2. 651 */ 652 // TODO(cpovirk): Move to Hashing or something, since it's used elsewhere in the Android version. 653 static int chooseTableSize(int setSize) { 654 setSize = Math.max(setSize, 2); 655 // Correct the size for open addressing to match desired load factor. 656 if (setSize < CUTOFF) { 657 // Round up to the next highest power of 2. 658 int tableSize = Integer.highestOneBit(setSize - 1) << 1; 659 while (tableSize * DESIRED_LOAD_FACTOR < setSize) { 660 tableSize <<= 1; 661 } 662 return tableSize; 663 } 664 665 // The table can't be completely full or we'll get infinite reprobes 666 checkArgument(setSize < MAX_TABLE_SIZE, "collection too large"); 667 return MAX_TABLE_SIZE; 668 } 669 670 /** 671 * Default implementation of the guts of ImmutableSet.Builder, creating an open-addressed hash 672 * table and deduplicating elements as they come, so it only allocates O(max(distinct, 673 * expectedCapacity)) rather than O(calls to add). 674 * 675 * <p>This implementation attempts to detect hash flooding, and if it's identified, falls back to 676 * JdkBackedSetBuilderImpl. 677 */ 678 private static final class RegularSetBuilderImpl<E> extends SetBuilderImpl<E> { 679 private @Nullable Object[] hashTable; 680 private int maxRunBeforeFallback; 681 private int expandTableThreshold; 682 private int hashCode; 683 684 RegularSetBuilderImpl(int expectedCapacity) { 685 super(expectedCapacity); 686 int tableSize = chooseTableSize(expectedCapacity); 687 this.hashTable = new @Nullable Object[tableSize]; 688 this.maxRunBeforeFallback = maxRunBeforeFallback(tableSize); 689 this.expandTableThreshold = (int) (DESIRED_LOAD_FACTOR * tableSize); 690 } 691 692 RegularSetBuilderImpl(RegularSetBuilderImpl<E> toCopy) { 693 super(toCopy); 694 this.hashTable = Arrays.copyOf(toCopy.hashTable, toCopy.hashTable.length); 695 this.maxRunBeforeFallback = toCopy.maxRunBeforeFallback; 696 this.expandTableThreshold = toCopy.expandTableThreshold; 697 this.hashCode = toCopy.hashCode; 698 } 699 700 @Override 701 SetBuilderImpl<E> add(E e) { 702 checkNotNull(e); 703 int eHash = e.hashCode(); 704 int i0 = Hashing.smear(eHash); 705 int mask = hashTable.length - 1; 706 for (int i = i0; i - i0 < maxRunBeforeFallback; i++) { 707 int index = i & mask; 708 Object tableEntry = hashTable[index]; 709 if (tableEntry == null) { 710 addDedupedElement(e); 711 hashTable[index] = e; 712 hashCode += eHash; 713 ensureTableCapacity(distinct); // rebuilds table if necessary 714 return this; 715 } else if (tableEntry.equals(e)) { // not a new element, ignore 716 return this; 717 } 718 } 719 // we fell out of the loop due to a long run; fall back to JDK impl 720 return new JdkBackedSetBuilderImpl<E>(this).add(e); 721 } 722 723 @Override 724 SetBuilderImpl<E> copy() { 725 return new RegularSetBuilderImpl<E>(this); 726 } 727 728 @Override 729 SetBuilderImpl<E> review() { 730 int targetTableSize = chooseTableSize(distinct); 731 if (targetTableSize * 2 < hashTable.length) { 732 hashTable = rebuildHashTable(targetTableSize, dedupedElements, distinct); 733 maxRunBeforeFallback = maxRunBeforeFallback(targetTableSize); 734 expandTableThreshold = (int) (DESIRED_LOAD_FACTOR * targetTableSize); 735 } 736 return hashFloodingDetected(hashTable) ? new JdkBackedSetBuilderImpl<E>(this) : this; 737 } 738 739 @Override 740 ImmutableSet<E> build() { 741 switch (distinct) { 742 case 0: 743 return of(); 744 case 1: 745 /* 746 * requireNonNull is safe because we ensure that the first `distinct` elements have been 747 * populated. 748 */ 749 return of(requireNonNull(dedupedElements[0])); 750 default: 751 /* 752 * The suppression is safe because we ensure that the first `distinct` elements have been 753 * populated. 754 */ 755 @SuppressWarnings("nullness") 756 Object[] elements = 757 (distinct == dedupedElements.length) 758 ? dedupedElements 759 : Arrays.copyOf(dedupedElements, distinct); 760 return new RegularImmutableSet<E>(elements, hashCode, hashTable, hashTable.length - 1); 761 } 762 } 763 764 /** Builds a new open-addressed hash table from the first n objects in elements. */ 765 static @Nullable Object[] rebuildHashTable( 766 int newTableSize, @Nullable Object[] elements, int n) { 767 @Nullable Object[] hashTable = new @Nullable Object[newTableSize]; 768 int mask = hashTable.length - 1; 769 for (int i = 0; i < n; i++) { 770 // requireNonNull is safe because we ensure that the first n elements have been populated. 771 Object e = requireNonNull(elements[i]); 772 int j0 = Hashing.smear(e.hashCode()); 773 for (int j = j0; ; j++) { 774 int index = j & mask; 775 if (hashTable[index] == null) { 776 hashTable[index] = e; 777 break; 778 } 779 } 780 } 781 return hashTable; 782 } 783 784 void ensureTableCapacity(int minCapacity) { 785 if (minCapacity > expandTableThreshold && hashTable.length < MAX_TABLE_SIZE) { 786 int newTableSize = hashTable.length * 2; 787 hashTable = rebuildHashTable(newTableSize, dedupedElements, distinct); 788 maxRunBeforeFallback = maxRunBeforeFallback(newTableSize); 789 expandTableThreshold = (int) (DESIRED_LOAD_FACTOR * newTableSize); 790 } 791 } 792 793 /** 794 * We attempt to detect deliberate hash flooding attempts. If one is detected, we fall back to a 795 * wrapper around j.u.HashSet, which has built in flooding protection. MAX_RUN_MULTIPLIER was 796 * determined experimentally to match our desired probability of false positives. 797 */ 798 // NB: yes, this is surprisingly high, but that's what the experiments said was necessary 799 // Raising this number slows the worst-case contains behavior, speeds up hashFloodingDetected, 800 // and reduces the false-positive probability. 801 static final int MAX_RUN_MULTIPLIER = 13; 802 803 /** 804 * Checks the whole hash table for poor hash distribution. Takes O(n) in the worst case, O(n / 805 * log n) on average. 806 * 807 * <p>The online hash flooding detecting in RegularSetBuilderImpl.add can detect e.g. many 808 * exactly matching hash codes, which would cause construction to take O(n^2), but can't detect 809 * e.g. hash codes adversarially designed to go into ascending table locations, which keeps 810 * construction O(n) (as desired) but then can have O(n) queries later. 811 * 812 * <p>If this returns false, then no query can take more than O(log n). 813 * 814 * <p>Note that for a RegularImmutableSet with elements with truly random hash codes, contains 815 * operations take expected O(1) time but with high probability take O(log n) for at least some 816 * element. (https://en.wikipedia.org/wiki/Linear_probing#Analysis) 817 * 818 * <p>This method may return {@code true} even on truly random input, but {@code 819 * ImmutableSetTest} tests that the probability of that is low. 820 */ 821 static boolean hashFloodingDetected(@Nullable Object[] hashTable) { 822 int maxRunBeforeFallback = maxRunBeforeFallback(hashTable.length); 823 int mask = hashTable.length - 1; 824 825 // Invariant: all elements at indices in [knownRunStart, knownRunEnd) are nonnull. 826 // If knownRunStart == knownRunEnd, this is vacuously true. 827 // When knownRunEnd exceeds hashTable.length, it "wraps", detecting runs around the end 828 // of the table. 829 int knownRunStart = 0; 830 int knownRunEnd = 0; 831 832 outerLoop: 833 while (knownRunStart < hashTable.length) { 834 if (knownRunStart == knownRunEnd && hashTable[knownRunStart] == null) { 835 if (hashTable[(knownRunStart + maxRunBeforeFallback - 1) & mask] == null) { 836 // There are only maxRunBeforeFallback - 1 elements between here and there, 837 // so even if they were all nonnull, we wouldn't detect a hash flood. Therefore, 838 // we can skip them all. 839 knownRunStart += maxRunBeforeFallback; 840 } else { 841 knownRunStart++; // the only case in which maxRunEnd doesn't increase by mRBF 842 // happens about f * (1-f) for f = DESIRED_LOAD_FACTOR, so around 21% of the time 843 } 844 knownRunEnd = knownRunStart; 845 } else { 846 for (int j = knownRunStart + maxRunBeforeFallback - 1; j >= knownRunEnd; j--) { 847 if (hashTable[j & mask] == null) { 848 knownRunEnd = knownRunStart + maxRunBeforeFallback; 849 knownRunStart = j + 1; 850 continue outerLoop; 851 } 852 } 853 return true; 854 } 855 } 856 return false; 857 } 858 859 /** 860 * If more than this many consecutive positions are filled in a table of the specified size, 861 * report probable hash flooding. ({@link #hashFloodingDetected} may also report hash flooding 862 * if fewer consecutive positions are filled; see that method for details.) 863 */ 864 static int maxRunBeforeFallback(int tableSize) { 865 return MAX_RUN_MULTIPLIER * IntMath.log2(tableSize, RoundingMode.UNNECESSARY); 866 } 867 } 868 869 /** 870 * SetBuilderImpl version that uses a JDK HashSet, which has built in hash flooding protection. 871 */ 872 private static final class JdkBackedSetBuilderImpl<E> extends SetBuilderImpl<E> { 873 private final Set<Object> delegate; 874 875 JdkBackedSetBuilderImpl(SetBuilderImpl<E> toCopy) { 876 super(toCopy); // initializes dedupedElements and distinct 877 delegate = Sets.newHashSetWithExpectedSize(distinct); 878 for (int i = 0; i < distinct; i++) { 879 /* 880 * requireNonNull is safe because we ensure that the first `distinct` elements have been 881 * populated. 882 */ 883 delegate.add(requireNonNull(dedupedElements[i])); 884 } 885 } 886 887 @Override 888 SetBuilderImpl<E> add(E e) { 889 checkNotNull(e); 890 if (delegate.add(e)) { 891 addDedupedElement(e); 892 } 893 return this; 894 } 895 896 @Override 897 SetBuilderImpl<E> copy() { 898 return new JdkBackedSetBuilderImpl<>(this); 899 } 900 901 @Override 902 ImmutableSet<E> build() { 903 switch (distinct) { 904 case 0: 905 return of(); 906 case 1: 907 /* 908 * requireNonNull is safe because we ensure that the first `distinct` elements have been 909 * populated. 910 */ 911 return of(requireNonNull(dedupedElements[0])); 912 default: 913 return new JdkBackedImmutableSet<E>( 914 delegate, ImmutableList.asImmutableList(dedupedElements, distinct)); 915 } 916 } 917 } 918 }