001/* 002 * Copyright (C) 2011 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the 010 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 011 * express or implied. See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014 015package com.google.common.collect; 016 017import static com.google.common.base.Preconditions.checkArgument; 018import static com.google.common.base.Preconditions.checkNotNull; 019 020import com.google.common.annotations.GwtIncompatible; 021import com.google.common.annotations.J2ktIncompatible; 022import com.google.common.annotations.VisibleForTesting; 023import com.google.common.math.IntMath; 024import com.google.errorprone.annotations.CanIgnoreReturnValue; 025import com.google.errorprone.annotations.DoNotCall; 026import com.google.errorprone.annotations.concurrent.LazyInit; 027import java.io.InvalidObjectException; 028import java.io.ObjectInputStream; 029import java.io.Serializable; 030import java.util.Arrays; 031import java.util.Collection; 032import java.util.Collections; 033import java.util.Comparator; 034import java.util.Iterator; 035import java.util.List; 036import java.util.function.Function; 037import java.util.function.ToIntFunction; 038import java.util.stream.Collector; 039import org.jspecify.annotations.Nullable; 040 041/** 042 * A {@link SortedMultiset} whose contents will never change, with many other important properties 043 * detailed at {@link ImmutableCollection}. 044 * 045 * <p><b>Warning:</b> as with any sorted collection, you are strongly advised not to use a {@link 046 * Comparator} or {@link Comparable} type whose comparison behavior is <i>inconsistent with 047 * equals</i>. That is, {@code a.compareTo(b)} or {@code comparator.compare(a, b)} should equal zero 048 * <i>if and only if</i> {@code a.equals(b)}. If this advice is not followed, the resulting 049 * collection will not correctly obey its specification. 050 * 051 * <p>See the Guava User Guide article on <a href= 052 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained">immutable collections</a>. 053 * 054 * @author Louis Wasserman 055 * @since 12.0 056 */ 057@GwtIncompatible // hasn't been tested yet 058public abstract class ImmutableSortedMultiset<E> extends ImmutableMultiset<E> 059 implements SortedMultiset<E> { 060 // TODO(lowasser): GWT compatibility 061 062 /** 063 * Returns a {@code Collector} that accumulates the input elements into a new {@code 064 * ImmutableMultiset}. Elements are sorted by the specified comparator. 065 * 066 * <p><b>Warning:</b> {@code comparator} should be <i>consistent with {@code equals}</i> as 067 * explained in the {@link Comparator} documentation. 068 * 069 * @since 33.2.0 (available since 21.0 in guava-jre) 070 */ 071 @SuppressWarnings("Java7ApiChecker") 072 @IgnoreJRERequirement // Users will use this only if they're already using streams. 073 public static <E> Collector<E, ?, ImmutableSortedMultiset<E>> toImmutableSortedMultiset( 074 Comparator<? super E> comparator) { 075 return toImmutableSortedMultiset(comparator, Function.identity(), e -> 1); 076 } 077 078 /** 079 * Returns a {@code Collector} that accumulates elements into an {@code ImmutableSortedMultiset} 080 * whose elements are the result of applying {@code elementFunction} to the inputs, with counts 081 * equal to the result of applying {@code countFunction} to the inputs. 082 * 083 * <p>If the mapped elements contain duplicates (according to {@code comparator}), the first 084 * occurrence in encounter order appears in the resulting multiset, with count equal to the sum of 085 * the outputs of {@code countFunction.applyAsInt(t)} for each {@code t} mapped to that element. 086 * 087 * @since 33.2.0 (available since 22.0 in guava-jre) 088 */ 089 @SuppressWarnings("Java7ApiChecker") 090 @IgnoreJRERequirement // Users will use this only if they're already using streams. 091 public static <T extends @Nullable Object, E> 092 Collector<T, ?, ImmutableSortedMultiset<E>> toImmutableSortedMultiset( 093 Comparator<? super E> comparator, 094 Function<? super T, ? extends E> elementFunction, 095 ToIntFunction<? super T> countFunction) { 096 checkNotNull(comparator); 097 checkNotNull(elementFunction); 098 checkNotNull(countFunction); 099 return Collector.of( 100 () -> TreeMultiset.create(comparator), 101 (multiset, t) -> mapAndAdd(t, multiset, elementFunction, countFunction), 102 (multiset1, multiset2) -> { 103 multiset1.addAll(multiset2); 104 return multiset1; 105 }, 106 (Multiset<E> multiset) -> copyOfSortedEntries(comparator, multiset.entrySet())); 107 } 108 109 @SuppressWarnings("Java7ApiChecker") 110 @IgnoreJRERequirement // helper for toImmutableSortedMultiset 111 /* 112 * If we make these calls inline inside toImmutableSortedMultiset, we get an Animal Sniffer error, 113 * despite the @IgnoreJRERequirement annotation there. My assumption is that, because javac 114 * generates a synthetic method for the body of the lambda, the actual method calls that Animal 115 * Sniffer is flagging don't appear inside toImmutableSortedMultiset but rather inside that 116 * synthetic method. By moving those calls to a named method, we're able to apply 117 * @IgnoreJRERequirement somewhere that it will help. 118 */ 119 private static <T extends @Nullable Object, E> void mapAndAdd( 120 T t, 121 Multiset<E> multiset, 122 Function<? super T, ? extends E> elementFunction, 123 ToIntFunction<? super T> countFunction) { 124 multiset.add(checkNotNull(elementFunction.apply(t)), countFunction.applyAsInt(t)); 125 } 126 127 /** 128 * Returns the empty immutable sorted multiset. 129 * 130 * <p><b>Performance note:</b> the instance returned is a singleton. 131 */ 132 @SuppressWarnings("unchecked") 133 public static <E> ImmutableSortedMultiset<E> of() { 134 return (ImmutableSortedMultiset) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; 135 } 136 137 /** Returns an immutable sorted multiset containing a single element. */ 138 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1) { 139 RegularImmutableSortedSet<E> elementSet = 140 (RegularImmutableSortedSet<E>) ImmutableSortedSet.of(e1); 141 long[] cumulativeCounts = {0, 1}; 142 return new RegularImmutableSortedMultiset<>(elementSet, cumulativeCounts, 0, 1); 143 } 144 145 /** 146 * Returns an immutable sorted multiset containing the given elements sorted by their natural 147 * ordering. 148 * 149 * @throws NullPointerException if any element is null 150 */ 151 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2) { 152 return copyOf(Ordering.natural(), Arrays.asList(e1, e2)); 153 } 154 155 /** 156 * Returns an immutable sorted multiset containing the given elements sorted by their natural 157 * ordering. 158 * 159 * @throws NullPointerException if any element is null 160 */ 161 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) { 162 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3)); 163 } 164 165 /** 166 * Returns an immutable sorted multiset containing the given elements sorted by their natural 167 * ordering. 168 * 169 * @throws NullPointerException if any element is null 170 */ 171 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 172 E e1, E e2, E e3, E e4) { 173 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4)); 174 } 175 176 /** 177 * Returns an immutable sorted multiset containing the given elements sorted by their natural 178 * ordering. 179 * 180 * @throws NullPointerException if any element is null 181 */ 182 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 183 E e1, E e2, E e3, E e4, E e5) { 184 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4, e5)); 185 } 186 187 /** 188 * Returns an immutable sorted multiset containing the given elements sorted by their natural 189 * ordering. 190 * 191 * @throws NullPointerException if any element is null 192 */ 193 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 194 E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { 195 int size = remaining.length + 6; 196 List<E> all = Lists.newArrayListWithCapacity(size); 197 Collections.addAll(all, e1, e2, e3, e4, e5, e6); 198 Collections.addAll(all, remaining); 199 return copyOf(Ordering.natural(), all); 200 } 201 202 /** 203 * Returns an immutable sorted multiset containing the given elements sorted by their natural 204 * ordering. 205 * 206 * @throws NullPointerException if any of {@code elements} is null 207 */ 208 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> copyOf(E[] elements) { 209 return copyOf(Ordering.natural(), Arrays.asList(elements)); 210 } 211 212 /** 213 * Returns an immutable sorted multiset containing the given elements sorted by their natural 214 * ordering. To create a copy of a {@code SortedMultiset} that preserves the comparator, call 215 * {@link #copyOfSorted} instead. This method iterates over {@code elements} at most once. 216 * 217 * <p>Note that if {@code s} is a {@code Multiset<String>}, then {@code 218 * ImmutableSortedMultiset.copyOf(s)} returns an {@code ImmutableSortedMultiset<String>} 219 * containing each of the strings in {@code s}, while {@code ImmutableSortedMultiset.of(s)} 220 * returns an {@code ImmutableSortedMultiset<Multiset<String>>} containing one element (the given 221 * multiset itself). 222 * 223 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 224 * safe to do so. The exact circumstances under which a copy will or will not be performed are 225 * undocumented and subject to change. 226 * 227 * <p>This method is not type-safe, as it may be called on elements that are not mutually 228 * comparable. 229 * 230 * @throws ClassCastException if the elements are not mutually comparable 231 * @throws NullPointerException if any of {@code elements} is null 232 */ 233 public static <E> ImmutableSortedMultiset<E> copyOf(Iterable<? extends E> elements) { 234 // Hack around E not being a subtype of Comparable. 235 // Unsafe, see ImmutableSortedMultisetFauxverideShim. 236 @SuppressWarnings("unchecked") 237 Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable<?>>natural(); 238 return copyOf(naturalOrder, elements); 239 } 240 241 /** 242 * Returns an immutable sorted multiset containing the given elements sorted by their natural 243 * ordering. 244 * 245 * <p>This method is not type-safe, as it may be called on elements that are not mutually 246 * comparable. 247 * 248 * @throws ClassCastException if the elements are not mutually comparable 249 * @throws NullPointerException if any of {@code elements} is null 250 */ 251 public static <E> ImmutableSortedMultiset<E> copyOf(Iterator<? extends E> elements) { 252 // Hack around E not being a subtype of Comparable. 253 // Unsafe, see ImmutableSortedMultisetFauxverideShim. 254 @SuppressWarnings("unchecked") 255 Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable<?>>natural(); 256 return copyOf(naturalOrder, elements); 257 } 258 259 /** 260 * Returns an immutable sorted multiset containing the given elements sorted by the given {@code 261 * Comparator}. 262 * 263 * @throws NullPointerException if {@code comparator} or any of {@code elements} is null 264 */ 265 public static <E> ImmutableSortedMultiset<E> copyOf( 266 Comparator<? super E> comparator, Iterator<? extends E> elements) { 267 checkNotNull(comparator); 268 return new Builder<E>(comparator).addAll(elements).build(); 269 } 270 271 /** 272 * Returns an immutable sorted multiset containing the given elements sorted by the given {@code 273 * Comparator}. This method iterates over {@code elements} at most once. 274 * 275 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 276 * safe to do so. The exact circumstances under which a copy will or will not be performed are 277 * undocumented and subject to change. 278 * 279 * @throws NullPointerException if {@code comparator} or any of {@code elements} is null 280 */ 281 public static <E> ImmutableSortedMultiset<E> copyOf( 282 Comparator<? super E> comparator, Iterable<? extends E> elements) { 283 if (elements instanceof ImmutableSortedMultiset) { 284 @SuppressWarnings("unchecked") // immutable collections are always safe for covariant casts 285 ImmutableSortedMultiset<E> multiset = (ImmutableSortedMultiset<E>) elements; 286 if (comparator.equals(multiset.comparator())) { 287 if (multiset.isPartialView()) { 288 return copyOfSortedEntries(comparator, multiset.entrySet().asList()); 289 } else { 290 return multiset; 291 } 292 } 293 } 294 return new ImmutableSortedMultiset.Builder<E>(comparator).addAll(elements).build(); 295 } 296 297 /** 298 * Returns an immutable sorted multiset containing the elements of a sorted multiset, sorted by 299 * the same {@code Comparator}. That behavior differs from {@link #copyOf(Iterable)}, which always 300 * uses the natural ordering of the elements. 301 * 302 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 303 * safe to do so. The exact circumstances under which a copy will or will not be performed are 304 * undocumented and subject to change. 305 * 306 * <p>This method is safe to use even when {@code sortedMultiset} is a synchronized or concurrent 307 * collection that is currently being modified by another thread. 308 * 309 * @throws NullPointerException if {@code sortedMultiset} or any of its elements is null 310 */ 311 public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) { 312 return copyOfSortedEntries( 313 sortedMultiset.comparator(), Lists.newArrayList(sortedMultiset.entrySet())); 314 } 315 316 private static <E> ImmutableSortedMultiset<E> copyOfSortedEntries( 317 Comparator<? super E> comparator, Collection<Entry<E>> entries) { 318 if (entries.isEmpty()) { 319 return emptyMultiset(comparator); 320 } 321 ImmutableList.Builder<E> elementsBuilder = new ImmutableList.Builder<>(entries.size()); 322 long[] cumulativeCounts = new long[entries.size() + 1]; 323 int i = 0; 324 for (Entry<E> entry : entries) { 325 elementsBuilder.add(entry.getElement()); 326 cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount(); 327 i++; 328 } 329 return new RegularImmutableSortedMultiset<>( 330 new RegularImmutableSortedSet<E>(elementsBuilder.build(), comparator), 331 cumulativeCounts, 332 0, 333 entries.size()); 334 } 335 336 @SuppressWarnings("unchecked") 337 static <E> ImmutableSortedMultiset<E> emptyMultiset(Comparator<? super E> comparator) { 338 if (Ordering.natural().equals(comparator)) { 339 return (ImmutableSortedMultiset<E>) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; 340 } else { 341 return new RegularImmutableSortedMultiset<>(comparator); 342 } 343 } 344 345 ImmutableSortedMultiset() {} 346 347 @Override 348 public final Comparator<? super E> comparator() { 349 return elementSet().comparator(); 350 } 351 352 @Override 353 public abstract ImmutableSortedSet<E> elementSet(); 354 355 @LazyInit transient @Nullable ImmutableSortedMultiset<E> descendingMultiset; 356 357 @Override 358 public ImmutableSortedMultiset<E> descendingMultiset() { 359 ImmutableSortedMultiset<E> result = descendingMultiset; 360 if (result == null) { 361 return descendingMultiset = 362 this.isEmpty() 363 ? emptyMultiset(Ordering.from(comparator()).reverse()) 364 : new DescendingImmutableSortedMultiset<E>(this); 365 } 366 return result; 367 } 368 369 /** 370 * {@inheritDoc} 371 * 372 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 373 * 374 * @throws UnsupportedOperationException always 375 * @deprecated Unsupported operation. 376 */ 377 @CanIgnoreReturnValue 378 @Deprecated 379 @Override 380 @DoNotCall("Always throws UnsupportedOperationException") 381 public final @Nullable Entry<E> pollFirstEntry() { 382 throw new UnsupportedOperationException(); 383 } 384 385 /** 386 * {@inheritDoc} 387 * 388 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 389 * 390 * @throws UnsupportedOperationException always 391 * @deprecated Unsupported operation. 392 */ 393 @CanIgnoreReturnValue 394 @Deprecated 395 @Override 396 @DoNotCall("Always throws UnsupportedOperationException") 397 public final @Nullable Entry<E> pollLastEntry() { 398 throw new UnsupportedOperationException(); 399 } 400 401 @Override 402 public abstract ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType); 403 404 @Override 405 public ImmutableSortedMultiset<E> subMultiset( 406 E lowerBound, BoundType lowerBoundType, E upperBound, BoundType upperBoundType) { 407 checkArgument( 408 comparator().compare(lowerBound, upperBound) <= 0, 409 "Expected lowerBound <= upperBound but %s > %s", 410 lowerBound, 411 upperBound); 412 return tailMultiset(lowerBound, lowerBoundType).headMultiset(upperBound, upperBoundType); 413 } 414 415 @Override 416 public abstract ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType); 417 418 /** 419 * Returns a builder that creates immutable sorted multisets with an explicit comparator. If the 420 * comparator has a more general type than the set being generated, such as creating a {@code 421 * SortedMultiset<Integer>} with a {@code Comparator<Number>}, use the {@link Builder} constructor 422 * instead. 423 * 424 * @throws NullPointerException if {@code comparator} is null 425 */ 426 public static <E> Builder<E> orderedBy(Comparator<E> comparator) { 427 return new Builder<>(comparator); 428 } 429 430 /** 431 * Returns a builder that creates immutable sorted multisets whose elements are ordered by the 432 * reverse of their natural ordering. 433 * 434 * <p>Note: the type parameter {@code E} extends {@code Comparable<?>} rather than {@code 435 * Comparable<? super E>} in order to accommodate users of obsolete javac versions affected by <a 436 * href="https://bugs.openjdk.org/browse/JDK-6468354">JDK-6468354</a>. 437 */ 438 public static <E extends Comparable<?>> Builder<E> reverseOrder() { 439 return new Builder<>(Ordering.<E>natural().reverse()); 440 } 441 442 /** 443 * Returns a builder that creates immutable sorted multisets whose elements are ordered by their 444 * natural ordering. The sorted multisets use {@link Ordering#natural()} as the comparator. This 445 * method provides more type-safety than {@link #builder}, as it can be called only for classes 446 * that implement {@link Comparable}. 447 * 448 * <p>Note: the type parameter {@code E} extends {@code Comparable<?>} rather than {@code 449 * Comparable<? super E>} in order to accommodate users of obsolete javac versions affected by <a 450 * href="https://bugs.openjdk.org/browse/JDK-6468354">JDK-6468354</a>. 451 */ 452 public static <E extends Comparable<?>> Builder<E> naturalOrder() { 453 return new Builder<>(Ordering.natural()); 454 } 455 456 /** 457 * A builder for creating immutable multiset instances, especially {@code public static final} 458 * multisets ("constant multisets"). Example: 459 * 460 * <pre>{@code 461 * public static final ImmutableSortedMultiset<Bean> BEANS = 462 * new ImmutableSortedMultiset.Builder<Bean>(colorComparator()) 463 * .addCopies(Bean.COCOA, 4) 464 * .addCopies(Bean.GARDEN, 6) 465 * .addCopies(Bean.RED, 8) 466 * .addCopies(Bean.BLACK_EYED, 10) 467 * .build(); 468 * }</pre> 469 * 470 * <p>Builder instances can be reused; it is safe to call {@link #build} multiple times to build 471 * multiple multisets in series. 472 * 473 * @since 12.0 474 */ 475 public static class Builder<E> extends ImmutableMultiset.Builder<E> { 476 /* 477 * We keep an array of elements and counts. Periodically -- when we need more room in the 478 * array, or when we're building, or the like -- we sort, deduplicate, and combine the counts. 479 * Negative counts indicate a setCount operation with ~counts[i]. 480 */ 481 482 private final Comparator<? super E> comparator; 483 484 @VisibleForTesting E[] elements; 485 private int[] counts; 486 487 /* 488 * The number of used positions in the elements array. We deduplicate periodically, so this 489 * may fluctuate up and down. 490 */ 491 private int length; 492 493 // True if we just called build() and the elements array is being used by a created ISM, meaning 494 // we shouldn't modify that array further. 495 private boolean forceCopyElements; 496 497 /** 498 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 499 * ImmutableSortedMultiset#orderedBy(Comparator)}. 500 */ 501 @SuppressWarnings("unchecked") 502 public Builder(Comparator<? super E> comparator) { 503 super(true); // doesn't allocate hash table in supertype 504 this.comparator = checkNotNull(comparator); 505 this.elements = (E[]) new Object[ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY]; 506 this.counts = new int[ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY]; 507 } 508 509 /** Check if we need to do deduplication and coalescing, and if so, do it. */ 510 private void maintenance() { 511 if (length == elements.length) { 512 dedupAndCoalesce(true); 513 } else if (forceCopyElements) { 514 this.elements = Arrays.copyOf(elements, elements.length); 515 // we don't currently need to copy the counts array, because we don't use it directly 516 // in built ISMs 517 } 518 forceCopyElements = false; 519 } 520 521 private void dedupAndCoalesce(boolean maybeExpand) { 522 if (length == 0) { 523 return; 524 } 525 E[] sortedElements = Arrays.copyOf(elements, length); 526 Arrays.sort(sortedElements, comparator); 527 int uniques = 1; 528 for (int i = 1; i < sortedElements.length; i++) { 529 if (comparator.compare(sortedElements[uniques - 1], sortedElements[i]) < 0) { 530 sortedElements[uniques] = sortedElements[i]; 531 uniques++; 532 } 533 } 534 Arrays.fill(sortedElements, uniques, length, null); 535 if (maybeExpand && uniques * 4 > length * 3) { 536 // lots of nonduplicated elements, expand the array by 50% 537 sortedElements = 538 Arrays.copyOf(sortedElements, IntMath.saturatedAdd(length, length / 2 + 1)); 539 } 540 int[] sortedCounts = new int[sortedElements.length]; 541 for (int i = 0; i < length; i++) { 542 int index = Arrays.binarySearch(sortedElements, 0, uniques, elements[i], comparator); 543 if (counts[i] >= 0) { 544 sortedCounts[index] += counts[i]; 545 } else { 546 sortedCounts[index] = ~counts[i]; 547 } 548 } 549 // Note that we're not getting rid, yet, of elements with count 0. We'll do that in build(). 550 this.elements = sortedElements; 551 this.counts = sortedCounts; 552 this.length = uniques; 553 } 554 555 /** 556 * Adds {@code element} to the {@code ImmutableSortedMultiset}. 557 * 558 * @param element the element to add 559 * @return this {@code Builder} object 560 * @throws NullPointerException if {@code element} is null 561 */ 562 @CanIgnoreReturnValue 563 @Override 564 public Builder<E> add(E element) { 565 return addCopies(element, 1); 566 } 567 568 /** 569 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 570 * 571 * @param elements the elements to add 572 * @return this {@code Builder} object 573 * @throws NullPointerException if {@code elements} is null or contains a null element 574 */ 575 @CanIgnoreReturnValue 576 @Override 577 public Builder<E> add(E... elements) { 578 for (E element : elements) { 579 add(element); 580 } 581 return this; 582 } 583 584 /** 585 * Adds a number of occurrences of an element to this {@code ImmutableSortedMultiset}. 586 * 587 * @param element the element to add 588 * @param occurrences the number of occurrences of the element to add. May be zero, in which 589 * case no change will be made. 590 * @return this {@code Builder} object 591 * @throws NullPointerException if {@code element} is null 592 * @throws IllegalArgumentException if {@code occurrences} is negative, or if this operation 593 * would result in more than {@link Integer#MAX_VALUE} occurrences of the element 594 */ 595 @CanIgnoreReturnValue 596 @Override 597 public Builder<E> addCopies(E element, int occurrences) { 598 checkNotNull(element); 599 CollectPreconditions.checkNonnegative(occurrences, "occurrences"); 600 if (occurrences == 0) { 601 return this; 602 } 603 maintenance(); 604 elements[length] = element; 605 counts[length] = occurrences; 606 length++; 607 return this; 608 } 609 610 /** 611 * Adds or removes the necessary occurrences of an element such that the element attains the 612 * desired count. 613 * 614 * @param element the element to add or remove occurrences of 615 * @param count the desired count of the element in this multiset 616 * @return this {@code Builder} object 617 * @throws NullPointerException if {@code element} is null 618 * @throws IllegalArgumentException if {@code count} is negative 619 */ 620 @CanIgnoreReturnValue 621 @Override 622 public Builder<E> setCount(E element, int count) { 623 checkNotNull(element); 624 CollectPreconditions.checkNonnegative(count, "count"); 625 maintenance(); 626 elements[length] = element; 627 counts[length] = ~count; 628 length++; 629 return this; 630 } 631 632 /** 633 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 634 * 635 * @param elements the {@code Iterable} to add to the {@code ImmutableSortedMultiset} 636 * @return this {@code Builder} object 637 * @throws NullPointerException if {@code elements} is null or contains a null element 638 */ 639 @CanIgnoreReturnValue 640 @Override 641 public Builder<E> addAll(Iterable<? extends E> elements) { 642 if (elements instanceof Multiset) { 643 for (Entry<? extends E> entry : ((Multiset<? extends E>) elements).entrySet()) { 644 addCopies(entry.getElement(), entry.getCount()); 645 } 646 } else { 647 for (E e : elements) { 648 add(e); 649 } 650 } 651 return this; 652 } 653 654 /** 655 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 656 * 657 * @param elements the elements to add to the {@code ImmutableSortedMultiset} 658 * @return this {@code Builder} object 659 * @throws NullPointerException if {@code elements} is null or contains a null element 660 */ 661 @CanIgnoreReturnValue 662 @Override 663 public Builder<E> addAll(Iterator<? extends E> elements) { 664 while (elements.hasNext()) { 665 add(elements.next()); 666 } 667 return this; 668 } 669 670 private void dedupAndCoalesceAndDeleteEmpty() { 671 dedupAndCoalesce(false); 672 673 // If there was a setCount(elem, 0), those elements are still present. Eliminate them. 674 int size = 0; 675 for (int i = 0; i < length; i++) { 676 if (counts[i] > 0) { 677 elements[size] = elements[i]; 678 counts[size] = counts[i]; 679 size++; 680 } 681 } 682 Arrays.fill(elements, size, length, null); 683 Arrays.fill(counts, size, length, 0); 684 length = size; 685 } 686 687 /** 688 * Returns a newly-created {@code ImmutableSortedMultiset} based on the contents of the {@code 689 * Builder}. 690 */ 691 @Override 692 public ImmutableSortedMultiset<E> build() { 693 dedupAndCoalesceAndDeleteEmpty(); 694 if (length == 0) { 695 return emptyMultiset(comparator); 696 } 697 RegularImmutableSortedSet<E> elementSet = 698 (RegularImmutableSortedSet<E>) ImmutableSortedSet.construct(comparator, length, elements); 699 long[] cumulativeCounts = new long[length + 1]; 700 for (int i = 0; i < length; i++) { 701 cumulativeCounts[i + 1] = cumulativeCounts[i] + counts[i]; 702 } 703 forceCopyElements = true; 704 return new RegularImmutableSortedMultiset<E>(elementSet, cumulativeCounts, 0, length); 705 } 706 } 707 708 @J2ktIncompatible // serialization 709 private static final class SerializedForm<E> implements Serializable { 710 final Comparator<? super E> comparator; 711 final E[] elements; 712 final int[] counts; 713 714 @SuppressWarnings("unchecked") 715 SerializedForm(SortedMultiset<E> multiset) { 716 this.comparator = multiset.comparator(); 717 int n = multiset.entrySet().size(); 718 elements = (E[]) new Object[n]; 719 counts = new int[n]; 720 int i = 0; 721 for (Entry<E> entry : multiset.entrySet()) { 722 elements[i] = entry.getElement(); 723 counts[i] = entry.getCount(); 724 i++; 725 } 726 } 727 728 Object readResolve() { 729 int n = elements.length; 730 Builder<E> builder = new Builder<>(comparator); 731 for (int i = 0; i < n; i++) { 732 builder.addCopies(elements[i], counts[i]); 733 } 734 return builder.build(); 735 } 736 } 737 738 @Override 739 @J2ktIncompatible // serialization 740 Object writeReplace() { 741 return new SerializedForm<E>(this); 742 } 743 744 @J2ktIncompatible // java.io.ObjectInputStream 745 private void readObject(ObjectInputStream stream) throws InvalidObjectException { 746 throw new InvalidObjectException("Use SerializedForm"); 747 } 748 749 /** 750 * Not supported. Use {@link #toImmutableSortedMultiset} instead. This method exists only to hide 751 * {@link ImmutableMultiset#toImmutableMultiset} from consumers of {@code 752 * ImmutableSortedMultiset}. 753 * 754 * @throws UnsupportedOperationException always 755 * @deprecated Use {@link ImmutableSortedMultiset#toImmutableSortedMultiset}. 756 * @since 33.2.0 (available since 21.0 in guava-jre) 757 */ 758 @DoNotCall("Use toImmutableSortedMultiset.") 759 @Deprecated 760 @SuppressWarnings("Java7ApiChecker") 761 @IgnoreJRERequirement // Users will use this only if they're already using streams. 762 public static <E> Collector<E, ?, ImmutableMultiset<E>> toImmutableMultiset() { 763 throw new UnsupportedOperationException(); 764 } 765 766 /** 767 * Not supported. Use {@link #toImmutableSortedMultiset} instead. This method exists only to hide 768 * {@link ImmutableMultiset#toImmutableMultiset} from consumers of {@code 769 * ImmutableSortedMultiset}. 770 * 771 * @throws UnsupportedOperationException always 772 * @deprecated Use {@link ImmutableSortedMultiset#toImmutableSortedMultiset}. 773 * @since 33.2.0 (available since 22.0 in guava-jre) 774 */ 775 @DoNotCall("Use toImmutableSortedMultiset.") 776 @Deprecated 777 @SuppressWarnings("Java7ApiChecker") 778 @IgnoreJRERequirement // Users will use this only if they're already using streams. 779 public static <T extends @Nullable Object, E> 780 Collector<T, ?, ImmutableMultiset<E>> toImmutableMultiset( 781 Function<? super T, ? extends E> elementFunction, 782 ToIntFunction<? super T> countFunction) { 783 throw new UnsupportedOperationException(); 784 } 785 786 /** 787 * Not supported. Use {@link #naturalOrder}, which offers better type-safety, instead. This method 788 * exists only to hide {@link ImmutableMultiset#builder} from consumers of {@code 789 * ImmutableSortedMultiset}. 790 * 791 * @throws UnsupportedOperationException always 792 * @deprecated Use {@link ImmutableSortedMultiset#naturalOrder}, which offers better type-safety. 793 */ 794 @DoNotCall("Use naturalOrder.") 795 @Deprecated 796 public static <E> ImmutableSortedMultiset.Builder<E> builder() { 797 throw new UnsupportedOperationException(); 798 } 799 800 /** 801 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 802 * Comparable} element.</b> Proper calls will resolve to the version in {@code 803 * ImmutableSortedMultiset}, not this dummy version. 804 * 805 * @throws UnsupportedOperationException always 806 * @deprecated <b>Pass a parameter of type {@code Comparable} to use {@link 807 * ImmutableSortedMultiset#of(Comparable)}.</b> 808 */ 809 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 810 @Deprecated 811 public static <E> ImmutableSortedMultiset<E> of(E e1) { 812 throw new UnsupportedOperationException(); 813 } 814 815 /** 816 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 817 * Comparable} element.</b> Proper calls will resolve to the version in {@code 818 * ImmutableSortedMultiset}, not this dummy version. 819 * 820 * @throws UnsupportedOperationException always 821 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 822 * ImmutableSortedMultiset#of(Comparable, Comparable)}.</b> 823 */ 824 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 825 @Deprecated 826 public static <E> ImmutableSortedMultiset<E> of(E e1, E e2) { 827 throw new UnsupportedOperationException(); 828 } 829 830 /** 831 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 832 * Comparable} element.</b> Proper calls will resolve to the version in {@code 833 * ImmutableSortedMultiset}, not this dummy version. 834 * 835 * @throws UnsupportedOperationException always 836 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 837 * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable)}.</b> 838 */ 839 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 840 @Deprecated 841 public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) { 842 throw new UnsupportedOperationException(); 843 } 844 845 /** 846 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 847 * Comparable} element.</b> Proper calls will resolve to the version in {@code 848 * ImmutableSortedMultiset}, not this dummy version. 849 * 850 * @throws UnsupportedOperationException always 851 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 852 * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable)}. </b> 853 */ 854 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 855 @Deprecated 856 public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3, E e4) { 857 throw new UnsupportedOperationException(); 858 } 859 860 /** 861 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 862 * Comparable} element.</b> Proper calls will resolve to the version in {@code 863 * ImmutableSortedMultiset}, not this dummy version. 864 * 865 * @throws UnsupportedOperationException always 866 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 867 * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable, Comparable)} . 868 * </b> 869 */ 870 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 871 @Deprecated 872 public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3, E e4, E e5) { 873 throw new UnsupportedOperationException(); 874 } 875 876 /** 877 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 878 * Comparable} element.</b> Proper calls will resolve to the version in {@code 879 * ImmutableSortedMultiset}, not this dummy version. 880 * 881 * @throws UnsupportedOperationException always 882 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 883 * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable, Comparable, 884 * Comparable, Comparable...)} . </b> 885 */ 886 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 887 @Deprecated 888 public static <E> ImmutableSortedMultiset<E> of( 889 E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { 890 throw new UnsupportedOperationException(); 891 } 892 893 /** 894 * Not supported. <b>You are attempting to create a multiset that may contain non-{@code 895 * Comparable} elements.</b> Proper calls will resolve to the version in {@code 896 * ImmutableSortedMultiset}, not this dummy version. 897 * 898 * @throws UnsupportedOperationException always 899 * @deprecated <b>Pass parameters of type {@code Comparable} to use {@link 900 * ImmutableSortedMultiset#copyOf(Comparable[])}.</b> 901 */ 902 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 903 @Deprecated 904 // The usage of "Z" here works around bugs in Javadoc (JDK-8318093) and JDiff. 905 public static <Z> ImmutableSortedMultiset<Z> copyOf(Z[] elements) { 906 throw new UnsupportedOperationException(); 907 } 908 909 private static final long serialVersionUID = 0xdecaf; 910}