• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11  * express or implied. See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 package com.google.common.collect;
16 
17 import static com.google.common.base.Preconditions.checkArgument;
18 import static com.google.common.base.Preconditions.checkNotNull;
19 
20 import com.google.common.annotations.GwtIncompatible;
21 import com.google.common.annotations.J2ktIncompatible;
22 import com.google.common.annotations.VisibleForTesting;
23 import com.google.common.math.IntMath;
24 import com.google.errorprone.annotations.CanIgnoreReturnValue;
25 import com.google.errorprone.annotations.DoNotCall;
26 import com.google.errorprone.annotations.concurrent.LazyInit;
27 import java.io.InvalidObjectException;
28 import java.io.ObjectInputStream;
29 import java.io.Serializable;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.Comparator;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.function.Function;
37 import java.util.function.ToIntFunction;
38 import java.util.stream.Collector;
39 import javax.annotation.CheckForNull;
40 import org.checkerframework.checker.nullness.qual.Nullable;
41 
42 /**
43  * A {@link SortedMultiset} whose contents will never change, with many other important properties
44  * detailed at {@link ImmutableCollection}.
45  *
46  * <p><b>Warning:</b> as with any sorted collection, you are strongly advised not to use a {@link
47  * Comparator} or {@link Comparable} type whose comparison behavior is <i>inconsistent with
48  * equals</i>. That is, {@code a.compareTo(b)} or {@code comparator.compare(a, b)} should equal zero
49  * <i>if and only if</i> {@code a.equals(b)}. If this advice is not followed, the resulting
50  * collection will not correctly obey its specification.
51  *
52  * <p>See the Guava User Guide article on <a href=
53  * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained">immutable collections</a>.
54  *
55  * @author Louis Wasserman
56  * @since 12.0
57  */
58 @GwtIncompatible // hasn't been tested yet
59 @ElementTypesAreNonnullByDefault
60 public abstract class ImmutableSortedMultiset<E> extends ImmutableMultiset<E>
61     implements SortedMultiset<E> {
62   // TODO(lowasser): GWT compatibility
63 
64   /**
65    * Returns a {@code Collector} that accumulates the input elements into a new {@code
66    * ImmutableMultiset}. Elements are sorted by the specified comparator.
67    *
68    * <p><b>Warning:</b> {@code comparator} should be <i>consistent with {@code equals}</i> as
69    * explained in the {@link Comparator} documentation.
70    *
71    * @since 33.2.0 (available since 21.0 in guava-jre)
72    */
73   @SuppressWarnings({"AndroidJdkLibsChecker", "Java7ApiChecker"})
74   @IgnoreJRERequirement // Users will use this only if they're already using streams.
toImmutableSortedMultiset( Comparator<? super E> comparator)75   public static <E> Collector<E, ?, ImmutableSortedMultiset<E>> toImmutableSortedMultiset(
76       Comparator<? super E> comparator) {
77     return toImmutableSortedMultiset(comparator, Function.identity(), e -> 1);
78   }
79 
80   /**
81    * Returns a {@code Collector} that accumulates elements into an {@code ImmutableSortedMultiset}
82    * whose elements are the result of applying {@code elementFunction} to the inputs, with counts
83    * equal to the result of applying {@code countFunction} to the inputs.
84    *
85    * <p>If the mapped elements contain duplicates (according to {@code comparator}), the first
86    * occurrence in encounter order appears in the resulting multiset, with count equal to the sum of
87    * the outputs of {@code countFunction.applyAsInt(t)} for each {@code t} mapped to that element.
88    *
89    * @since 33.2.0 (available since 22.0 in guava-jre)
90    */
91   @SuppressWarnings({"AndroidJdkLibsChecker", "Java7ApiChecker"})
92   @IgnoreJRERequirement // Users will use this only if they're already using streams.
93   public static <T extends @Nullable Object, E>
toImmutableSortedMultiset( Comparator<? super E> comparator, Function<? super T, ? extends E> elementFunction, ToIntFunction<? super T> countFunction)94       Collector<T, ?, ImmutableSortedMultiset<E>> toImmutableSortedMultiset(
95           Comparator<? super E> comparator,
96           Function<? super T, ? extends E> elementFunction,
97           ToIntFunction<? super T> countFunction) {
98     checkNotNull(comparator);
99     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({"AndroidJdkLibsChecker", "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    */
mapAndAdd( T t, Multiset<E> multiset, Function<? super T, ? extends E> elementFunction, ToIntFunction<? super T> countFunction)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")
of()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. */
of(E e1)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    */
of(E e1, E e2)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    */
of(E e1, E e2, E e3)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    */
of( E e1, E e2, E e3, E e4)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    */
of( E e1, E e2, E e3, E e4, E e5)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    */
of( E e1, E e2, E e3, E e4, E e5, E e6, E... remaining)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    */
copyOf(E[] elements)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    */
copyOf(Iterable<? extends E> elements)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    */
copyOf(Iterator<? extends E> elements)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    */
copyOf( Comparator<? super E> comparator, Iterator<? extends E> elements)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    */
copyOf( Comparator<? super E> comparator, Iterable<? extends E> elements)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    */
copyOfSorted(SortedMultiset<E> sortedMultiset)313   public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) {
314     return copyOfSortedEntries(
315         sortedMultiset.comparator(), Lists.newArrayList(sortedMultiset.entrySet()));
316   }
317 
copyOfSortedEntries( Comparator<? super E> comparator, Collection<Entry<E>> entries)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")
emptyMultiset(Comparator<? super E> comparator)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 
ImmutableSortedMultiset()347   ImmutableSortedMultiset() {}
348 
349   @Override
comparator()350   public final Comparator<? super E> comparator() {
351     return elementSet().comparator();
352   }
353 
354   @Override
elementSet()355   public abstract ImmutableSortedSet<E> elementSet();
356 
357   @LazyInit @CheckForNull transient ImmutableSortedMultiset<E> descendingMultiset;
358 
359   @Override
descendingMultiset()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
pollFirstEntry()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
pollLastEntry()401   public final Entry<E> pollLastEntry() {
402     throw new UnsupportedOperationException();
403   }
404 
405   @Override
headMultiset(E upperBound, BoundType boundType)406   public abstract ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType);
407 
408   @Override
subMultiset( E lowerBound, BoundType lowerBoundType, E upperBound, BoundType upperBoundType)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
tailMultiset(E lowerBound, BoundType boundType)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    */
orderedBy(Comparator<E> comparator)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    */
reverseOrder()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    */
naturalOrder()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")
Builder(Comparator<? super E> comparator)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. */
maintenance()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 
dedupAndCoalesce(boolean maybeExpand)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
add(E element)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
add(E... elements)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
addCopies(E element, int occurrences)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
setCount(E element, int count)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
addAll(Iterable<? extends E> elements)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
addAll(Iterator<? extends E> elements)667     public Builder<E> addAll(Iterator<? extends E> elements) {
668       while (elements.hasNext()) {
669         add(elements.next());
670       }
671       return this;
672     }
673 
dedupAndCoalesceAndDeleteEmpty()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
build()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")
SerializedForm(SortedMultiset<E> multiset)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 
readResolve()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
writeReplace()744   Object writeReplace() {
745     return new SerializedForm<E>(this);
746   }
747 
748   @J2ktIncompatible // java.io.ObjectInputStream
readObject(ObjectInputStream stream)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({"AndroidJdkLibsChecker", "Java7ApiChecker"})
765   @IgnoreJRERequirement // Users will use this only if they're already using streams.
toImmutableMultiset()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({"AndroidJdkLibsChecker", "Java7ApiChecker"})
782   @IgnoreJRERequirement // Users will use this only if they're already using streams.
783   public static <T extends @Nullable Object, E>
toImmutableMultiset( Function<? super T, ? extends E> elementFunction, ToIntFunction<? super T> countFunction)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
builder()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
of(E e1)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
of(E e1, E e2)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
of(E e1, E e2, E e3)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
of(E e1, E e2, E e3, E e4)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
of(E e1, E e2, E e3, E e4, E e5)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
of( E e1, E e2, E e3, E e4, E e5, E e6, E... remaining)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.
copyOf(Z[] elements)909   public static <Z> ImmutableSortedMultiset<Z> copyOf(Z[] elements) {
910     throw new UnsupportedOperationException();
911   }
912 
913   private static final long serialVersionUID = 0xdecaf;
914 }
915