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