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 javax.annotation.CheckForNull;
037
038/**
039 * A {@link SortedMultiset} whose contents will never change, with many other important properties
040 * detailed at {@link ImmutableCollection}.
041 *
042 * <p><b>Warning:</b> as with any sorted collection, you are strongly advised not to use a {@link
043 * Comparator} or {@link Comparable} type whose comparison behavior is <i>inconsistent with
044 * equals</i>. That is, {@code a.compareTo(b)} or {@code comparator.compare(a, b)} should equal zero
045 * <i>if and only if</i> {@code a.equals(b)}. If this advice is not followed, the resulting
046 * collection will not correctly obey its specification.
047 *
048 * <p>See the Guava User Guide article on <a href=
049 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained">immutable collections</a>.
050 *
051 * @author Louis Wasserman
052 * @since 12.0
053 */
054@GwtIncompatible // hasn't been tested yet
055@ElementTypesAreNonnullByDefault
056public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultisetFauxverideShim<E>
057    implements SortedMultiset<E> {
058  // TODO(lowasser): GWT compatibility
059
060  /**
061   * Returns the empty immutable sorted multiset.
062   *
063   * <p><b>Performance note:</b> the instance returned is a singleton.
064   */
065  @SuppressWarnings("unchecked")
066  public static <E> ImmutableSortedMultiset<E> of() {
067    return (ImmutableSortedMultiset) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET;
068  }
069
070  /** Returns an immutable sorted multiset containing a single element. */
071  public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E element) {
072    RegularImmutableSortedSet<E> elementSet =
073        (RegularImmutableSortedSet<E>) ImmutableSortedSet.of(element);
074    long[] cumulativeCounts = {0, 1};
075    return new RegularImmutableSortedMultiset<E>(elementSet, cumulativeCounts, 0, 1);
076  }
077
078  /**
079   * Returns an immutable sorted multiset containing the given elements sorted by their natural
080   * ordering.
081   *
082   * @throws NullPointerException if any element is null
083   */
084  public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2) {
085    return copyOf(Ordering.natural(), Arrays.asList(e1, e2));
086  }
087
088  /**
089   * Returns an immutable sorted multiset containing the given elements sorted by their natural
090   * ordering.
091   *
092   * @throws NullPointerException if any element is null
093   */
094  public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) {
095    return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3));
096  }
097
098  /**
099   * Returns an immutable sorted multiset containing the given elements sorted by their natural
100   * ordering.
101   *
102   * @throws NullPointerException if any element is null
103   */
104  public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(
105      E e1, E e2, E e3, E e4) {
106    return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4));
107  }
108
109  /**
110   * Returns an immutable sorted multiset containing the given elements sorted by their natural
111   * ordering.
112   *
113   * @throws NullPointerException if any element is null
114   */
115  public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(
116      E e1, E e2, E e3, E e4, E e5) {
117    return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4, e5));
118  }
119
120  /**
121   * Returns an immutable sorted multiset containing the given elements sorted by their natural
122   * ordering.
123   *
124   * @throws NullPointerException if any element is null
125   */
126  public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(
127      E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) {
128    int size = remaining.length + 6;
129    List<E> all = Lists.newArrayListWithCapacity(size);
130    Collections.addAll(all, e1, e2, e3, e4, e5, e6);
131    Collections.addAll(all, remaining);
132    return copyOf(Ordering.natural(), all);
133  }
134
135  /**
136   * Returns an immutable sorted multiset containing the given elements sorted by their natural
137   * ordering.
138   *
139   * @throws NullPointerException if any of {@code elements} is null
140   */
141  public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> copyOf(E[] elements) {
142    return copyOf(Ordering.natural(), Arrays.asList(elements));
143  }
144
145  /**
146   * Returns an immutable sorted multiset containing the given elements sorted by their natural
147   * ordering. To create a copy of a {@code SortedMultiset} that preserves the comparator, call
148   * {@link #copyOfSorted} instead. This method iterates over {@code elements} at most once.
149   *
150   * <p>Note that if {@code s} is a {@code Multiset<String>}, then {@code
151   * ImmutableSortedMultiset.copyOf(s)} returns an {@code ImmutableSortedMultiset<String>}
152   * containing each of the strings in {@code s}, while {@code ImmutableSortedMultiset.of(s)}
153   * returns an {@code ImmutableSortedMultiset<Multiset<String>>} containing one element (the given
154   * multiset itself).
155   *
156   * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
157   * safe to do so. The exact circumstances under which a copy will or will not be performed are
158   * undocumented and subject to change.
159   *
160   * <p>This method is not type-safe, as it may be called on elements that are not mutually
161   * comparable.
162   *
163   * @throws ClassCastException if the elements are not mutually comparable
164   * @throws NullPointerException if any of {@code elements} is null
165   */
166  public static <E> ImmutableSortedMultiset<E> copyOf(Iterable<? extends E> elements) {
167    // Hack around E not being a subtype of Comparable.
168    // Unsafe, see ImmutableSortedMultisetFauxverideShim.
169    @SuppressWarnings("unchecked")
170    Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
171    return copyOf(naturalOrder, elements);
172  }
173
174  /**
175   * Returns an immutable sorted multiset containing the given elements sorted by their natural
176   * ordering.
177   *
178   * <p>This method is not type-safe, as it may be called on elements that are not mutually
179   * comparable.
180   *
181   * @throws ClassCastException if the elements are not mutually comparable
182   * @throws NullPointerException if any of {@code elements} is null
183   */
184  public static <E> ImmutableSortedMultiset<E> copyOf(Iterator<? extends E> elements) {
185    // Hack around E not being a subtype of Comparable.
186    // Unsafe, see ImmutableSortedMultisetFauxverideShim.
187    @SuppressWarnings("unchecked")
188    Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
189    return copyOf(naturalOrder, elements);
190  }
191
192  /**
193   * Returns an immutable sorted multiset containing the given elements sorted by the given {@code
194   * Comparator}.
195   *
196   * @throws NullPointerException if {@code comparator} or any of {@code elements} is null
197   */
198  public static <E> ImmutableSortedMultiset<E> copyOf(
199      Comparator<? super E> comparator, Iterator<? extends E> elements) {
200    checkNotNull(comparator);
201    return new Builder<E>(comparator).addAll(elements).build();
202  }
203
204  /**
205   * Returns an immutable sorted multiset containing the given elements sorted by the given {@code
206   * Comparator}. This method iterates over {@code elements} at most once.
207   *
208   * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
209   * safe to do so. The exact circumstances under which a copy will or will not be performed are
210   * undocumented and subject to change.
211   *
212   * @throws NullPointerException if {@code comparator} or any of {@code elements} is null
213   */
214  @SuppressWarnings("unchecked")
215  public static <E> ImmutableSortedMultiset<E> copyOf(
216      Comparator<? super E> comparator, Iterable<? extends E> elements) {
217    if (elements instanceof ImmutableSortedMultiset) {
218      @SuppressWarnings("unchecked") // immutable collections are always safe for covariant casts
219      ImmutableSortedMultiset<E> multiset = (ImmutableSortedMultiset<E>) elements;
220      if (comparator.equals(multiset.comparator())) {
221        if (multiset.isPartialView()) {
222          return copyOfSortedEntries(comparator, multiset.entrySet().asList());
223        } else {
224          return multiset;
225        }
226      }
227    }
228    return new ImmutableSortedMultiset.Builder<E>(comparator).addAll(elements).build();
229  }
230
231  /**
232   * Returns an immutable sorted multiset containing the elements of a sorted multiset, sorted by
233   * the same {@code Comparator}. That behavior differs from {@link #copyOf(Iterable)}, which always
234   * uses the natural ordering of the elements.
235   *
236   * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
237   * safe to do so. The exact circumstances under which a copy will or will not be performed are
238   * undocumented and subject to change.
239   *
240   * <p>This method is safe to use even when {@code sortedMultiset} is a synchronized or concurrent
241   * collection that is currently being modified by another thread.
242   *
243   * @throws NullPointerException if {@code sortedMultiset} or any of its elements is null
244   */
245  public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) {
246    return copyOfSortedEntries(
247        sortedMultiset.comparator(), Lists.newArrayList(sortedMultiset.entrySet()));
248  }
249
250  private static <E> ImmutableSortedMultiset<E> copyOfSortedEntries(
251      Comparator<? super E> comparator, Collection<Entry<E>> entries) {
252    if (entries.isEmpty()) {
253      return emptyMultiset(comparator);
254    }
255    ImmutableList.Builder<E> elementsBuilder = new ImmutableList.Builder<E>(entries.size());
256    long[] cumulativeCounts = new long[entries.size() + 1];
257    int i = 0;
258    for (Entry<E> entry : entries) {
259      elementsBuilder.add(entry.getElement());
260      cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount();
261      i++;
262    }
263    return new RegularImmutableSortedMultiset<E>(
264        new RegularImmutableSortedSet<E>(elementsBuilder.build(), comparator),
265        cumulativeCounts,
266        0,
267        entries.size());
268  }
269
270  @SuppressWarnings("unchecked")
271  static <E> ImmutableSortedMultiset<E> emptyMultiset(Comparator<? super E> comparator) {
272    if (Ordering.natural().equals(comparator)) {
273      return (ImmutableSortedMultiset<E>) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET;
274    } else {
275      return new RegularImmutableSortedMultiset<E>(comparator);
276    }
277  }
278
279  ImmutableSortedMultiset() {}
280
281  @Override
282  public final Comparator<? super E> comparator() {
283    return elementSet().comparator();
284  }
285
286  @Override
287  public abstract ImmutableSortedSet<E> elementSet();
288
289  @LazyInit @CheckForNull transient ImmutableSortedMultiset<E> descendingMultiset;
290
291  @Override
292  public ImmutableSortedMultiset<E> descendingMultiset() {
293    ImmutableSortedMultiset<E> result = descendingMultiset;
294    if (result == null) {
295      return descendingMultiset =
296          this.isEmpty()
297              ? emptyMultiset(Ordering.from(comparator()).reverse())
298              : new DescendingImmutableSortedMultiset<E>(this);
299    }
300    return result;
301  }
302
303  /**
304   * {@inheritDoc}
305   *
306   * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}.
307   *
308   * @throws UnsupportedOperationException always
309   * @deprecated Unsupported operation.
310   */
311  @CanIgnoreReturnValue
312  @Deprecated
313  @Override
314  @DoNotCall("Always throws UnsupportedOperationException")
315  @CheckForNull
316  public final Entry<E> pollFirstEntry() {
317    throw new UnsupportedOperationException();
318  }
319
320  /**
321   * {@inheritDoc}
322   *
323   * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}.
324   *
325   * @throws UnsupportedOperationException always
326   * @deprecated Unsupported operation.
327   */
328  @CanIgnoreReturnValue
329  @Deprecated
330  @Override
331  @DoNotCall("Always throws UnsupportedOperationException")
332  @CheckForNull
333  public final Entry<E> pollLastEntry() {
334    throw new UnsupportedOperationException();
335  }
336
337  @Override
338  public abstract ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType);
339
340  @Override
341  public ImmutableSortedMultiset<E> subMultiset(
342      E lowerBound, BoundType lowerBoundType, E upperBound, BoundType upperBoundType) {
343    checkArgument(
344        comparator().compare(lowerBound, upperBound) <= 0,
345        "Expected lowerBound <= upperBound but %s > %s",
346        lowerBound,
347        upperBound);
348    return tailMultiset(lowerBound, lowerBoundType).headMultiset(upperBound, upperBoundType);
349  }
350
351  @Override
352  public abstract ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType);
353
354  /**
355   * Returns a builder that creates immutable sorted multisets with an explicit comparator. If the
356   * comparator has a more general type than the set being generated, such as creating a {@code
357   * SortedMultiset<Integer>} with a {@code Comparator<Number>}, use the {@link Builder} constructor
358   * instead.
359   *
360   * @throws NullPointerException if {@code comparator} is null
361   */
362  public static <E> Builder<E> orderedBy(Comparator<E> comparator) {
363    return new Builder<E>(comparator);
364  }
365
366  /**
367   * Returns a builder that creates immutable sorted multisets whose elements are ordered by the
368   * reverse of their natural ordering.
369   *
370   * <p>Note: the type parameter {@code E} extends {@code Comparable<?>} rather than {@code
371   * Comparable<? super E>} as a workaround for javac <a
372   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>.
373   */
374  public static <E extends Comparable<?>> Builder<E> reverseOrder() {
375    return new Builder<E>(Ordering.<E>natural().reverse());
376  }
377
378  /**
379   * Returns a builder that creates immutable sorted multisets whose elements are ordered by their
380   * natural ordering. The sorted multisets use {@link Ordering#natural()} as the comparator. This
381   * method provides more type-safety than {@link #builder}, as it can be called only for classes
382   * that implement {@link Comparable}.
383   *
384   * <p>Note: the type parameter {@code E} extends {@code Comparable<?>} rather than {@code
385   * Comparable<? super E>} as a workaround for javac <a
386   * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>.
387   */
388  public static <E extends Comparable<?>> Builder<E> naturalOrder() {
389    return new Builder<E>(Ordering.natural());
390  }
391
392  /**
393   * A builder for creating immutable multiset instances, especially {@code public static final}
394   * multisets ("constant multisets"). Example:
395   *
396   * <pre>{@code
397   * public static final ImmutableSortedMultiset<Bean> BEANS =
398   *     new ImmutableSortedMultiset.Builder<Bean>(colorComparator())
399   *         .addCopies(Bean.COCOA, 4)
400   *         .addCopies(Bean.GARDEN, 6)
401   *         .addCopies(Bean.RED, 8)
402   *         .addCopies(Bean.BLACK_EYED, 10)
403   *         .build();
404   * }</pre>
405   *
406   * <p>Builder instances can be reused; it is safe to call {@link #build} multiple times to build
407   * multiple multisets in series.
408   *
409   * @since 12.0
410   */
411  public static class Builder<E> extends ImmutableMultiset.Builder<E> {
412    /*
413     * We keep an array of elements and counts.  Periodically -- when we need more room in the
414     * array, or when we're building, or the like -- we sort, deduplicate, and combine the counts.
415     * Negative counts indicate a setCount operation with ~counts[i].
416     */
417
418    private final Comparator<? super E> comparator;
419
420    @VisibleForTesting E[] elements;
421    private int[] counts;
422
423    /*
424     * The number of used positions in the elements array.  We deduplicate periodically, so this
425     * may fluctuate up and down.
426     */
427    private int length;
428
429    // True if we just called build() and the elements array is being used by a created ISM, meaning
430    // we shouldn't modify that array further.
431    private boolean forceCopyElements;
432
433    /**
434     * Creates a new builder. The returned builder is equivalent to the builder generated by {@link
435     * ImmutableSortedMultiset#orderedBy(Comparator)}.
436     */
437    @SuppressWarnings("unchecked")
438    public Builder(Comparator<? super E> comparator) {
439      super(true); // doesn't allocate hash table in supertype
440      this.comparator = checkNotNull(comparator);
441      this.elements = (E[]) new Object[ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY];
442      this.counts = new int[ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY];
443    }
444
445    /** Check if we need to do deduplication and coalescing, and if so, do it. */
446    private void maintenance() {
447      if (length == elements.length) {
448        dedupAndCoalesce(true);
449      } else if (forceCopyElements) {
450        this.elements = Arrays.copyOf(elements, elements.length);
451        // we don't currently need to copy the counts array, because we don't use it directly
452        // in built ISMs
453      }
454      forceCopyElements = false;
455    }
456
457    private void dedupAndCoalesce(boolean maybeExpand) {
458      if (length == 0) {
459        return;
460      }
461      E[] sortedElements = Arrays.copyOf(elements, length);
462      Arrays.sort(sortedElements, comparator);
463      int uniques = 1;
464      for (int i = 1; i < sortedElements.length; i++) {
465        if (comparator.compare(sortedElements[uniques - 1], sortedElements[i]) < 0) {
466          sortedElements[uniques] = sortedElements[i];
467          uniques++;
468        }
469      }
470      Arrays.fill(sortedElements, uniques, length, null);
471      if (maybeExpand && uniques * 4 > length * 3) {
472        // lots of nonduplicated elements, expand the array by 50%
473        sortedElements =
474            Arrays.copyOf(sortedElements, IntMath.saturatedAdd(length, length / 2 + 1));
475      }
476      int[] sortedCounts = new int[sortedElements.length];
477      for (int i = 0; i < length; i++) {
478        int index = Arrays.binarySearch(sortedElements, 0, uniques, elements[i], comparator);
479        if (counts[i] >= 0) {
480          sortedCounts[index] += counts[i];
481        } else {
482          sortedCounts[index] = ~counts[i];
483        }
484      }
485      // Note that we're not getting rid, yet, of elements with count 0.  We'll do that in build().
486      this.elements = sortedElements;
487      this.counts = sortedCounts;
488      this.length = uniques;
489    }
490
491    /**
492     * Adds {@code element} to the {@code ImmutableSortedMultiset}.
493     *
494     * @param element the element to add
495     * @return this {@code Builder} object
496     * @throws NullPointerException if {@code element} is null
497     */
498    @CanIgnoreReturnValue
499    @Override
500    public Builder<E> add(E element) {
501      return addCopies(element, 1);
502    }
503
504    /**
505     * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}.
506     *
507     * @param elements the elements to add
508     * @return this {@code Builder} object
509     * @throws NullPointerException if {@code elements} is null or contains a null element
510     */
511    @CanIgnoreReturnValue
512    @Override
513    public Builder<E> add(E... elements) {
514      for (E element : elements) {
515        add(element);
516      }
517      return this;
518    }
519
520    /**
521     * Adds a number of occurrences of an element to this {@code ImmutableSortedMultiset}.
522     *
523     * @param element the element to add
524     * @param occurrences the number of occurrences of the element to add. May be zero, in which
525     *     case no change will be made.
526     * @return this {@code Builder} object
527     * @throws NullPointerException if {@code element} is null
528     * @throws IllegalArgumentException if {@code occurrences} is negative, or if this operation
529     *     would result in more than {@link Integer#MAX_VALUE} occurrences of the element
530     */
531    @CanIgnoreReturnValue
532    @Override
533    public Builder<E> addCopies(E element, int occurrences) {
534      checkNotNull(element);
535      CollectPreconditions.checkNonnegative(occurrences, "occurrences");
536      if (occurrences == 0) {
537        return this;
538      }
539      maintenance();
540      elements[length] = element;
541      counts[length] = occurrences;
542      length++;
543      return this;
544    }
545
546    /**
547     * Adds or removes the necessary occurrences of an element such that the element attains the
548     * desired count.
549     *
550     * @param element the element to add or remove occurrences of
551     * @param count the desired count of the element in this multiset
552     * @return this {@code Builder} object
553     * @throws NullPointerException if {@code element} is null
554     * @throws IllegalArgumentException if {@code count} is negative
555     */
556    @CanIgnoreReturnValue
557    @Override
558    public Builder<E> setCount(E element, int count) {
559      checkNotNull(element);
560      CollectPreconditions.checkNonnegative(count, "count");
561      maintenance();
562      elements[length] = element;
563      counts[length] = ~count;
564      length++;
565      return this;
566    }
567
568    /**
569     * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}.
570     *
571     * @param elements the {@code Iterable} to add to the {@code ImmutableSortedMultiset}
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> addAll(Iterable<? extends E> elements) {
578      if (elements instanceof Multiset) {
579        for (Entry<? extends E> entry : ((Multiset<? extends E>) elements).entrySet()) {
580          addCopies(entry.getElement(), entry.getCount());
581        }
582      } else {
583        for (E e : elements) {
584          add(e);
585        }
586      }
587      return this;
588    }
589
590    /**
591     * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}.
592     *
593     * @param elements the elements to add to the {@code ImmutableSortedMultiset}
594     * @return this {@code Builder} object
595     * @throws NullPointerException if {@code elements} is null or contains a null element
596     */
597    @CanIgnoreReturnValue
598    @Override
599    public Builder<E> addAll(Iterator<? extends E> elements) {
600      while (elements.hasNext()) {
601        add(elements.next());
602      }
603      return this;
604    }
605
606    private void dedupAndCoalesceAndDeleteEmpty() {
607      dedupAndCoalesce(false);
608
609      // If there was a setCount(elem, 0), those elements are still present.  Eliminate them.
610      int size = 0;
611      for (int i = 0; i < length; i++) {
612        if (counts[i] > 0) {
613          elements[size] = elements[i];
614          counts[size] = counts[i];
615          size++;
616        }
617      }
618      Arrays.fill(elements, size, length, null);
619      Arrays.fill(counts, size, length, 0);
620      length = size;
621    }
622
623    /**
624     * Returns a newly-created {@code ImmutableSortedMultiset} based on the contents of the {@code
625     * Builder}.
626     */
627    @Override
628    public ImmutableSortedMultiset<E> build() {
629      dedupAndCoalesceAndDeleteEmpty();
630      if (length == 0) {
631        return emptyMultiset(comparator);
632      }
633      RegularImmutableSortedSet<E> elementSet =
634          (RegularImmutableSortedSet<E>) ImmutableSortedSet.construct(comparator, length, elements);
635      long[] cumulativeCounts = new long[length + 1];
636      for (int i = 0; i < length; i++) {
637        cumulativeCounts[i + 1] = cumulativeCounts[i] + counts[i];
638      }
639      forceCopyElements = true;
640      return new RegularImmutableSortedMultiset<E>(elementSet, cumulativeCounts, 0, length);
641    }
642  }
643
644  @J2ktIncompatible // serialization
645  private static final class SerializedForm<E> implements Serializable {
646    final Comparator<? super E> comparator;
647    final E[] elements;
648    final int[] counts;
649
650    @SuppressWarnings("unchecked")
651    SerializedForm(SortedMultiset<E> multiset) {
652      this.comparator = multiset.comparator();
653      int n = multiset.entrySet().size();
654      elements = (E[]) new Object[n];
655      counts = new int[n];
656      int i = 0;
657      for (Entry<E> entry : multiset.entrySet()) {
658        elements[i] = entry.getElement();
659        counts[i] = entry.getCount();
660        i++;
661      }
662    }
663
664    Object readResolve() {
665      int n = elements.length;
666      Builder<E> builder = new Builder<>(comparator);
667      for (int i = 0; i < n; i++) {
668        builder.addCopies(elements[i], counts[i]);
669      }
670      return builder.build();
671    }
672  }
673
674  @Override
675  @J2ktIncompatible // serialization
676  Object writeReplace() {
677    return new SerializedForm<E>(this);
678  }
679
680  @J2ktIncompatible // java.io.ObjectInputStream
681  private void readObject(ObjectInputStream stream) throws InvalidObjectException {
682    throw new InvalidObjectException("Use SerializedForm");
683  }
684}