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