001/* 002 * Copyright (C) 2007 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.collect; 018 019import static com.google.common.base.Preconditions.checkArgument; 020import static com.google.common.base.Preconditions.checkNotNull; 021import static com.google.common.collect.CollectPreconditions.checkNonnegative; 022import static com.google.common.collect.ImmutableList.asImmutableList; 023import static com.google.common.collect.Sets.equalsImpl; 024import static com.google.common.collect.Sets.hashCodeImpl; 025import static com.google.common.collect.Sets.newHashSetWithExpectedSize; 026import static com.google.common.math.IntMath.sqrt; 027import static java.lang.Math.max; 028import static java.util.Objects.requireNonNull; 029 030import com.google.common.annotations.GwtCompatible; 031import com.google.common.annotations.GwtIncompatible; 032import com.google.common.annotations.J2ktIncompatible; 033import com.google.common.annotations.VisibleForTesting; 034import com.google.common.math.IntMath; 035import com.google.common.primitives.Ints; 036import com.google.errorprone.annotations.CanIgnoreReturnValue; 037import com.google.errorprone.annotations.concurrent.LazyInit; 038import com.google.j2objc.annotations.RetainedWith; 039import java.io.InvalidObjectException; 040import java.io.ObjectInputStream; 041import java.io.Serializable; 042import java.math.RoundingMode; 043import java.util.Arrays; 044import java.util.Collection; 045import java.util.Collections; 046import java.util.EnumSet; 047import java.util.Iterator; 048import java.util.Set; 049import java.util.SortedSet; 050import java.util.Spliterator; 051import java.util.stream.Collector; 052import org.jspecify.annotations.Nullable; 053 054/** 055 * A {@link Set} whose contents will never change, with many other important properties detailed at 056 * {@link ImmutableCollection}. 057 * 058 * @since 2.0 059 */ 060@GwtCompatible 061@SuppressWarnings("serial") // we're overriding default serialization 062public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements Set<E> { 063 static final int SPLITERATOR_CHARACTERISTICS = 064 ImmutableCollection.SPLITERATOR_CHARACTERISTICS | Spliterator.DISTINCT; 065 066 /** 067 * Returns a {@code Collector} that accumulates the input elements into a new {@code 068 * ImmutableSet}. Elements appear in the resulting set in the encounter order of the stream; if 069 * the stream contains duplicates (according to {@link Object#equals(Object)}), only the first 070 * duplicate in encounter order will appear in the result. 071 * 072 * @since 21.0 073 */ 074 public static <E> Collector<E, ?, ImmutableSet<E>> toImmutableSet() { 075 return CollectCollectors.toImmutableSet(); 076 } 077 078 /** 079 * Returns the empty immutable set. Preferred over {@link Collections#emptySet} for code 080 * consistency, and because the return type conveys the immutability guarantee. 081 * 082 * <p><b>Performance note:</b> the instance returned is a singleton. 083 */ 084 @SuppressWarnings({"unchecked"}) // fully variant implementation (never actually produces any Es) 085 public static <E> ImmutableSet<E> of() { 086 return (ImmutableSet<E>) RegularImmutableSet.EMPTY; 087 } 088 089 /** 090 * Returns an immutable set containing the given element. Preferred over {@link 091 * Collections#singleton} for code consistency, {@code null} rejection, and because the return 092 * type conveys the immutability guarantee. 093 */ 094 public static <E> ImmutableSet<E> of(E e1) { 095 return new SingletonImmutableSet<>(e1); 096 } 097 098 /* 099 * TODO(b/315526394): Skip the Builder entirely for the of(...) methods, since we don't need to 100 * worry that we might trigger the fallback to the JDK-backed implementation? (The varargs one 101 * _could_, so we could keep it as it is. Or we could convince ourselves that hash flooding is 102 * unlikely in practice there, too.) 103 */ 104 105 /** 106 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 107 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 108 * the first are ignored. 109 */ 110 public static <E> ImmutableSet<E> of(E e1, E e2) { 111 return new RegularSetBuilderImpl<E>(2).add(e1).add(e2).review().build(); 112 } 113 114 /** 115 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 116 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 117 * the first are ignored. 118 */ 119 public static <E> ImmutableSet<E> of(E e1, E e2, E e3) { 120 return new RegularSetBuilderImpl<E>(3).add(e1).add(e2).add(e3).review().build(); 121 } 122 123 /** 124 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 125 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 126 * the first are ignored. 127 */ 128 public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4) { 129 return new RegularSetBuilderImpl<E>(4).add(e1).add(e2).add(e3).add(e4).review().build(); 130 } 131 132 /** 133 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 134 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 135 * the first are ignored. 136 */ 137 public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5) { 138 return new RegularSetBuilderImpl<E>(5).add(e1).add(e2).add(e3).add(e4).add(e5).review().build(); 139 } 140 141 /** 142 * Returns an immutable set containing the given elements, minus duplicates, in the order each was 143 * first specified. That is, if multiple elements are {@linkplain Object#equals equal}, all except 144 * the first are ignored. 145 * 146 * <p>The array {@code others} must not be longer than {@code Integer.MAX_VALUE - 6}. 147 * 148 * @since 3.0 (source-compatible since 2.0) 149 */ 150 @SafeVarargs // For Eclipse. For internal javac we have disabled this pointless type of warning. 151 public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) { 152 checkArgument( 153 others.length <= Integer.MAX_VALUE - 6, "the total number of elements must fit in an int"); 154 SetBuilderImpl<E> builder = new RegularSetBuilderImpl<>(6 + others.length); 155 builder = builder.add(e1).add(e2).add(e3).add(e4).add(e5).add(e6); 156 for (int i = 0; i < others.length; i++) { 157 builder = builder.add(others[i]); 158 } 159 return builder.review().build(); 160 } 161 162 /** 163 * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order 164 * each appears first in the source collection. 165 * 166 * <p><b>Performance note:</b> This method will sometimes recognize that the actual copy operation 167 * is unnecessary; for example, {@code copyOf(copyOf(anArrayList))} will copy the data only once. 168 * This reduces the expense of habitually making defensive copies at API boundaries. However, the 169 * precise conditions for skipping the copy operation are undefined. 170 * 171 * @throws NullPointerException if any of {@code elements} is null 172 * @since 7.0 (source-compatible since 2.0) 173 */ 174 public static <E> ImmutableSet<E> copyOf(Collection<? extends E> elements) { 175 /* 176 * TODO(lowasser): consider checking for ImmutableAsList here 177 * TODO(lowasser): consider checking for Multiset here 178 */ 179 // Don't refer to ImmutableSortedSet by name so it won't pull in all that code 180 if (elements instanceof ImmutableSet && !(elements instanceof SortedSet)) { 181 @SuppressWarnings("unchecked") // all supported methods are covariant 182 ImmutableSet<E> set = (ImmutableSet<E>) elements; 183 if (!set.isPartialView()) { 184 return set; 185 } 186 } else if (elements instanceof EnumSet) { 187 EnumSet<?> clone = ((EnumSet<?>) elements).clone(); 188 ImmutableSet<?> untypedResult = ImmutableEnumSet.asImmutable(clone); 189 /* 190 * The result has the same type argument we started with. We just couldn't express EnumSet<E> 191 * or ImmutableEnumSet<E> along the way because our own <E> isn't <E extends Enum<E>>. 192 * 193 * We are also performing a safe covariant cast to change <? extends E> to <E>. 194 */ 195 @SuppressWarnings("unchecked") 196 ImmutableSet<E> result = (ImmutableSet<E>) untypedResult; 197 return result; 198 } 199 200 if (elements.isEmpty()) { 201 // We avoid allocating anything. 202 return of(); 203 } 204 // Collection<E>.toArray() is required to contain only E instances, and all we do is read them. 205 // TODO(cpovirk): Consider using Object[] anyway. 206 @SuppressWarnings("unchecked") 207 E[] array = (E[]) elements.toArray(); 208 /* 209 * For a Set, we guess that it contains no duplicates. That's just a guess for purpose of 210 * sizing; if the Set uses different equality semantics, it might contain duplicates according 211 * to equals(), and we will deduplicate those properly, albeit at some cost in allocations. 212 */ 213 int expectedSize = 214 elements instanceof Set ? array.length : estimatedSizeForUnknownDuplication(array.length); 215 return fromArrayWithExpectedSize(array, expectedSize); 216 } 217 218 /** 219 * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order 220 * each appears first in the source iterable. This method iterates over {@code elements} only 221 * once. 222 * 223 * <p><b>Performance note:</b> This method will sometimes recognize that the actual copy operation 224 * is unnecessary; for example, {@code copyOf(copyOf(anArrayList))} should copy the data only 225 * once. This reduces the expense of habitually making defensive copies at API boundaries. 226 * However, the precise conditions for skipping the copy operation are undefined. 227 * 228 * @throws NullPointerException if any of {@code elements} is null 229 */ 230 public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) { 231 return (elements instanceof Collection) 232 ? copyOf((Collection<? extends E>) elements) 233 : copyOf(elements.iterator()); 234 } 235 236 /** 237 * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order 238 * each appears first in the source iterator. 239 * 240 * @throws NullPointerException if any of {@code elements} is null 241 */ 242 public static <E> ImmutableSet<E> copyOf(Iterator<? extends E> elements) { 243 // We special-case for 0 or 1 elements, but anything further is madness. 244 if (!elements.hasNext()) { 245 return of(); 246 } 247 E first = elements.next(); 248 if (!elements.hasNext()) { 249 return of(first); 250 } else { 251 return new ImmutableSet.Builder<E>().add(first).addAll(elements).build(); 252 } 253 } 254 255 /** 256 * Returns an immutable set containing each of {@code elements}, minus duplicates, in the order 257 * each appears first in the source array. 258 * 259 * @throws NullPointerException if any of {@code elements} is null 260 * @since 3.0 261 */ 262 public static <E> ImmutableSet<E> copyOf(E[] elements) { 263 return fromArrayWithExpectedSize(elements, estimatedSizeForUnknownDuplication(elements.length)); 264 } 265 266 private static <E> ImmutableSet<E> fromArrayWithExpectedSize(E[] elements, int expectedSize) { 267 switch (elements.length) { 268 case 0: 269 return of(); 270 case 1: 271 return of(elements[0]); 272 default: 273 SetBuilderImpl<E> builder = new RegularSetBuilderImpl<>(expectedSize); 274 for (int i = 0; i < elements.length; i++) { 275 builder = builder.add(elements[i]); 276 } 277 return builder.review().build(); 278 } 279 } 280 281 ImmutableSet() {} 282 283 /** Returns {@code true} if the {@code hashCode()} method runs quickly. */ 284 boolean isHashCodeFast() { 285 return false; 286 } 287 288 @Override 289 public boolean equals(@Nullable Object object) { 290 if (object == this) { 291 return true; 292 } 293 if (object instanceof ImmutableSet 294 && isHashCodeFast() 295 && ((ImmutableSet<?>) object).isHashCodeFast() 296 && hashCode() != object.hashCode()) { 297 return false; 298 } 299 return equalsImpl(this, object); 300 } 301 302 @Override 303 public int hashCode() { 304 return hashCodeImpl(this); 305 } 306 307 // This declaration is needed to make Set.iterator() and 308 // ImmutableCollection.iterator() consistent. 309 @Override 310 public abstract UnmodifiableIterator<E> iterator(); 311 312 abstract static class CachingAsList<E> extends ImmutableSet<E> { 313 @LazyInit @RetainedWith private transient @Nullable ImmutableList<E> asList; 314 315 @Override 316 public ImmutableList<E> asList() { 317 ImmutableList<E> result = asList; 318 if (result == null) { 319 result = asList = createAsList(); 320 } 321 return result; 322 } 323 324 ImmutableList<E> createAsList() { 325 return new RegularImmutableAsList<>(this, toArray()); 326 } 327 328 // redeclare to help optimizers with b/310253115 329 @SuppressWarnings("RedundantOverride") 330 @Override 331 @J2ktIncompatible 332 @GwtIncompatible 333 Object writeReplace() { 334 return super.writeReplace(); 335 } 336 } 337 338 /* 339 * This class is used to serialize all ImmutableSet instances, except for 340 * ImmutableEnumSet/ImmutableSortedSet, regardless of implementation type. It 341 * captures their "logical contents" and they are reconstructed using public 342 * static factories. This is necessary to ensure that the existence of a 343 * particular implementation type is an implementation detail. 344 */ 345 @J2ktIncompatible // serialization 346 private static final class SerializedForm implements Serializable { 347 final Object[] elements; 348 349 SerializedForm(Object[] elements) { 350 this.elements = elements; 351 } 352 353 Object readResolve() { 354 return copyOf(elements); 355 } 356 357 @GwtIncompatible private static final long serialVersionUID = 0; 358 } 359 360 @Override 361 @J2ktIncompatible 362 Object writeReplace() { 363 return new SerializedForm(toArray()); 364 } 365 366 @J2ktIncompatible 367 private void readObject(ObjectInputStream stream) throws InvalidObjectException { 368 throw new InvalidObjectException("Use SerializedForm"); 369 } 370 371 /** 372 * Returns a new builder. The generated builder is equivalent to the builder created by the {@link 373 * Builder} constructor. 374 */ 375 public static <E> Builder<E> builder() { 376 return new Builder<>(); 377 } 378 379 /** 380 * Returns a new builder, expecting the specified number of distinct elements to be added. 381 * 382 * <p>If {@code expectedSize} is exactly the number of distinct elements added to the builder 383 * before {@link Builder#build} is called, the builder is likely to perform better than an unsized 384 * {@link #builder()} would have. 385 * 386 * <p>It is not specified if any performance benefits apply if {@code expectedSize} is close to, 387 * but not exactly, the number of distinct elements added to the builder. 388 * 389 * @since 23.1 390 */ 391 public static <E> Builder<E> builderWithExpectedSize(int expectedSize) { 392 checkNonnegative(expectedSize, "expectedSize"); 393 return new Builder<>(expectedSize); 394 } 395 396 /** 397 * A builder for creating {@code ImmutableSet} instances. Example: 398 * 399 * {@snippet : 400 * static final ImmutableSet<Color> GOOGLE_COLORS = 401 * ImmutableSet.<Color>builder() 402 * .addAll(WEBSAFE_COLORS) 403 * .add(new Color(0, 191, 255)) 404 * .build(); 405 * } 406 * 407 * <p>Elements appear in the resulting set in the same order they were first added to the builder. 408 * 409 * <p>Building does not change the state of the builder, so it is still possible to add more 410 * elements and to build again. 411 * 412 * @since 2.0 413 */ 414 public static class Builder<E> extends ImmutableCollection.Builder<E> { 415 /* 416 * `impl` is null only for instances of the subclass, ImmutableSortedSet.Builder. That subclass 417 * overrides all the methods that access it here. Thus, all the methods here can safely assume 418 * that this field is non-null. 419 */ 420 private @Nullable SetBuilderImpl<E> impl; 421 boolean forceCopy; 422 423 /** 424 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 425 * ImmutableSet#builder}. 426 */ 427 public Builder() { 428 this(0); 429 } 430 431 Builder(int capacity) { 432 if (capacity > 0) { 433 impl = new RegularSetBuilderImpl<>(capacity); 434 } else { 435 impl = EmptySetBuilderImpl.instance(); 436 } 437 } 438 439 Builder(@SuppressWarnings("unused") boolean subclass) { 440 this.impl = null; // unused 441 } 442 443 @VisibleForTesting 444 void forceJdk() { 445 requireNonNull(impl); // see the comment on the field 446 this.impl = new JdkBackedSetBuilderImpl<>(impl); 447 } 448 449 final void copyIfNecessary() { 450 if (forceCopy) { 451 copy(); 452 forceCopy = false; 453 } 454 } 455 456 void copy() { 457 requireNonNull(impl); // see the comment on the field 458 impl = impl.copy(); 459 } 460 461 @Override 462 @CanIgnoreReturnValue 463 public Builder<E> add(E element) { 464 requireNonNull(impl); // see the comment on the field 465 checkNotNull(element); 466 copyIfNecessary(); 467 impl = impl.add(element); 468 return this; 469 } 470 471 @Override 472 @CanIgnoreReturnValue 473 public Builder<E> add(E... elements) { 474 super.add(elements); 475 return this; 476 } 477 478 /** 479 * Adds each element of {@code elements} to the {@code ImmutableSet}, ignoring duplicate 480 * elements (only the first duplicate element is added). 481 * 482 * @param elements the elements to add 483 * @return this {@code Builder} object 484 * @throws NullPointerException if {@code elements} is null or contains a null element 485 */ 486 @Override 487 @CanIgnoreReturnValue 488 public Builder<E> addAll(Iterable<? extends E> elements) { 489 super.addAll(elements); 490 return this; 491 } 492 493 @Override 494 @CanIgnoreReturnValue 495 public Builder<E> addAll(Iterator<? extends E> elements) { 496 super.addAll(elements); 497 return this; 498 } 499 500 @CanIgnoreReturnValue 501 Builder<E> combine(Builder<E> other) { 502 requireNonNull(impl); 503 requireNonNull(other.impl); 504 /* 505 * For discussion of requireNonNull, see the comment on the field. 506 * 507 * (And I don't believe there's any situation in which we call x.combine(y) when x is a plain 508 * ImmutableSet.Builder but y is an ImmutableSortedSet.Builder (or vice versa). Certainly 509 * ImmutableSortedSet.Builder.combine() is written as if its argument will never be a plain 510 * ImmutableSet.Builder: It casts immediately to ImmutableSortedSet.Builder.) 511 */ 512 copyIfNecessary(); 513 this.impl = this.impl.combine(other.impl); 514 return this; 515 } 516 517 @Override 518 public ImmutableSet<E> build() { 519 requireNonNull(impl); // see the comment on the field 520 forceCopy = true; 521 impl = impl.review(); 522 return impl.build(); 523 } 524 } 525 526 /** Swappable internal implementation of an ImmutableSet.Builder. */ 527 private abstract static class SetBuilderImpl<E> { 528 // The first `distinct` elements are non-null. 529 // Since we can never access null elements, we don't mark this nullable. 530 E[] dedupedElements; 531 int distinct; 532 533 @SuppressWarnings("unchecked") 534 SetBuilderImpl(int expectedCapacity) { 535 this.dedupedElements = (E[]) new Object[expectedCapacity]; 536 this.distinct = 0; 537 } 538 539 /** Initializes this SetBuilderImpl with a copy of the deduped elements array from toCopy. */ 540 SetBuilderImpl(SetBuilderImpl<E> toCopy) { 541 this.dedupedElements = Arrays.copyOf(toCopy.dedupedElements, toCopy.dedupedElements.length); 542 this.distinct = toCopy.distinct; 543 } 544 545 /** 546 * Resizes internal data structures if necessary to store the specified number of distinct 547 * elements. 548 */ 549 private void ensureCapacity(int minCapacity) { 550 if (minCapacity > dedupedElements.length) { 551 int newCapacity = 552 ImmutableCollection.Builder.expandedCapacity(dedupedElements.length, minCapacity); 553 dedupedElements = Arrays.copyOf(dedupedElements, newCapacity); 554 } 555 } 556 557 /** Adds e to the insertion-order array of deduplicated elements. Calls ensureCapacity. */ 558 final void addDedupedElement(E e) { 559 ensureCapacity(distinct + 1); 560 dedupedElements[distinct++] = e; 561 } 562 563 /** 564 * Adds e to this SetBuilderImpl, returning the updated result. Only use the returned 565 * SetBuilderImpl, since we may switch implementations if e.g. hash flooding is detected. 566 */ 567 abstract SetBuilderImpl<E> add(E e); 568 569 /** Adds all the elements from the specified SetBuilderImpl to this SetBuilderImpl. */ 570 final SetBuilderImpl<E> combine(SetBuilderImpl<E> other) { 571 SetBuilderImpl<E> result = this; 572 for (int i = 0; i < other.distinct; i++) { 573 /* 574 * requireNonNull is safe because we ensure that the first `distinct` elements have been 575 * populated. 576 */ 577 result = result.add(requireNonNull(other.dedupedElements[i])); 578 } 579 return result; 580 } 581 582 /** 583 * Creates a new copy of this SetBuilderImpl. Modifications to that SetBuilderImpl will not 584 * affect this SetBuilderImpl or sets constructed from this SetBuilderImpl via build(). 585 */ 586 abstract SetBuilderImpl<E> copy(); 587 588 /** 589 * Call this before build(). Does a final check on the internal data structures, e.g. shrinking 590 * unnecessarily large structures or detecting previously unnoticed hash flooding. 591 */ 592 SetBuilderImpl<E> review() { 593 return this; 594 } 595 596 abstract ImmutableSet<E> build(); 597 } 598 599 private static final class EmptySetBuilderImpl<E> extends SetBuilderImpl<E> { 600 private static final EmptySetBuilderImpl<Object> INSTANCE = new EmptySetBuilderImpl<>(); 601 602 @SuppressWarnings("unchecked") 603 static <E> SetBuilderImpl<E> instance() { 604 return (SetBuilderImpl<E>) INSTANCE; 605 } 606 607 private EmptySetBuilderImpl() { 608 super(0); 609 } 610 611 @Override 612 SetBuilderImpl<E> add(E e) { 613 return new RegularSetBuilderImpl<E>(Builder.DEFAULT_INITIAL_CAPACITY).add(e); 614 } 615 616 @Override 617 SetBuilderImpl<E> copy() { 618 return this; 619 } 620 621 @Override 622 ImmutableSet<E> build() { 623 return of(); 624 } 625 } 626 627 // We use power-of-2 tables, and this is the highest int that's a power of 2 628 static final int MAX_TABLE_SIZE = Ints.MAX_POWER_OF_TWO; 629 630 // Represents how tightly we can pack things, as a maximum. 631 private static final double DESIRED_LOAD_FACTOR = 0.7; 632 633 // If the set has this many elements, it will "max out" the table size 634 private static final int CUTOFF = (int) (MAX_TABLE_SIZE * DESIRED_LOAD_FACTOR); 635 636 /** 637 * Returns an array size suitable for the backing array of a hash table that uses open addressing 638 * with linear probing in its implementation. The returned size is the smallest power of two that 639 * can hold setSize elements with the desired load factor. Always returns at least setSize + 2. 640 */ 641 // TODO(cpovirk): Move to Hashing or something, since it's used elsewhere in the Android version. 642 static int chooseTableSize(int setSize) { 643 setSize = max(setSize, 2); 644 // Correct the size for open addressing to match desired load factor. 645 if (setSize < CUTOFF) { 646 // Round up to the next highest power of 2. 647 int tableSize = Integer.highestOneBit(setSize - 1) << 1; 648 while (tableSize * DESIRED_LOAD_FACTOR < setSize) { 649 tableSize <<= 1; 650 } 651 return tableSize; 652 } 653 654 // The table can't be completely full or we'll get infinite reprobes 655 checkArgument(setSize < MAX_TABLE_SIZE, "collection too large"); 656 return MAX_TABLE_SIZE; 657 } 658 659 /** 660 * Default implementation of the guts of ImmutableSet.Builder, creating an open-addressed hash 661 * table and deduplicating elements as they come, so it only allocates O(max(distinct, 662 * expectedCapacity)) rather than O(calls to add). 663 * 664 * <p>This implementation attempts to detect hash flooding, and if it's identified, falls back to 665 * JdkBackedSetBuilderImpl. 666 */ 667 private static final class RegularSetBuilderImpl<E> extends SetBuilderImpl<E> { 668 // null until at least two elements are present 669 private @Nullable Object @Nullable [] hashTable; 670 private int maxRunBeforeFallback; 671 private int expandTableThreshold; 672 private int hashCode; 673 674 RegularSetBuilderImpl(int expectedCapacity) { 675 super(expectedCapacity); 676 this.hashTable = null; 677 this.maxRunBeforeFallback = 0; 678 this.expandTableThreshold = 0; 679 } 680 681 RegularSetBuilderImpl(RegularSetBuilderImpl<E> toCopy) { 682 super(toCopy); 683 this.hashTable = (toCopy.hashTable == null) ? null : toCopy.hashTable.clone(); 684 this.maxRunBeforeFallback = toCopy.maxRunBeforeFallback; 685 this.expandTableThreshold = toCopy.expandTableThreshold; 686 this.hashCode = toCopy.hashCode; 687 } 688 689 @Override 690 SetBuilderImpl<E> add(E e) { 691 checkNotNull(e); 692 if (hashTable == null) { 693 if (distinct == 0) { 694 addDedupedElement(e); 695 return this; 696 } else { 697 ensureTableCapacity(dedupedElements.length); 698 E elem = dedupedElements[0]; 699 distinct--; 700 return insertInHashTable(elem).add(e); 701 } 702 } 703 return insertInHashTable(e); 704 } 705 706 private SetBuilderImpl<E> insertInHashTable(E e) { 707 requireNonNull(hashTable); 708 int eHash = e.hashCode(); 709 int i0 = Hashing.smear(eHash); 710 int mask = hashTable.length - 1; 711 for (int i = i0; i - i0 < maxRunBeforeFallback; i++) { 712 int index = i & mask; 713 Object tableEntry = hashTable[index]; 714 if (tableEntry == null) { 715 addDedupedElement(e); 716 hashTable[index] = e; 717 hashCode += eHash; 718 ensureTableCapacity(distinct); // rebuilds table if necessary 719 return this; 720 } else if (tableEntry.equals(e)) { // not a new element, ignore 721 return this; 722 } 723 } 724 // we fell out of the loop due to a long run; fall back to JDK impl 725 return new JdkBackedSetBuilderImpl<E>(this).add(e); 726 } 727 728 @Override 729 SetBuilderImpl<E> copy() { 730 return new RegularSetBuilderImpl<>(this); 731 } 732 733 @Override 734 SetBuilderImpl<E> review() { 735 if (hashTable == null) { 736 return this; 737 } 738 int targetTableSize = chooseTableSize(distinct); 739 if (targetTableSize * 2 < hashTable.length) { 740 hashTable = rebuildHashTable(targetTableSize, dedupedElements, distinct); 741 maxRunBeforeFallback = maxRunBeforeFallback(targetTableSize); 742 expandTableThreshold = (int) (DESIRED_LOAD_FACTOR * targetTableSize); 743 } 744 return hashFloodingDetected(hashTable) ? new JdkBackedSetBuilderImpl<E>(this) : this; 745 } 746 747 @Override 748 ImmutableSet<E> build() { 749 switch (distinct) { 750 case 0: 751 return of(); 752 case 1: 753 /* 754 * requireNonNull is safe because we ensure that the first `distinct` elements have been 755 * populated. 756 */ 757 return of(requireNonNull(dedupedElements[0])); 758 default: 759 /* 760 * The suppression is safe because we ensure that the first `distinct` elements have been 761 * populated. 762 */ 763 @SuppressWarnings("nullness") 764 Object[] elements = 765 (distinct == dedupedElements.length) 766 ? dedupedElements 767 : Arrays.copyOf(dedupedElements, distinct); 768 return new RegularImmutableSet<>( 769 elements, hashCode, requireNonNull(hashTable), hashTable.length - 1); 770 } 771 } 772 773 /** Builds a new open-addressed hash table from the first n objects in elements. */ 774 static @Nullable Object[] rebuildHashTable(int newTableSize, Object[] elements, int n) { 775 @Nullable Object[] hashTable = new @Nullable Object[newTableSize]; 776 int mask = hashTable.length - 1; 777 for (int i = 0; i < n; i++) { 778 // requireNonNull is safe because we ensure that the first n elements have been populated. 779 Object e = requireNonNull(elements[i]); 780 int j0 = Hashing.smear(e.hashCode()); 781 for (int j = j0; ; j++) { 782 int index = j & mask; 783 if (hashTable[index] == null) { 784 hashTable[index] = e; 785 break; 786 } 787 } 788 } 789 return hashTable; 790 } 791 792 void ensureTableCapacity(int minCapacity) { 793 int newTableSize; 794 if (hashTable == null) { 795 newTableSize = chooseTableSize(minCapacity); 796 hashTable = new Object[newTableSize]; 797 } else if (minCapacity > expandTableThreshold && hashTable.length < MAX_TABLE_SIZE) { 798 newTableSize = hashTable.length * 2; 799 hashTable = rebuildHashTable(newTableSize, dedupedElements, distinct); 800 } else { 801 return; 802 } 803 maxRunBeforeFallback = maxRunBeforeFallback(newTableSize); 804 expandTableThreshold = (int) (DESIRED_LOAD_FACTOR * newTableSize); 805 } 806 807 /** 808 * We attempt to detect deliberate hash flooding attempts. If one is detected, we fall back to a 809 * wrapper around j.u.HashSet, which has built-in flooding protection. MAX_RUN_MULTIPLIER was 810 * determined experimentally to match our desired probability of false positives. 811 */ 812 // NB: yes, this is surprisingly high, but that's what the experiments said was necessary 813 // Raising this number slows the worst-case contains behavior, speeds up hashFloodingDetected, 814 // and reduces the false-positive probability. 815 static final int MAX_RUN_MULTIPLIER = 13; 816 817 /** 818 * Checks the whole hash table for poor hash distribution. Takes O(n) in the worst case, O(n / 819 * log n) on average. 820 * 821 * <p>The online hash flooding detecting in RegularSetBuilderImpl.add can detect e.g. many 822 * exactly matching hash codes, which would cause construction to take O(n^2), but can't detect 823 * e.g. hash codes adversarially designed to go into ascending table locations, which keeps 824 * construction O(n) (as desired) but then can have O(n) queries later. 825 * 826 * <p>If this returns false, then no query can take more than O(log n). 827 * 828 * <p>Note that for a RegularImmutableSet with elements with truly random hash codes, contains 829 * operations take expected O(1) time but with high probability take O(log n) for at least some 830 * element. (https://en.wikipedia.org/wiki/Linear_probing#Analysis) 831 * 832 * <p>This method may return {@code true} even on truly random input, but {@code 833 * ImmutableSetTest} tests that the probability of that is low. 834 */ 835 static boolean hashFloodingDetected(@Nullable Object[] hashTable) { 836 int maxRunBeforeFallback = maxRunBeforeFallback(hashTable.length); 837 int mask = hashTable.length - 1; 838 839 // Invariant: all elements at indices in [knownRunStart, knownRunEnd) are nonnull. 840 // If knownRunStart == knownRunEnd, this is vacuously true. 841 // When knownRunEnd exceeds hashTable.length, it "wraps", detecting runs around the end 842 // of the table. 843 int knownRunStart = 0; 844 int knownRunEnd = 0; 845 846 outerLoop: 847 while (knownRunStart < hashTable.length) { 848 if (knownRunStart == knownRunEnd && hashTable[knownRunStart] == null) { 849 if (hashTable[(knownRunStart + maxRunBeforeFallback - 1) & mask] == null) { 850 // There are only maxRunBeforeFallback - 1 elements between here and there, 851 // so even if they were all nonnull, we wouldn't detect a hash flood. Therefore, 852 // we can skip them all. 853 knownRunStart += maxRunBeforeFallback; 854 } else { 855 knownRunStart++; // the only case in which maxRunEnd doesn't increase by mRBF 856 // happens about f * (1-f) for f = DESIRED_LOAD_FACTOR, so around 21% of the time 857 } 858 knownRunEnd = knownRunStart; 859 } else { 860 for (int j = knownRunStart + maxRunBeforeFallback - 1; j >= knownRunEnd; j--) { 861 if (hashTable[j & mask] == null) { 862 knownRunEnd = knownRunStart + maxRunBeforeFallback; 863 knownRunStart = j + 1; 864 continue outerLoop; 865 } 866 } 867 return true; 868 } 869 } 870 return false; 871 } 872 873 /** 874 * If more than this many consecutive positions are filled in a table of the specified size, 875 * report probable hash flooding. ({@link #hashFloodingDetected} may also report hash flooding 876 * if fewer consecutive positions are filled; see that method for details.) 877 */ 878 static int maxRunBeforeFallback(int tableSize) { 879 return MAX_RUN_MULTIPLIER * IntMath.log2(tableSize, RoundingMode.UNNECESSARY); 880 } 881 } 882 883 /** 884 * SetBuilderImpl version that uses a JDK HashSet, which has built in hash flooding protection. 885 */ 886 private static final class JdkBackedSetBuilderImpl<E> extends SetBuilderImpl<E> { 887 private final Set<Object> delegate; 888 889 JdkBackedSetBuilderImpl(SetBuilderImpl<E> toCopy) { 890 super(toCopy); // initializes dedupedElements and distinct 891 delegate = newHashSetWithExpectedSize(distinct); 892 for (int i = 0; i < distinct; i++) { 893 /* 894 * requireNonNull is safe because we ensure that the first `distinct` elements have been 895 * populated. 896 */ 897 delegate.add(requireNonNull(dedupedElements[i])); 898 } 899 } 900 901 @Override 902 SetBuilderImpl<E> add(E e) { 903 checkNotNull(e); 904 if (delegate.add(e)) { 905 addDedupedElement(e); 906 } 907 return this; 908 } 909 910 @Override 911 SetBuilderImpl<E> copy() { 912 return new JdkBackedSetBuilderImpl<>(this); 913 } 914 915 @Override 916 ImmutableSet<E> build() { 917 switch (distinct) { 918 case 0: 919 return of(); 920 case 1: 921 /* 922 * requireNonNull is safe because we ensure that the first `distinct` elements have been 923 * populated. 924 */ 925 return of(requireNonNull(dedupedElements[0])); 926 default: 927 return new JdkBackedImmutableSet<>(delegate, asImmutableList(dedupedElements, distinct)); 928 } 929 } 930 } 931 932 private static int estimatedSizeForUnknownDuplication(int inputElementsIncludingAnyDuplicates) { 933 if (inputElementsIncludingAnyDuplicates 934 < ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY) { 935 return inputElementsIncludingAnyDuplicates; 936 } 937 // Guess the size is "halfway between" all duplicates and no duplicates, on a log scale. 938 return max( 939 ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY, 940 sqrt(inputElementsIncludingAnyDuplicates, RoundingMode.CEILING)); 941 } 942 943 @GwtIncompatible @J2ktIncompatible private static final long serialVersionUID = 0xcafebabe; 944}