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