001/*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect;
018
019import static com.google.common.base.Preconditions.checkArgument;
020import static com.google.common.base.Preconditions.checkNotNull;
021import static com.google.common.base.Preconditions.checkState;
022import static com.google.common.collect.CollectPreconditions.checkNonnegative;
023import static com.google.common.collect.NullnessCasts.uncheckedCastNullableTToT;
024import static java.lang.Math.max;
025import static java.util.Objects.requireNonNull;
026
027import com.google.common.annotations.GwtCompatible;
028import com.google.common.annotations.GwtIncompatible;
029import com.google.common.annotations.J2ktIncompatible;
030import com.google.common.base.MoreObjects;
031import com.google.common.primitives.Ints;
032import com.google.errorprone.annotations.CanIgnoreReturnValue;
033import java.io.IOException;
034import java.io.ObjectInputStream;
035import java.io.ObjectOutputStream;
036import java.io.Serializable;
037import java.util.Comparator;
038import java.util.ConcurrentModificationException;
039import java.util.Iterator;
040import java.util.NoSuchElementException;
041import java.util.function.ObjIntConsumer;
042import org.jspecify.annotations.Nullable;
043
044/**
045 * A multiset which maintains the ordering of its elements, according to either their natural order
046 * or an explicit {@link Comparator}. In all cases, this implementation uses {@link
047 * Comparable#compareTo} or {@link Comparator#compare} instead of {@link Object#equals} to determine
048 * equivalence of instances.
049 *
050 * <p><b>Warning:</b> The comparison must be <i>consistent with equals</i> as explained by the
051 * {@link Comparable} class specification. Otherwise, the resulting multiset will violate the {@link
052 * java.util.Collection} contract, which is specified in terms of {@link Object#equals}.
053 *
054 * <p>See the Guava User Guide article on <a href=
055 * "https://github.com/google/guava/wiki/NewCollectionTypesExplained#multiset">{@code Multiset}</a>.
056 *
057 * @author Louis Wasserman
058 * @author Jared Levy
059 * @since 2.0
060 */
061@GwtCompatible
062public final class TreeMultiset<E extends @Nullable Object> extends AbstractSortedMultiset<E>
063    implements Serializable {
064
065  /**
066   * Creates a new, empty multiset, sorted according to the elements' natural order. All elements
067   * inserted into the multiset must implement the {@code Comparable} interface. Furthermore, all
068   * such elements must be <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
069   * {@code ClassCastException} for any elements {@code e1} and {@code e2} in the multiset. If the
070   * user attempts to add an element to the multiset that violates this constraint (for example, the
071   * user attempts to add a string element to a set whose elements are integers), the {@code
072   * add(Object)} call will throw a {@code ClassCastException}.
073   *
074   * <p>The type specification is {@code <E extends Comparable>}, instead of the more specific
075   * {@code <E extends Comparable<? super E>>}, to support classes defined without generics.
076   */
077  @SuppressWarnings("rawtypes") // https://github.com/google/guava/issues/989
078  public static <E extends Comparable> TreeMultiset<E> create() {
079    return new TreeMultiset<>(Ordering.natural());
080  }
081
082  /**
083   * Creates a new, empty multiset, sorted according to the specified comparator. All elements
084   * inserted into the multiset must be <i>mutually comparable</i> by the specified comparator:
085   * {@code comparator.compare(e1, e2)} must not throw a {@code ClassCastException} for any elements
086   * {@code e1} and {@code e2} in the multiset. If the user attempts to add an element to the
087   * multiset that violates this constraint, the {@code add(Object)} call will throw a {@code
088   * ClassCastException}.
089   *
090   * @param comparator the comparator that will be used to sort this multiset. A null value
091   *     indicates that the elements' <i>natural ordering</i> should be used.
092   */
093  @SuppressWarnings("unchecked")
094  public static <E extends @Nullable Object> TreeMultiset<E> create(
095      @Nullable Comparator<? super E> comparator) {
096    return (comparator == null)
097        ? new TreeMultiset<E>((Comparator) Ordering.natural())
098        : new TreeMultiset<E>(comparator);
099  }
100
101  /**
102   * Creates an empty multiset containing the given initial elements, sorted according to the
103   * elements' natural order.
104   *
105   * <p>This implementation is highly efficient when {@code elements} is itself a {@link Multiset}.
106   *
107   * <p>The type specification is {@code <E extends Comparable>}, instead of the more specific
108   * {@code <E extends Comparable<? super E>>}, to support classes defined without generics.
109   */
110  @SuppressWarnings("rawtypes") // https://github.com/google/guava/issues/989
111  public static <E extends Comparable> TreeMultiset<E> create(Iterable<? extends E> elements) {
112    TreeMultiset<E> multiset = create();
113    Iterables.addAll(multiset, elements);
114    return multiset;
115  }
116
117  private final transient Reference<AvlNode<E>> rootReference;
118  private final transient GeneralRange<E> range;
119  private final transient AvlNode<E> header;
120
121  /**
122   * An instance created in {@link #readObject} to be returned from {@link #readResolve}. This field
123   * is used only by those methods, and it is never set in a "normal" instance.
124   *
125   * <p>For more background, see {@code ConcurrentHashMultiset.deserializationReplacement}.
126   */
127  private transient @Nullable TreeMultiset<E> deserializationReplacement;
128
129  private TreeMultiset(
130      Reference<AvlNode<E>> rootReference, GeneralRange<E> range, AvlNode<E> endLink) {
131    super(range.comparator());
132    this.rootReference = rootReference;
133    this.range = range;
134    this.header = endLink;
135  }
136
137  private TreeMultiset(Comparator<? super E> comparator) {
138    super(comparator);
139    this.range = GeneralRange.all(comparator);
140    this.header = new AvlNode<>();
141    successor(header, header);
142    this.rootReference = new Reference<>();
143  }
144
145  /** A function which can be summed across a subtree. */
146  private enum Aggregate {
147    SIZE {
148      @Override
149      int nodeAggregate(AvlNode<?> node) {
150        return node.elemCount;
151      }
152
153      @Override
154      long treeAggregate(@Nullable AvlNode<?> root) {
155        return (root == null) ? 0 : root.totalCount;
156      }
157    },
158    DISTINCT {
159      @Override
160      int nodeAggregate(AvlNode<?> node) {
161        return 1;
162      }
163
164      @Override
165      long treeAggregate(@Nullable AvlNode<?> root) {
166        return (root == null) ? 0 : root.distinctElements;
167      }
168    };
169
170    abstract int nodeAggregate(AvlNode<?> node);
171
172    abstract long treeAggregate(@Nullable AvlNode<?> root);
173  }
174
175  private long aggregateForEntries(Aggregate aggr) {
176    AvlNode<E> root = rootReference.get();
177    long total = aggr.treeAggregate(root);
178    if (range.hasLowerBound()) {
179      total -= aggregateBelowRange(aggr, root);
180    }
181    if (range.hasUpperBound()) {
182      total -= aggregateAboveRange(aggr, root);
183    }
184    return total;
185  }
186
187  private long aggregateBelowRange(Aggregate aggr, @Nullable AvlNode<E> node) {
188    if (node == null) {
189      return 0;
190    }
191    // The cast is safe because we call this method only if hasLowerBound().
192    int cmp =
193        comparator()
194            .compare(uncheckedCastNullableTToT(range.getLowerEndpoint()), node.getElement());
195    if (cmp < 0) {
196      return aggregateBelowRange(aggr, node.left);
197    } else if (cmp == 0) {
198      switch (range.getLowerBoundType()) {
199        case OPEN:
200          return aggr.nodeAggregate(node) + aggr.treeAggregate(node.left);
201        case CLOSED:
202          return aggr.treeAggregate(node.left);
203      }
204      throw new AssertionError();
205    } else {
206      return aggr.treeAggregate(node.left)
207          + aggr.nodeAggregate(node)
208          + aggregateBelowRange(aggr, node.right);
209    }
210  }
211
212  private long aggregateAboveRange(Aggregate aggr, @Nullable AvlNode<E> node) {
213    if (node == null) {
214      return 0;
215    }
216    // The cast is safe because we call this method only if hasUpperBound().
217    int cmp =
218        comparator()
219            .compare(uncheckedCastNullableTToT(range.getUpperEndpoint()), node.getElement());
220    if (cmp > 0) {
221      return aggregateAboveRange(aggr, node.right);
222    } else if (cmp == 0) {
223      switch (range.getUpperBoundType()) {
224        case OPEN:
225          return aggr.nodeAggregate(node) + aggr.treeAggregate(node.right);
226        case CLOSED:
227          return aggr.treeAggregate(node.right);
228      }
229      throw new AssertionError();
230    } else {
231      return aggr.treeAggregate(node.right)
232          + aggr.nodeAggregate(node)
233          + aggregateAboveRange(aggr, node.left);
234    }
235  }
236
237  @Override
238  public int size() {
239    return Ints.saturatedCast(aggregateForEntries(Aggregate.SIZE));
240  }
241
242  @Override
243  int distinctElements() {
244    return Ints.saturatedCast(aggregateForEntries(Aggregate.DISTINCT));
245  }
246
247  private static int distinctElements(@Nullable AvlNode<?> node) {
248    return (node == null) ? 0 : node.distinctElements;
249  }
250
251  @Override
252  public int count(@Nullable Object element) {
253    try {
254      @SuppressWarnings("unchecked")
255      E e = (E) element;
256      AvlNode<E> root = rootReference.get();
257      if (!range.contains(e) || root == null) {
258        return 0;
259      }
260      return root.count(comparator(), e);
261    } catch (ClassCastException | NullPointerException e) {
262      return 0;
263    }
264  }
265
266  @CanIgnoreReturnValue
267  @Override
268  public int add(@ParametricNullness E element, int occurrences) {
269    checkNonnegative(occurrences, "occurrences");
270    if (occurrences == 0) {
271      return count(element);
272    }
273    checkArgument(range.contains(element));
274    AvlNode<E> root = rootReference.get();
275    if (root == null) {
276      int unused = comparator().compare(element, element);
277      AvlNode<E> newRoot = new AvlNode<>(element, occurrences);
278      successor(header, newRoot, header);
279      rootReference.checkAndSet(root, newRoot);
280      return 0;
281    }
282    int[] result = new int[1]; // used as a mutable int reference to hold result
283    AvlNode<E> newRoot = root.add(comparator(), element, occurrences, result);
284    rootReference.checkAndSet(root, newRoot);
285    return result[0];
286  }
287
288  @CanIgnoreReturnValue
289  @Override
290  public int remove(@Nullable Object element, int occurrences) {
291    checkNonnegative(occurrences, "occurrences");
292    if (occurrences == 0) {
293      return count(element);
294    }
295    AvlNode<E> root = rootReference.get();
296    int[] result = new int[1]; // used as a mutable int reference to hold result
297    AvlNode<E> newRoot;
298    try {
299      @SuppressWarnings("unchecked")
300      E e = (E) element;
301      if (!range.contains(e) || root == null) {
302        return 0;
303      }
304      newRoot = root.remove(comparator(), e, occurrences, result);
305    } catch (ClassCastException | NullPointerException e) {
306      return 0;
307    }
308    rootReference.checkAndSet(root, newRoot);
309    return result[0];
310  }
311
312  @CanIgnoreReturnValue
313  @Override
314  public int setCount(@ParametricNullness E element, int count) {
315    checkNonnegative(count, "count");
316    if (!range.contains(element)) {
317      checkArgument(count == 0);
318      return 0;
319    }
320
321    AvlNode<E> root = rootReference.get();
322    if (root == null) {
323      if (count > 0) {
324        add(element, count);
325      }
326      return 0;
327    }
328    int[] result = new int[1]; // used as a mutable int reference to hold result
329    AvlNode<E> newRoot = root.setCount(comparator(), element, count, result);
330    rootReference.checkAndSet(root, newRoot);
331    return result[0];
332  }
333
334  @CanIgnoreReturnValue
335  @Override
336  public boolean setCount(@ParametricNullness E element, int oldCount, int newCount) {
337    checkNonnegative(newCount, "newCount");
338    checkNonnegative(oldCount, "oldCount");
339    checkArgument(range.contains(element));
340
341    AvlNode<E> root = rootReference.get();
342    if (root == null) {
343      if (oldCount == 0) {
344        if (newCount > 0) {
345          add(element, newCount);
346        }
347        return true;
348      } else {
349        return false;
350      }
351    }
352    int[] result = new int[1]; // used as a mutable int reference to hold result
353    AvlNode<E> newRoot = root.setCount(comparator(), element, oldCount, newCount, result);
354    rootReference.checkAndSet(root, newRoot);
355    return result[0] == oldCount;
356  }
357
358  @Override
359  public void clear() {
360    if (!range.hasLowerBound() && !range.hasUpperBound()) {
361      // We can do this in O(n) rather than removing one by one, which could force rebalancing.
362      for (AvlNode<E> current = header.succ(); current != header; ) {
363        AvlNode<E> next = current.succ();
364
365        current.elemCount = 0;
366        // Also clear these fields so that one deleted Entry doesn't retain all elements.
367        current.left = null;
368        current.right = null;
369        current.pred = null;
370        current.succ = null;
371
372        current = next;
373      }
374      successor(header, header);
375      rootReference.clear();
376    } else {
377      // TODO(cpovirk): Perhaps we can optimize in this case, too?
378      Iterators.clear(entryIterator());
379    }
380  }
381
382  private Entry<E> wrapEntry(AvlNode<E> baseEntry) {
383    return new Multisets.AbstractEntry<E>() {
384      @Override
385      @ParametricNullness
386      public E getElement() {
387        return baseEntry.getElement();
388      }
389
390      @Override
391      public int getCount() {
392        int result = baseEntry.getCount();
393        if (result == 0) {
394          return count(getElement());
395        } else {
396          return result;
397        }
398      }
399    };
400  }
401
402  /** Returns the first node in the tree that is in range. */
403  private @Nullable AvlNode<E> firstNode() {
404    AvlNode<E> root = rootReference.get();
405    if (root == null) {
406      return null;
407    }
408    AvlNode<E> node;
409    if (range.hasLowerBound()) {
410      // The cast is safe because of the hasLowerBound check.
411      E endpoint = uncheckedCastNullableTToT(range.getLowerEndpoint());
412      node = root.ceiling(comparator(), endpoint);
413      if (node == null) {
414        return null;
415      }
416      if (range.getLowerBoundType() == BoundType.OPEN
417          && comparator().compare(endpoint, node.getElement()) == 0) {
418        node = node.succ();
419      }
420    } else {
421      node = header.succ();
422    }
423    return (node == header || !range.contains(node.getElement())) ? null : node;
424  }
425
426  private @Nullable AvlNode<E> lastNode() {
427    AvlNode<E> root = rootReference.get();
428    if (root == null) {
429      return null;
430    }
431    AvlNode<E> node;
432    if (range.hasUpperBound()) {
433      // The cast is safe because of the hasUpperBound check.
434      E endpoint = uncheckedCastNullableTToT(range.getUpperEndpoint());
435      node = root.floor(comparator(), endpoint);
436      if (node == null) {
437        return null;
438      }
439      if (range.getUpperBoundType() == BoundType.OPEN
440          && comparator().compare(endpoint, node.getElement()) == 0) {
441        node = node.pred();
442      }
443    } else {
444      node = header.pred();
445    }
446    return (node == header || !range.contains(node.getElement())) ? null : node;
447  }
448
449  @Override
450  Iterator<E> elementIterator() {
451    return Multisets.elementIterator(entryIterator());
452  }
453
454  @Override
455  Iterator<Entry<E>> entryIterator() {
456    return new Iterator<Entry<E>>() {
457      private @Nullable AvlNode<E> current = firstNode();
458      private @Nullable Entry<E> prevEntry;
459
460      @Override
461      public boolean hasNext() {
462        if (current == null) {
463          return false;
464        } else if (range.tooHigh(current.getElement())) {
465          current = null;
466          return false;
467        } else {
468          return true;
469        }
470      }
471
472      @Override
473      public Entry<E> next() {
474        if (!hasNext()) {
475          throw new NoSuchElementException();
476        }
477        // requireNonNull is safe because current is only nulled out after iteration is complete.
478        Entry<E> result = wrapEntry(requireNonNull(current));
479        prevEntry = result;
480        if (current.succ() == header) {
481          current = null;
482        } else {
483          current = current.succ();
484        }
485        return result;
486      }
487
488      @Override
489      public void remove() {
490        checkState(prevEntry != null, "no calls to next() since the last call to remove()");
491        setCount(prevEntry.getElement(), 0);
492        prevEntry = null;
493      }
494    };
495  }
496
497  @Override
498  Iterator<Entry<E>> descendingEntryIterator() {
499    return new Iterator<Entry<E>>() {
500      private @Nullable AvlNode<E> current = lastNode();
501      private @Nullable Entry<E> prevEntry = null;
502
503      @Override
504      public boolean hasNext() {
505        if (current == null) {
506          return false;
507        } else if (range.tooLow(current.getElement())) {
508          current = null;
509          return false;
510        } else {
511          return true;
512        }
513      }
514
515      @Override
516      public Entry<E> next() {
517        if (!hasNext()) {
518          throw new NoSuchElementException();
519        }
520        // requireNonNull is safe because current is only nulled out after iteration is complete.
521        requireNonNull(current);
522        Entry<E> result = wrapEntry(current);
523        prevEntry = result;
524        if (current.pred() == header) {
525          current = null;
526        } else {
527          current = current.pred();
528        }
529        return result;
530      }
531
532      @Override
533      public void remove() {
534        checkState(prevEntry != null, "no calls to next() since the last call to remove()");
535        setCount(prevEntry.getElement(), 0);
536        prevEntry = null;
537      }
538    };
539  }
540
541  @Override
542  public void forEachEntry(ObjIntConsumer<? super E> action) {
543    checkNotNull(action);
544    for (AvlNode<E> node = firstNode();
545        node != header && node != null && !range.tooHigh(node.getElement());
546        node = node.succ()) {
547      action.accept(node.getElement(), node.getCount());
548    }
549  }
550
551  @Override
552  public Iterator<E> iterator() {
553    return Multisets.iteratorImpl(this);
554  }
555
556  @Override
557  public SortedMultiset<E> headMultiset(@ParametricNullness E upperBound, BoundType boundType) {
558    return new TreeMultiset<>(
559        rootReference,
560        range.intersect(GeneralRange.upTo(comparator(), upperBound, boundType)),
561        header);
562  }
563
564  @Override
565  public SortedMultiset<E> tailMultiset(@ParametricNullness E lowerBound, BoundType boundType) {
566    return new TreeMultiset<>(
567        rootReference,
568        range.intersect(GeneralRange.downTo(comparator(), lowerBound, boundType)),
569        header);
570  }
571
572  private static final class Reference<T> {
573    private @Nullable T value;
574
575    @Nullable T get() {
576      return value;
577    }
578
579    void checkAndSet(@Nullable T expected, @Nullable T newValue) {
580      if (value != expected) {
581        throw new ConcurrentModificationException();
582      }
583      value = newValue;
584    }
585
586    void clear() {
587      value = null;
588    }
589  }
590
591  private static final class AvlNode<E extends @Nullable Object> {
592    /*
593     * For "normal" nodes, the type of this field is `E`, not `@Nullable E` (though note that E is a
594     * type that can include null, as in a TreeMultiset<@Nullable String>).
595     *
596     * For the header node, though, this field contains `null`, regardless of the type of the
597     * multiset.
598     *
599     * Most code that operates on an AvlNode never operates on the header node. Such code can access
600     * the elem field without a null check by calling getElement().
601     */
602    private final @Nullable E elem;
603
604    // elemCount is 0 iff this node has been deleted.
605    private int elemCount;
606
607    private int distinctElements;
608    private long totalCount;
609    private int height;
610    private @Nullable AvlNode<E> left;
611    private @Nullable AvlNode<E> right;
612    /*
613     * pred and succ are nullable after construction, but we always call successor() to initialize
614     * them immediately thereafter.
615     *
616     * They may be subsequently nulled out by TreeMultiset.clear(). I think that the only place that
617     * we can reference a node whose fields have been cleared is inside the iterator (and presumably
618     * only under concurrent modification).
619     *
620     * To access these fields when you know that they are not null, call the pred() and succ()
621     * methods, which perform null checks before returning the fields.
622     */
623    private @Nullable AvlNode<E> pred;
624    private @Nullable AvlNode<E> succ;
625
626    AvlNode(@ParametricNullness E elem, int elemCount) {
627      checkArgument(elemCount > 0);
628      this.elem = elem;
629      this.elemCount = elemCount;
630      this.totalCount = elemCount;
631      this.distinctElements = 1;
632      this.height = 1;
633      this.left = null;
634      this.right = null;
635    }
636
637    /** Constructor for the header node. */
638    AvlNode() {
639      this.elem = null;
640      this.elemCount = 1;
641    }
642
643    // For discussion of pred() and succ(), see the comment on the pred and succ fields.
644
645    private AvlNode<E> pred() {
646      return requireNonNull(pred);
647    }
648
649    private AvlNode<E> succ() {
650      return requireNonNull(succ);
651    }
652
653    int count(Comparator<? super E> comparator, @ParametricNullness E e) {
654      int cmp = comparator.compare(e, getElement());
655      if (cmp < 0) {
656        return (left == null) ? 0 : left.count(comparator, e);
657      } else if (cmp > 0) {
658        return (right == null) ? 0 : right.count(comparator, e);
659      } else {
660        return elemCount;
661      }
662    }
663
664    @CanIgnoreReturnValue
665    private AvlNode<E> addRightChild(@ParametricNullness E e, int count) {
666      right = new AvlNode<>(e, count);
667      successor(this, right, succ());
668      height = max(2, height);
669      distinctElements++;
670      totalCount += count;
671      return this;
672    }
673
674    @CanIgnoreReturnValue
675    private AvlNode<E> addLeftChild(@ParametricNullness E e, int count) {
676      left = new AvlNode<>(e, count);
677      successor(pred(), left, this);
678      height = max(2, height);
679      distinctElements++;
680      totalCount += count;
681      return this;
682    }
683
684    AvlNode<E> add(
685        Comparator<? super E> comparator, @ParametricNullness E e, int count, int[] result) {
686      /*
687       * It speeds things up considerably to unconditionally add count to totalCount here,
688       * but that destroys failure atomicity in the case of count overflow. =(
689       */
690      int cmp = comparator.compare(e, getElement());
691      if (cmp < 0) {
692        AvlNode<E> initLeft = left;
693        if (initLeft == null) {
694          result[0] = 0;
695          return addLeftChild(e, count);
696        }
697        int initHeight = initLeft.height;
698
699        left = initLeft.add(comparator, e, count, result);
700        if (result[0] == 0) {
701          distinctElements++;
702        }
703        this.totalCount += count;
704        return (left.height == initHeight) ? this : rebalance();
705      } else if (cmp > 0) {
706        AvlNode<E> initRight = right;
707        if (initRight == null) {
708          result[0] = 0;
709          return addRightChild(e, count);
710        }
711        int initHeight = initRight.height;
712
713        right = initRight.add(comparator, e, count, result);
714        if (result[0] == 0) {
715          distinctElements++;
716        }
717        this.totalCount += count;
718        return (right.height == initHeight) ? this : rebalance();
719      }
720
721      // adding count to me!  No rebalance possible.
722      result[0] = elemCount;
723      long resultCount = (long) elemCount + count;
724      checkArgument(resultCount <= Integer.MAX_VALUE);
725      this.elemCount += count;
726      this.totalCount += count;
727      return this;
728    }
729
730    @Nullable AvlNode<E> remove(
731        Comparator<? super E> comparator, @ParametricNullness E e, int count, int[] result) {
732      int cmp = comparator.compare(e, getElement());
733      if (cmp < 0) {
734        AvlNode<E> initLeft = left;
735        if (initLeft == null) {
736          result[0] = 0;
737          return this;
738        }
739
740        left = initLeft.remove(comparator, e, count, result);
741
742        if (result[0] > 0) {
743          if (count >= result[0]) {
744            this.distinctElements--;
745            this.totalCount -= result[0];
746          } else {
747            this.totalCount -= count;
748          }
749        }
750        return (result[0] == 0) ? this : rebalance();
751      } else if (cmp > 0) {
752        AvlNode<E> initRight = right;
753        if (initRight == null) {
754          result[0] = 0;
755          return this;
756        }
757
758        right = initRight.remove(comparator, e, count, result);
759
760        if (result[0] > 0) {
761          if (count >= result[0]) {
762            this.distinctElements--;
763            this.totalCount -= result[0];
764          } else {
765            this.totalCount -= count;
766          }
767        }
768        return rebalance();
769      }
770
771      // removing count from me!
772      result[0] = elemCount;
773      if (count >= elemCount) {
774        return deleteMe();
775      } else {
776        this.elemCount -= count;
777        this.totalCount -= count;
778        return this;
779      }
780    }
781
782    @Nullable AvlNode<E> setCount(
783        Comparator<? super E> comparator, @ParametricNullness E e, int count, int[] result) {
784      int cmp = comparator.compare(e, getElement());
785      if (cmp < 0) {
786        AvlNode<E> initLeft = left;
787        if (initLeft == null) {
788          result[0] = 0;
789          return (count > 0) ? addLeftChild(e, count) : this;
790        }
791
792        left = initLeft.setCount(comparator, e, count, result);
793
794        if (count == 0 && result[0] != 0) {
795          this.distinctElements--;
796        } else if (count > 0 && result[0] == 0) {
797          this.distinctElements++;
798        }
799
800        this.totalCount += count - result[0];
801        return rebalance();
802      } else if (cmp > 0) {
803        AvlNode<E> initRight = right;
804        if (initRight == null) {
805          result[0] = 0;
806          return (count > 0) ? addRightChild(e, count) : this;
807        }
808
809        right = initRight.setCount(comparator, e, count, result);
810
811        if (count == 0 && result[0] != 0) {
812          this.distinctElements--;
813        } else if (count > 0 && result[0] == 0) {
814          this.distinctElements++;
815        }
816
817        this.totalCount += count - result[0];
818        return rebalance();
819      }
820
821      // setting my count
822      result[0] = elemCount;
823      if (count == 0) {
824        return deleteMe();
825      }
826      this.totalCount += count - elemCount;
827      this.elemCount = count;
828      return this;
829    }
830
831    @Nullable AvlNode<E> setCount(
832        Comparator<? super E> comparator,
833        @ParametricNullness E e,
834        int expectedCount,
835        int newCount,
836        int[] result) {
837      int cmp = comparator.compare(e, getElement());
838      if (cmp < 0) {
839        AvlNode<E> initLeft = left;
840        if (initLeft == null) {
841          result[0] = 0;
842          if (expectedCount == 0 && newCount > 0) {
843            return addLeftChild(e, newCount);
844          }
845          return this;
846        }
847
848        left = initLeft.setCount(comparator, e, expectedCount, newCount, result);
849
850        if (result[0] == expectedCount) {
851          if (newCount == 0 && result[0] != 0) {
852            this.distinctElements--;
853          } else if (newCount > 0 && result[0] == 0) {
854            this.distinctElements++;
855          }
856          this.totalCount += newCount - result[0];
857        }
858        return rebalance();
859      } else if (cmp > 0) {
860        AvlNode<E> initRight = right;
861        if (initRight == null) {
862          result[0] = 0;
863          if (expectedCount == 0 && newCount > 0) {
864            return addRightChild(e, newCount);
865          }
866          return this;
867        }
868
869        right = initRight.setCount(comparator, e, expectedCount, newCount, result);
870
871        if (result[0] == expectedCount) {
872          if (newCount == 0 && result[0] != 0) {
873            this.distinctElements--;
874          } else if (newCount > 0 && result[0] == 0) {
875            this.distinctElements++;
876          }
877          this.totalCount += newCount - result[0];
878        }
879        return rebalance();
880      }
881
882      // setting my count
883      result[0] = elemCount;
884      if (expectedCount == elemCount) {
885        if (newCount == 0) {
886          return deleteMe();
887        }
888        this.totalCount += newCount - elemCount;
889        this.elemCount = newCount;
890      }
891      return this;
892    }
893
894    private @Nullable AvlNode<E> deleteMe() {
895      int oldElemCount = this.elemCount;
896      this.elemCount = 0;
897      successor(pred(), succ());
898      if (left == null) {
899        return right;
900      } else if (right == null) {
901        return left;
902      } else if (left.height >= right.height) {
903        AvlNode<E> newTop = pred();
904        // newTop is the maximum node in my left subtree
905        newTop.left = left.removeMax(newTop);
906        newTop.right = right;
907        newTop.distinctElements = distinctElements - 1;
908        newTop.totalCount = totalCount - oldElemCount;
909        return newTop.rebalance();
910      } else {
911        AvlNode<E> newTop = succ();
912        newTop.right = right.removeMin(newTop);
913        newTop.left = left;
914        newTop.distinctElements = distinctElements - 1;
915        newTop.totalCount = totalCount - oldElemCount;
916        return newTop.rebalance();
917      }
918    }
919
920    // Removes the minimum node from this subtree to be reused elsewhere
921    private @Nullable AvlNode<E> removeMin(AvlNode<E> node) {
922      if (left == null) {
923        return right;
924      } else {
925        left = left.removeMin(node);
926        distinctElements--;
927        totalCount -= node.elemCount;
928        return rebalance();
929      }
930    }
931
932    // Removes the maximum node from this subtree to be reused elsewhere
933    private @Nullable AvlNode<E> removeMax(AvlNode<E> node) {
934      if (right == null) {
935        return left;
936      } else {
937        right = right.removeMax(node);
938        distinctElements--;
939        totalCount -= node.elemCount;
940        return rebalance();
941      }
942    }
943
944    private void recomputeMultiset() {
945      this.distinctElements = 1 + distinctElements(left) + distinctElements(right);
946      this.totalCount = elemCount + totalCount(left) + totalCount(right);
947    }
948
949    private void recomputeHeight() {
950      this.height = 1 + max(height(left), height(right));
951    }
952
953    private void recompute() {
954      recomputeMultiset();
955      recomputeHeight();
956    }
957
958    private AvlNode<E> rebalance() {
959      switch (balanceFactor()) {
960        case -2:
961          // requireNonNull is safe because right must exist in order to get a negative factor.
962          requireNonNull(right);
963          if (right.balanceFactor() > 0) {
964            right = right.rotateRight();
965          }
966          return rotateLeft();
967        case 2:
968          // requireNonNull is safe because left must exist in order to get a positive factor.
969          requireNonNull(left);
970          if (left.balanceFactor() < 0) {
971            left = left.rotateLeft();
972          }
973          return rotateRight();
974        default:
975          recomputeHeight();
976          return this;
977      }
978    }
979
980    private int balanceFactor() {
981      return height(left) - height(right);
982    }
983
984    private AvlNode<E> rotateLeft() {
985      checkState(right != null);
986      AvlNode<E> newTop = right;
987      this.right = newTop.left;
988      newTop.left = this;
989      newTop.totalCount = this.totalCount;
990      newTop.distinctElements = this.distinctElements;
991      this.recompute();
992      newTop.recomputeHeight();
993      return newTop;
994    }
995
996    private AvlNode<E> rotateRight() {
997      checkState(left != null);
998      AvlNode<E> newTop = left;
999      this.left = newTop.right;
1000      newTop.right = this;
1001      newTop.totalCount = this.totalCount;
1002      newTop.distinctElements = this.distinctElements;
1003      this.recompute();
1004      newTop.recomputeHeight();
1005      return newTop;
1006    }
1007
1008    private static long totalCount(@Nullable AvlNode<?> node) {
1009      return (node == null) ? 0 : node.totalCount;
1010    }
1011
1012    private static int height(@Nullable AvlNode<?> node) {
1013      return (node == null) ? 0 : node.height;
1014    }
1015
1016    private @Nullable AvlNode<E> ceiling(
1017        Comparator<? super E> comparator, @ParametricNullness E e) {
1018      int cmp = comparator.compare(e, getElement());
1019      if (cmp < 0) {
1020        return (left == null) ? this : MoreObjects.firstNonNull(left.ceiling(comparator, e), this);
1021      } else if (cmp == 0) {
1022        return this;
1023      } else {
1024        return (right == null) ? null : right.ceiling(comparator, e);
1025      }
1026    }
1027
1028    private @Nullable AvlNode<E> floor(Comparator<? super E> comparator, @ParametricNullness E e) {
1029      int cmp = comparator.compare(e, getElement());
1030      if (cmp > 0) {
1031        return (right == null) ? this : MoreObjects.firstNonNull(right.floor(comparator, e), this);
1032      } else if (cmp == 0) {
1033        return this;
1034      } else {
1035        return (left == null) ? null : left.floor(comparator, e);
1036      }
1037    }
1038
1039    @ParametricNullness
1040    E getElement() {
1041      // For discussion of this cast, see the comment on the elem field.
1042      return uncheckedCastNullableTToT(elem);
1043    }
1044
1045    int getCount() {
1046      return elemCount;
1047    }
1048
1049    @Override
1050    public String toString() {
1051      return Multisets.immutableEntry(getElement(), getCount()).toString();
1052    }
1053  }
1054
1055  private static <T extends @Nullable Object> void successor(AvlNode<T> a, AvlNode<T> b) {
1056    a.succ = b;
1057    b.pred = a;
1058  }
1059
1060  private static <T extends @Nullable Object> void successor(
1061      AvlNode<T> a, AvlNode<T> b, AvlNode<T> c) {
1062    successor(a, b);
1063    successor(b, c);
1064  }
1065
1066  /*
1067   * TODO(jlevy): Decide whether entrySet() should return entries with an equals() method that
1068   * calls the comparator to compare the two keys. If that change is made,
1069   * AbstractMultiset.equals() can simply check whether two multisets have equal entry sets.
1070   */
1071
1072  /**
1073   * @serialData the comparator, the number of distinct elements, the first element, its count, the
1074   *     second element, its count, and so on
1075   */
1076  @GwtIncompatible
1077  @J2ktIncompatible
1078    private void writeObject(ObjectOutputStream stream) throws IOException {
1079    stream.defaultWriteObject();
1080    stream.writeObject(elementSet().comparator());
1081    Serialization.writeMultiset(this, stream);
1082  }
1083
1084  @J2ktIncompatible
1085  @GwtIncompatible
1086    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
1087    stream.defaultReadObject();
1088    @SuppressWarnings("unchecked")
1089    // reading data stored by writeObject
1090    Comparator<? super E> comparator = (Comparator<? super E>) requireNonNull(stream.readObject());
1091    deserializationReplacement = new TreeMultiset<>(comparator);
1092    Serialization.populateMultiset(deserializationReplacement, stream);
1093  }
1094
1095  @J2ktIncompatible
1096  @GwtIncompatible
1097    private Object readResolve() {
1098    return requireNonNull(deserializationReplacement); // set by readObject
1099  }
1100
1101  @GwtIncompatible @J2ktIncompatible private static final long serialVersionUID = 1;
1102}