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