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 public static <E> ImmutableSortedMultiset<E> copyOf( 280 Comparator<? super E> comparator, Iterable<? extends E> elements) { 281 if (elements instanceof ImmutableSortedMultiset) { 282 @SuppressWarnings("unchecked") // immutable collections are always safe for covariant casts 283 ImmutableSortedMultiset<E> multiset = (ImmutableSortedMultiset<E>) elements; 284 if (comparator.equals(multiset.comparator())) { 285 if (multiset.isPartialView()) { 286 return copyOfSortedEntries(comparator, multiset.entrySet().asList()); 287 } else { 288 return multiset; 289 } 290 } 291 } 292 return new ImmutableSortedMultiset.Builder<E>(comparator).addAll(elements).build(); 293 } 294 295 /** 296 * Returns an immutable sorted multiset containing the elements of a sorted multiset, sorted by 297 * the same {@code Comparator}. That behavior differs from {@link #copyOf(Iterable)}, which always 298 * uses the natural ordering of the elements. 299 * 300 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 301 * safe to do so. The exact circumstances under which a copy will or will not be performed are 302 * undocumented and subject to change. 303 * 304 * <p>This method is safe to use even when {@code sortedMultiset} is a synchronized or concurrent 305 * collection that is currently being modified by another thread. 306 * 307 * @throws NullPointerException if {@code sortedMultiset} or any of its elements is null 308 */ 309 public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) { 310 return copyOfSortedEntries( 311 sortedMultiset.comparator(), Lists.newArrayList(sortedMultiset.entrySet())); 312 } 313 314 private static <E> ImmutableSortedMultiset<E> copyOfSortedEntries( 315 Comparator<? super E> comparator, Collection<Entry<E>> entries) { 316 if (entries.isEmpty()) { 317 return emptyMultiset(comparator); 318 } 319 ImmutableList.Builder<E> elementsBuilder = new ImmutableList.Builder<E>(entries.size()); 320 long[] cumulativeCounts = new long[entries.size() + 1]; 321 int i = 0; 322 for (Entry<E> entry : entries) { 323 elementsBuilder.add(entry.getElement()); 324 cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount(); 325 i++; 326 } 327 return new RegularImmutableSortedMultiset<E>( 328 new RegularImmutableSortedSet<E>(elementsBuilder.build(), comparator), 329 cumulativeCounts, 330 0, 331 entries.size()); 332 } 333 334 @SuppressWarnings("unchecked") 335 static <E> ImmutableSortedMultiset<E> emptyMultiset(Comparator<? super E> comparator) { 336 if (Ordering.natural().equals(comparator)) { 337 return (ImmutableSortedMultiset<E>) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; 338 } else { 339 return new RegularImmutableSortedMultiset<E>(comparator); 340 } 341 } 342 343 ImmutableSortedMultiset() {} 344 345 @Override 346 public final Comparator<? super E> comparator() { 347 return elementSet().comparator(); 348 } 349 350 @Override 351 public abstract ImmutableSortedSet<E> elementSet(); 352 353 @LazyInit @CheckForNull transient ImmutableSortedMultiset<E> descendingMultiset; 354 355 @Override 356 public ImmutableSortedMultiset<E> descendingMultiset() { 357 ImmutableSortedMultiset<E> result = descendingMultiset; 358 if (result == null) { 359 return descendingMultiset = 360 this.isEmpty() 361 ? emptyMultiset(Ordering.from(comparator()).reverse()) 362 : new DescendingImmutableSortedMultiset<E>(this); 363 } 364 return result; 365 } 366 367 /** 368 * {@inheritDoc} 369 * 370 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 371 * 372 * @throws UnsupportedOperationException always 373 * @deprecated Unsupported operation. 374 */ 375 @CanIgnoreReturnValue 376 @Deprecated 377 @Override 378 @DoNotCall("Always throws UnsupportedOperationException") 379 @CheckForNull 380 public final Entry<E> pollFirstEntry() { 381 throw new UnsupportedOperationException(); 382 } 383 384 /** 385 * {@inheritDoc} 386 * 387 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 388 * 389 * @throws UnsupportedOperationException always 390 * @deprecated Unsupported operation. 391 */ 392 @CanIgnoreReturnValue 393 @Deprecated 394 @Override 395 @DoNotCall("Always throws UnsupportedOperationException") 396 @CheckForNull 397 public final 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<E>(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>} as a workaround for javac <a 436 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>. 437 */ 438 public static <E extends Comparable<?>> Builder<E> reverseOrder() { 439 return new Builder<E>(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>} as a workaround for javac <a 450 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>. 451 */ 452 public static <E extends Comparable<?>> Builder<E> naturalOrder() { 453 return new Builder<E>(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 */ 757 @DoNotCall("Use toImmutableSortedMultiset.") 758 @Deprecated 759 @SuppressWarnings({"AndroidJdkLibsChecker", "Java7ApiChecker"}) 760 @IgnoreJRERequirement // Users will use this only if they're already using streams. 761 static <E> Collector<E, ?, ImmutableMultiset<E>> toImmutableMultiset() { 762 throw new UnsupportedOperationException(); 763 } 764 765 /** 766 * Not supported. Use {@link #toImmutableSortedMultiset} instead. This method exists only to hide 767 * {@link ImmutableMultiset#toImmutableMultiset} from consumers of {@code 768 * ImmutableSortedMultiset}. 769 * 770 * @throws UnsupportedOperationException always 771 * @deprecated Use {@link ImmutableSortedMultiset#toImmutableSortedMultiset}. 772 */ 773 @DoNotCall("Use toImmutableSortedMultiset.") 774 @Deprecated 775 @SuppressWarnings({"AndroidJdkLibsChecker", "Java7ApiChecker"}) 776 @IgnoreJRERequirement // Users will use this only if they're already using streams. 777 static <T extends @Nullable Object, E> Collector<T, ?, ImmutableMultiset<E>> toImmutableMultiset( 778 Function<? super T, ? extends E> elementFunction, ToIntFunction<? super T> countFunction) { 779 throw new UnsupportedOperationException(); 780 } 781 782 /** 783 * Not supported. Use {@link #naturalOrder}, which offers better type-safety, instead. This method 784 * exists only to hide {@link ImmutableMultiset#builder} from consumers of {@code 785 * ImmutableSortedMultiset}. 786 * 787 * @throws UnsupportedOperationException always 788 * @deprecated Use {@link ImmutableSortedMultiset#naturalOrder}, which offers better type-safety. 789 */ 790 @DoNotCall("Use naturalOrder.") 791 @Deprecated 792 public static <E> ImmutableSortedMultiset.Builder<E> builder() { 793 throw new UnsupportedOperationException(); 794 } 795 796 /** 797 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 798 * Comparable} element.</b> Proper calls will resolve to the version in {@code 799 * ImmutableSortedMultiset}, not this dummy version. 800 * 801 * @throws UnsupportedOperationException always 802 * @deprecated <b>Pass a parameter of type {@code Comparable} to use {@link 803 * ImmutableSortedMultiset#of(Comparable)}.</b> 804 */ 805 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 806 @Deprecated 807 public static <E> ImmutableSortedMultiset<E> of(E element) { 808 throw new UnsupportedOperationException(); 809 } 810 811 /** 812 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 813 * Comparable} element.</b> Proper calls will resolve to the version in {@code 814 * ImmutableSortedMultiset}, not this dummy version. 815 * 816 * @throws UnsupportedOperationException always 817 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 818 * ImmutableSortedMultiset#of(Comparable, Comparable)}.</b> 819 */ 820 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 821 @Deprecated 822 public static <E> ImmutableSortedMultiset<E> of(E e1, E e2) { 823 throw new UnsupportedOperationException(); 824 } 825 826 /** 827 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 828 * Comparable} element.</b> Proper calls will resolve to the version in {@code 829 * ImmutableSortedMultiset}, not this dummy version. 830 * 831 * @throws UnsupportedOperationException always 832 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 833 * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable)}.</b> 834 */ 835 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 836 @Deprecated 837 public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) { 838 throw new UnsupportedOperationException(); 839 } 840 841 /** 842 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 843 * Comparable} element.</b> Proper calls will resolve to the version in {@code 844 * ImmutableSortedMultiset}, not this dummy version. 845 * 846 * @throws UnsupportedOperationException always 847 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 848 * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable)}. </b> 849 */ 850 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 851 @Deprecated 852 public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3, E e4) { 853 throw new UnsupportedOperationException(); 854 } 855 856 /** 857 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 858 * Comparable} element.</b> Proper calls will resolve to the version in {@code 859 * ImmutableSortedMultiset}, not this dummy version. 860 * 861 * @throws UnsupportedOperationException always 862 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 863 * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable, Comparable)} . 864 * </b> 865 */ 866 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 867 @Deprecated 868 public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3, E e4, E e5) { 869 throw new UnsupportedOperationException(); 870 } 871 872 /** 873 * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code 874 * Comparable} element.</b> Proper calls will resolve to the version in {@code 875 * ImmutableSortedMultiset}, not this dummy version. 876 * 877 * @throws UnsupportedOperationException always 878 * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link 879 * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable, Comparable, 880 * Comparable, Comparable...)} . </b> 881 */ 882 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 883 @Deprecated 884 public static <E> ImmutableSortedMultiset<E> of( 885 E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { 886 throw new UnsupportedOperationException(); 887 } 888 889 /** 890 * Not supported. <b>You are attempting to create a multiset that may contain non-{@code 891 * Comparable} elements.</b> Proper calls will resolve to the version in {@code 892 * ImmutableSortedMultiset}, not this dummy version. 893 * 894 * @throws UnsupportedOperationException always 895 * @deprecated <b>Pass parameters of type {@code Comparable} to use {@link 896 * ImmutableSortedMultiset#copyOf(Comparable[])}.</b> 897 */ 898 @DoNotCall("Elements must be Comparable. (Or, pass a Comparator to orderedBy or copyOf.)") 899 @Deprecated 900 // The usage of "Z" here works around bugs in Javadoc (JDK-8318093) and JDiff. 901 public static <Z> ImmutableSortedMultiset<Z> copyOf(Z[] elements) { 902 throw new UnsupportedOperationException(); 903 } 904 905 private static final long serialVersionUID = 0xdecaf; 906}