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.collect.CollectPreconditions.checkNonnegative;
022import static com.google.common.collect.CollectPreconditions.checkRemove;
023import static java.util.Objects.requireNonNull;
024
025import com.google.common.annotations.Beta;
026import com.google.common.annotations.GwtCompatible;
027import com.google.common.base.Objects;
028import com.google.common.base.Predicate;
029import com.google.common.base.Predicates;
030import com.google.common.collect.Multiset.Entry;
031import com.google.common.math.IntMath;
032import com.google.common.primitives.Ints;
033import com.google.errorprone.annotations.CanIgnoreReturnValue;
034import java.io.Serializable;
035import java.util.Arrays;
036import java.util.Collection;
037import java.util.Collections;
038import java.util.Comparator;
039import java.util.Iterator;
040import java.util.NoSuchElementException;
041import java.util.Set;
042import javax.annotation.CheckForNull;
043import org.checkerframework.checker.nullness.qual.Nullable;
044
045/**
046 * Provides static utility methods for creating and working with {@link Multiset} instances.
047 *
048 * <p>See the Guava User Guide article on <a href=
049 * "https://github.com/google/guava/wiki/CollectionUtilitiesExplained#multisets"> {@code
050 * Multisets}</a>.
051 *
052 * @author Kevin Bourrillion
053 * @author Mike Bostock
054 * @author Louis Wasserman
055 * @since 2.0
056 */
057@GwtCompatible
058@ElementTypesAreNonnullByDefault
059public final class Multisets {
060  private Multisets() {}
061
062  /**
063   * Returns an unmodifiable view of the specified multiset. Query operations on the returned
064   * multiset "read through" to the specified multiset, and attempts to modify the returned multiset
065   * result in an {@link UnsupportedOperationException}.
066   *
067   * <p>The returned multiset will be serializable if the specified multiset is serializable.
068   *
069   * @param multiset the multiset for which an unmodifiable view is to be generated
070   * @return an unmodifiable view of the multiset
071   */
072  public static <E extends @Nullable Object> Multiset<E> unmodifiableMultiset(
073      Multiset<? extends E> multiset) {
074    if (multiset instanceof UnmodifiableMultiset || multiset instanceof ImmutableMultiset) {
075      @SuppressWarnings("unchecked") // Since it's unmodifiable, the covariant cast is safe
076      Multiset<E> result = (Multiset<E>) multiset;
077      return result;
078    }
079    return new UnmodifiableMultiset<E>(checkNotNull(multiset));
080  }
081
082  /**
083   * Simply returns its argument.
084   *
085   * @deprecated no need to use this
086   * @since 10.0
087   */
088  @Deprecated
089  public static <E> Multiset<E> unmodifiableMultiset(ImmutableMultiset<E> multiset) {
090    return checkNotNull(multiset);
091  }
092
093  static class UnmodifiableMultiset<E extends @Nullable Object> extends ForwardingMultiset<E>
094      implements Serializable {
095    final Multiset<? extends E> delegate;
096
097    UnmodifiableMultiset(Multiset<? extends E> delegate) {
098      this.delegate = delegate;
099    }
100
101    @SuppressWarnings("unchecked")
102    @Override
103    protected Multiset<E> delegate() {
104      // This is safe because all non-covariant methods are overridden
105      return (Multiset<E>) delegate;
106    }
107
108    @CheckForNull transient Set<E> elementSet;
109
110    Set<E> createElementSet() {
111      return Collections.<E>unmodifiableSet(delegate.elementSet());
112    }
113
114    @Override
115    public Set<E> elementSet() {
116      Set<E> es = elementSet;
117      return (es == null) ? elementSet = createElementSet() : es;
118    }
119
120    @CheckForNull transient Set<Multiset.Entry<E>> entrySet;
121
122    @SuppressWarnings("unchecked")
123    @Override
124    public Set<Multiset.Entry<E>> entrySet() {
125      Set<Multiset.Entry<E>> es = entrySet;
126      return (es == null)
127          // Safe because the returned set is made unmodifiable and Entry
128          // itself is readonly
129          ? entrySet = (Set) Collections.unmodifiableSet(delegate.entrySet())
130          : es;
131    }
132
133    @Override
134    public Iterator<E> iterator() {
135      return Iterators.<E>unmodifiableIterator(delegate.iterator());
136    }
137
138    @Override
139    public boolean add(@ParametricNullness E element) {
140      throw new UnsupportedOperationException();
141    }
142
143    @Override
144    public int add(@ParametricNullness E element, int occurrences) {
145      throw new UnsupportedOperationException();
146    }
147
148    @Override
149    public boolean addAll(Collection<? extends E> elementsToAdd) {
150      throw new UnsupportedOperationException();
151    }
152
153    @Override
154    public boolean remove(@CheckForNull Object element) {
155      throw new UnsupportedOperationException();
156    }
157
158    @Override
159    public int remove(@CheckForNull Object element, int occurrences) {
160      throw new UnsupportedOperationException();
161    }
162
163    @Override
164    public boolean removeAll(Collection<?> elementsToRemove) {
165      throw new UnsupportedOperationException();
166    }
167
168    @Override
169    public boolean retainAll(Collection<?> elementsToRetain) {
170      throw new UnsupportedOperationException();
171    }
172
173    @Override
174    public void clear() {
175      throw new UnsupportedOperationException();
176    }
177
178    @Override
179    public int setCount(@ParametricNullness E element, int count) {
180      throw new UnsupportedOperationException();
181    }
182
183    @Override
184    public boolean setCount(@ParametricNullness E element, int oldCount, int newCount) {
185      throw new UnsupportedOperationException();
186    }
187
188    private static final long serialVersionUID = 0;
189  }
190
191  /**
192   * Returns an unmodifiable view of the specified sorted multiset. Query operations on the returned
193   * multiset "read through" to the specified multiset, and attempts to modify the returned multiset
194   * result in an {@link UnsupportedOperationException}.
195   *
196   * <p>The returned multiset will be serializable if the specified multiset is serializable.
197   *
198   * @param sortedMultiset the sorted multiset for which an unmodifiable view is to be generated
199   * @return an unmodifiable view of the multiset
200   * @since 11.0
201   */
202  @Beta
203  public static <E extends @Nullable Object> SortedMultiset<E> unmodifiableSortedMultiset(
204      SortedMultiset<E> sortedMultiset) {
205    // it's in its own file so it can be emulated for GWT
206    return new UnmodifiableSortedMultiset<E>(checkNotNull(sortedMultiset));
207  }
208
209  /**
210   * Returns an immutable multiset entry with the specified element and count. The entry will be
211   * serializable if {@code e} is.
212   *
213   * @param e the element to be associated with the returned entry
214   * @param n the count to be associated with the returned entry
215   * @throws IllegalArgumentException if {@code n} is negative
216   */
217  public static <E extends @Nullable Object> Multiset.Entry<E> immutableEntry(
218      @ParametricNullness E e, int n) {
219    return new ImmutableEntry<E>(e, n);
220  }
221
222  static class ImmutableEntry<E extends @Nullable Object> extends AbstractEntry<E>
223      implements Serializable {
224    @ParametricNullness private final E element;
225    private final int count;
226
227    ImmutableEntry(@ParametricNullness E element, int count) {
228      this.element = element;
229      this.count = count;
230      checkNonnegative(count, "count");
231    }
232
233    @Override
234    @ParametricNullness
235    public final E getElement() {
236      return element;
237    }
238
239    @Override
240    public final int getCount() {
241      return count;
242    }
243
244    @CheckForNull
245    public ImmutableEntry<E> nextInBucket() {
246      return null;
247    }
248
249    private static final long serialVersionUID = 0;
250  }
251
252  /**
253   * Returns a view of the elements of {@code unfiltered} that satisfy a predicate. The returned
254   * multiset is a live view of {@code unfiltered}; changes to one affect the other.
255   *
256   * <p>The resulting multiset's iterators, and those of its {@code entrySet()} and {@code
257   * elementSet()}, do not support {@code remove()}. However, all other multiset methods supported
258   * by {@code unfiltered} are supported by the returned multiset. When given an element that
259   * doesn't satisfy the predicate, the multiset's {@code add()} and {@code addAll()} methods throw
260   * an {@link IllegalArgumentException}. When methods such as {@code removeAll()} and {@code
261   * clear()} are called on the filtered multiset, only elements that satisfy the filter will be
262   * removed from the underlying multiset.
263   *
264   * <p>The returned multiset isn't threadsafe or serializable, even if {@code unfiltered} is.
265   *
266   * <p>Many of the filtered multiset's methods, such as {@code size()}, iterate across every
267   * element in the underlying multiset and determine which elements satisfy the filter. When a live
268   * view is <i>not</i> needed, it may be faster to copy the returned multiset and use the copy.
269   *
270   * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>, as documented at
271   * {@link Predicate#apply}. Do not provide a predicate such as {@code
272   * Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. (See {@link
273   * Iterables#filter(Iterable, Class)} for related functionality.)
274   *
275   * @since 14.0
276   */
277  @Beta
278  public static <E extends @Nullable Object> Multiset<E> filter(
279      Multiset<E> unfiltered, Predicate<? super E> predicate) {
280    if (unfiltered instanceof FilteredMultiset) {
281      // Support clear(), removeAll(), and retainAll() when filtering a filtered
282      // collection.
283      FilteredMultiset<E> filtered = (FilteredMultiset<E>) unfiltered;
284      Predicate<E> combinedPredicate = Predicates.<E>and(filtered.predicate, predicate);
285      return new FilteredMultiset<E>(filtered.unfiltered, combinedPredicate);
286    }
287    return new FilteredMultiset<E>(unfiltered, predicate);
288  }
289
290  private static final class FilteredMultiset<E extends @Nullable Object> extends ViewMultiset<E> {
291    final Multiset<E> unfiltered;
292    final Predicate<? super E> predicate;
293
294    FilteredMultiset(Multiset<E> unfiltered, Predicate<? super E> predicate) {
295      this.unfiltered = checkNotNull(unfiltered);
296      this.predicate = checkNotNull(predicate);
297    }
298
299    @Override
300    public UnmodifiableIterator<E> iterator() {
301      return Iterators.filter(unfiltered.iterator(), predicate);
302    }
303
304    @Override
305    Set<E> createElementSet() {
306      return Sets.filter(unfiltered.elementSet(), predicate);
307    }
308
309    @Override
310    Iterator<E> elementIterator() {
311      throw new AssertionError("should never be called");
312    }
313
314    @Override
315    Set<Entry<E>> createEntrySet() {
316      return Sets.filter(
317          unfiltered.entrySet(),
318          new Predicate<Entry<E>>() {
319            @Override
320            public boolean apply(Entry<E> entry) {
321              return predicate.apply(entry.getElement());
322            }
323          });
324    }
325
326    @Override
327    Iterator<Entry<E>> entryIterator() {
328      throw new AssertionError("should never be called");
329    }
330
331    @Override
332    public int count(@CheckForNull Object element) {
333      int count = unfiltered.count(element);
334      if (count > 0) {
335        @SuppressWarnings("unchecked") // element is equal to an E
336        E e = (E) element;
337        return predicate.apply(e) ? count : 0;
338      }
339      return 0;
340    }
341
342    @Override
343    public int add(@ParametricNullness E element, int occurrences) {
344      checkArgument(
345          predicate.apply(element), "Element %s does not match predicate %s", element, predicate);
346      return unfiltered.add(element, occurrences);
347    }
348
349    @Override
350    public int remove(@CheckForNull Object element, int occurrences) {
351      checkNonnegative(occurrences, "occurrences");
352      if (occurrences == 0) {
353        return count(element);
354      } else {
355        return contains(element) ? unfiltered.remove(element, occurrences) : 0;
356      }
357    }
358  }
359
360  /**
361   * Returns the expected number of distinct elements given the specified elements. The number of
362   * distinct elements is only computed if {@code elements} is an instance of {@code Multiset};
363   * otherwise the default value of 11 is returned.
364   */
365  static int inferDistinctElements(Iterable<?> elements) {
366    if (elements instanceof Multiset) {
367      return ((Multiset<?>) elements).elementSet().size();
368    }
369    return 11; // initial capacity will be rounded up to 16
370  }
371
372  /**
373   * Returns an unmodifiable view of the union of two multisets. In the returned multiset, the count
374   * of each element is the <i>maximum</i> of its counts in the two backing multisets. The iteration
375   * order of the returned multiset matches that of the element set of {@code multiset1} followed by
376   * the members of the element set of {@code multiset2} that are not contained in {@code
377   * multiset1}, with repeated occurrences of the same element appearing consecutively.
378   *
379   * <p>Results are undefined if {@code multiset1} and {@code multiset2} are based on different
380   * equivalence relations (as {@code HashMultiset} and {@code TreeMultiset} are).
381   *
382   * @since 14.0
383   */
384  @Beta
385  public static <E extends @Nullable Object> Multiset<E> union(
386      final Multiset<? extends E> multiset1, final Multiset<? extends E> multiset2) {
387    checkNotNull(multiset1);
388    checkNotNull(multiset2);
389
390    return new ViewMultiset<E>() {
391      @Override
392      public boolean contains(@CheckForNull Object element) {
393        return multiset1.contains(element) || multiset2.contains(element);
394      }
395
396      @Override
397      public boolean isEmpty() {
398        return multiset1.isEmpty() && multiset2.isEmpty();
399      }
400
401      @Override
402      public int count(@CheckForNull Object element) {
403        return Math.max(multiset1.count(element), multiset2.count(element));
404      }
405
406      @Override
407      Set<E> createElementSet() {
408        return Sets.union(multiset1.elementSet(), multiset2.elementSet());
409      }
410
411      @Override
412      Iterator<E> elementIterator() {
413        throw new AssertionError("should never be called");
414      }
415
416      @Override
417      Iterator<Entry<E>> entryIterator() {
418        final Iterator<? extends Entry<? extends E>> iterator1 = multiset1.entrySet().iterator();
419        final Iterator<? extends Entry<? extends E>> iterator2 = multiset2.entrySet().iterator();
420        // TODO(lowasser): consider making the entries live views
421        return new AbstractIterator<Entry<E>>() {
422          @Override
423          @CheckForNull
424          protected Entry<E> computeNext() {
425            if (iterator1.hasNext()) {
426              Entry<? extends E> entry1 = iterator1.next();
427              E element = entry1.getElement();
428              int count = Math.max(entry1.getCount(), multiset2.count(element));
429              return immutableEntry(element, count);
430            }
431            while (iterator2.hasNext()) {
432              Entry<? extends E> entry2 = iterator2.next();
433              E element = entry2.getElement();
434              if (!multiset1.contains(element)) {
435                return immutableEntry(element, entry2.getCount());
436              }
437            }
438            return endOfData();
439          }
440        };
441      }
442    };
443  }
444
445  /**
446   * Returns an unmodifiable view of the intersection of two multisets. In the returned multiset,
447   * the count of each element is the <i>minimum</i> of its counts in the two backing multisets,
448   * with elements that would have a count of 0 not included. The iteration order of the returned
449   * multiset matches that of the element set of {@code multiset1}, with repeated occurrences of the
450   * same element appearing consecutively.
451   *
452   * <p>Results are undefined if {@code multiset1} and {@code multiset2} are based on different
453   * equivalence relations (as {@code HashMultiset} and {@code TreeMultiset} are).
454   *
455   * @since 2.0
456   */
457  public static <E extends @Nullable Object> Multiset<E> intersection(
458      final Multiset<E> multiset1, final Multiset<?> multiset2) {
459    checkNotNull(multiset1);
460    checkNotNull(multiset2);
461
462    return new ViewMultiset<E>() {
463      @Override
464      public int count(@CheckForNull Object element) {
465        int count1 = multiset1.count(element);
466        return (count1 == 0) ? 0 : Math.min(count1, multiset2.count(element));
467      }
468
469      @Override
470      Set<E> createElementSet() {
471        return Sets.intersection(multiset1.elementSet(), multiset2.elementSet());
472      }
473
474      @Override
475      Iterator<E> elementIterator() {
476        throw new AssertionError("should never be called");
477      }
478
479      @Override
480      Iterator<Entry<E>> entryIterator() {
481        final Iterator<Entry<E>> iterator1 = multiset1.entrySet().iterator();
482        // TODO(lowasser): consider making the entries live views
483        return new AbstractIterator<Entry<E>>() {
484          @Override
485          @CheckForNull
486          protected Entry<E> computeNext() {
487            while (iterator1.hasNext()) {
488              Entry<E> entry1 = iterator1.next();
489              E element = entry1.getElement();
490              int count = Math.min(entry1.getCount(), multiset2.count(element));
491              if (count > 0) {
492                return immutableEntry(element, count);
493              }
494            }
495            return endOfData();
496          }
497        };
498      }
499    };
500  }
501
502  /**
503   * Returns an unmodifiable view of the sum of two multisets. In the returned multiset, the count
504   * of each element is the <i>sum</i> of its counts in the two backing multisets. The iteration
505   * order of the returned multiset matches that of the element set of {@code multiset1} followed by
506   * the members of the element set of {@code multiset2} that are not contained in {@code
507   * multiset1}, with repeated occurrences of the same element appearing consecutively.
508   *
509   * <p>Results are undefined if {@code multiset1} and {@code multiset2} are based on different
510   * equivalence relations (as {@code HashMultiset} and {@code TreeMultiset} are).
511   *
512   * @since 14.0
513   */
514  @Beta
515  public static <E extends @Nullable Object> Multiset<E> sum(
516      final Multiset<? extends E> multiset1, final Multiset<? extends E> multiset2) {
517    checkNotNull(multiset1);
518    checkNotNull(multiset2);
519
520    // TODO(lowasser): consider making the entries live views
521    return new ViewMultiset<E>() {
522      @Override
523      public boolean contains(@CheckForNull Object element) {
524        return multiset1.contains(element) || multiset2.contains(element);
525      }
526
527      @Override
528      public boolean isEmpty() {
529        return multiset1.isEmpty() && multiset2.isEmpty();
530      }
531
532      @Override
533      public int size() {
534        return IntMath.saturatedAdd(multiset1.size(), multiset2.size());
535      }
536
537      @Override
538      public int count(@CheckForNull Object element) {
539        return multiset1.count(element) + multiset2.count(element);
540      }
541
542      @Override
543      Set<E> createElementSet() {
544        return Sets.union(multiset1.elementSet(), multiset2.elementSet());
545      }
546
547      @Override
548      Iterator<E> elementIterator() {
549        throw new AssertionError("should never be called");
550      }
551
552      @Override
553      Iterator<Entry<E>> entryIterator() {
554        final Iterator<? extends Entry<? extends E>> iterator1 = multiset1.entrySet().iterator();
555        final Iterator<? extends Entry<? extends E>> iterator2 = multiset2.entrySet().iterator();
556        return new AbstractIterator<Entry<E>>() {
557          @Override
558          @CheckForNull
559          protected Entry<E> computeNext() {
560            if (iterator1.hasNext()) {
561              Entry<? extends E> entry1 = iterator1.next();
562              E element = entry1.getElement();
563              int count = entry1.getCount() + multiset2.count(element);
564              return immutableEntry(element, count);
565            }
566            while (iterator2.hasNext()) {
567              Entry<? extends E> entry2 = iterator2.next();
568              E element = entry2.getElement();
569              if (!multiset1.contains(element)) {
570                return immutableEntry(element, entry2.getCount());
571              }
572            }
573            return endOfData();
574          }
575        };
576      }
577    };
578  }
579
580  /**
581   * Returns an unmodifiable view of the difference of two multisets. In the returned multiset, the
582   * count of each element is the result of the <i>zero-truncated subtraction</i> of its count in
583   * the second multiset from its count in the first multiset, with elements that would have a count
584   * of 0 not included. The iteration order of the returned multiset matches that of the element set
585   * of {@code multiset1}, with repeated occurrences of the same element appearing consecutively.
586   *
587   * <p>Results are undefined if {@code multiset1} and {@code multiset2} are based on different
588   * equivalence relations (as {@code HashMultiset} and {@code TreeMultiset} are).
589   *
590   * @since 14.0
591   */
592  @Beta
593  public static <E extends @Nullable Object> Multiset<E> difference(
594      final Multiset<E> multiset1, final Multiset<?> multiset2) {
595    checkNotNull(multiset1);
596    checkNotNull(multiset2);
597
598    // TODO(lowasser): consider making the entries live views
599    return new ViewMultiset<E>() {
600      @Override
601      public int count(@CheckForNull Object element) {
602        int count1 = multiset1.count(element);
603        return (count1 == 0) ? 0 : Math.max(0, count1 - multiset2.count(element));
604      }
605
606      @Override
607      public void clear() {
608        throw new UnsupportedOperationException();
609      }
610
611      @Override
612      Iterator<E> elementIterator() {
613        final Iterator<Entry<E>> iterator1 = multiset1.entrySet().iterator();
614        return new AbstractIterator<E>() {
615          @Override
616          @CheckForNull
617          protected E computeNext() {
618            while (iterator1.hasNext()) {
619              Entry<E> entry1 = iterator1.next();
620              E element = entry1.getElement();
621              if (entry1.getCount() > multiset2.count(element)) {
622                return element;
623              }
624            }
625            return endOfData();
626          }
627        };
628      }
629
630      @Override
631      Iterator<Entry<E>> entryIterator() {
632        final Iterator<Entry<E>> iterator1 = multiset1.entrySet().iterator();
633        return new AbstractIterator<Entry<E>>() {
634          @Override
635          @CheckForNull
636          protected Entry<E> computeNext() {
637            while (iterator1.hasNext()) {
638              Entry<E> entry1 = iterator1.next();
639              E element = entry1.getElement();
640              int count = entry1.getCount() - multiset2.count(element);
641              if (count > 0) {
642                return immutableEntry(element, count);
643              }
644            }
645            return endOfData();
646          }
647        };
648      }
649
650      @Override
651      int distinctElements() {
652        return Iterators.size(entryIterator());
653      }
654    };
655  }
656
657  /**
658   * Returns {@code true} if {@code subMultiset.count(o) <= superMultiset.count(o)} for all {@code
659   * o}.
660   *
661   * @since 10.0
662   */
663  @CanIgnoreReturnValue
664  public static boolean containsOccurrences(Multiset<?> superMultiset, Multiset<?> subMultiset) {
665    checkNotNull(superMultiset);
666    checkNotNull(subMultiset);
667    for (Entry<?> entry : subMultiset.entrySet()) {
668      int superCount = superMultiset.count(entry.getElement());
669      if (superCount < entry.getCount()) {
670        return false;
671      }
672    }
673    return true;
674  }
675
676  /**
677   * Modifies {@code multisetToModify} so that its count for an element {@code e} is at most {@code
678   * multisetToRetain.count(e)}.
679   *
680   * <p>To be precise, {@code multisetToModify.count(e)} is set to {@code
681   * Math.min(multisetToModify.count(e), multisetToRetain.count(e))}. This is similar to {@link
682   * #intersection(Multiset, Multiset) intersection} {@code (multisetToModify, multisetToRetain)},
683   * but mutates {@code multisetToModify} instead of returning a view.
684   *
685   * <p>In contrast, {@code multisetToModify.retainAll(multisetToRetain)} keeps all occurrences of
686   * elements that appear at all in {@code multisetToRetain}, and deletes all occurrences of all
687   * other elements.
688   *
689   * @return {@code true} if {@code multisetToModify} was changed as a result of this operation
690   * @since 10.0
691   */
692  @CanIgnoreReturnValue
693  public static boolean retainOccurrences(
694      Multiset<?> multisetToModify, Multiset<?> multisetToRetain) {
695    return retainOccurrencesImpl(multisetToModify, multisetToRetain);
696  }
697
698  /** Delegate implementation which cares about the element type. */
699  private static <E extends @Nullable Object> boolean retainOccurrencesImpl(
700      Multiset<E> multisetToModify, Multiset<?> occurrencesToRetain) {
701    checkNotNull(multisetToModify);
702    checkNotNull(occurrencesToRetain);
703    // Avoiding ConcurrentModificationExceptions is tricky.
704    Iterator<Entry<E>> entryIterator = multisetToModify.entrySet().iterator();
705    boolean changed = false;
706    while (entryIterator.hasNext()) {
707      Entry<E> entry = entryIterator.next();
708      int retainCount = occurrencesToRetain.count(entry.getElement());
709      if (retainCount == 0) {
710        entryIterator.remove();
711        changed = true;
712      } else if (retainCount < entry.getCount()) {
713        multisetToModify.setCount(entry.getElement(), retainCount);
714        changed = true;
715      }
716    }
717    return changed;
718  }
719
720  /**
721   * For each occurrence of an element {@code e} in {@code occurrencesToRemove}, removes one
722   * occurrence of {@code e} in {@code multisetToModify}.
723   *
724   * <p>Equivalently, this method modifies {@code multisetToModify} so that {@code
725   * multisetToModify.count(e)} is set to {@code Math.max(0, multisetToModify.count(e) -
726   * Iterables.frequency(occurrencesToRemove, e))}.
727   *
728   * <p>This is <i>not</i> the same as {@code multisetToModify.} {@link Multiset#removeAll
729   * removeAll}{@code (occurrencesToRemove)}, which removes all occurrences of elements that appear
730   * in {@code occurrencesToRemove}. However, this operation <i>is</i> equivalent to, albeit
731   * sometimes more efficient than, the following:
732   *
733   * <pre>{@code
734   * for (E e : occurrencesToRemove) {
735   *   multisetToModify.remove(e);
736   * }
737   * }</pre>
738   *
739   * @return {@code true} if {@code multisetToModify} was changed as a result of this operation
740   * @since 18.0 (present in 10.0 with a requirement that the second parameter be a {@code
741   *     Multiset})
742   */
743  @CanIgnoreReturnValue
744  public static boolean removeOccurrences(
745      Multiset<?> multisetToModify, Iterable<?> occurrencesToRemove) {
746    if (occurrencesToRemove instanceof Multiset) {
747      return removeOccurrences(multisetToModify, (Multiset<?>) occurrencesToRemove);
748    } else {
749      checkNotNull(multisetToModify);
750      checkNotNull(occurrencesToRemove);
751      boolean changed = false;
752      for (Object o : occurrencesToRemove) {
753        changed |= multisetToModify.remove(o);
754      }
755      return changed;
756    }
757  }
758
759  /**
760   * For each occurrence of an element {@code e} in {@code occurrencesToRemove}, removes one
761   * occurrence of {@code e} in {@code multisetToModify}.
762   *
763   * <p>Equivalently, this method modifies {@code multisetToModify} so that {@code
764   * multisetToModify.count(e)} is set to {@code Math.max(0, multisetToModify.count(e) -
765   * occurrencesToRemove.count(e))}.
766   *
767   * <p>This is <i>not</i> the same as {@code multisetToModify.} {@link Multiset#removeAll
768   * removeAll}{@code (occurrencesToRemove)}, which removes all occurrences of elements that appear
769   * in {@code occurrencesToRemove}. However, this operation <i>is</i> equivalent to, albeit
770   * sometimes more efficient than, the following:
771   *
772   * <pre>{@code
773   * for (E e : occurrencesToRemove) {
774   *   multisetToModify.remove(e);
775   * }
776   * }</pre>
777   *
778   * @return {@code true} if {@code multisetToModify} was changed as a result of this operation
779   * @since 10.0 (missing in 18.0 when only the overload taking an {@code Iterable} was present)
780   */
781  @CanIgnoreReturnValue
782  public static boolean removeOccurrences(
783      Multiset<?> multisetToModify, Multiset<?> occurrencesToRemove) {
784    checkNotNull(multisetToModify);
785    checkNotNull(occurrencesToRemove);
786
787    boolean changed = false;
788    Iterator<? extends Entry<?>> entryIterator = multisetToModify.entrySet().iterator();
789    while (entryIterator.hasNext()) {
790      Entry<?> entry = entryIterator.next();
791      int removeCount = occurrencesToRemove.count(entry.getElement());
792      if (removeCount >= entry.getCount()) {
793        entryIterator.remove();
794        changed = true;
795      } else if (removeCount > 0) {
796        multisetToModify.remove(entry.getElement(), removeCount);
797        changed = true;
798      }
799    }
800    return changed;
801  }
802
803  /**
804   * Implementation of the {@code equals}, {@code hashCode}, and {@code toString} methods of {@link
805   * Multiset.Entry}.
806   */
807  abstract static class AbstractEntry<E extends @Nullable Object> implements Multiset.Entry<E> {
808    /**
809     * Indicates whether an object equals this entry, following the behavior specified in {@link
810     * Multiset.Entry#equals}.
811     */
812    @Override
813    public boolean equals(@CheckForNull Object object) {
814      if (object instanceof Multiset.Entry) {
815        Multiset.Entry<?> that = (Multiset.Entry<?>) object;
816        return this.getCount() == that.getCount()
817            && Objects.equal(this.getElement(), that.getElement());
818      }
819      return false;
820    }
821
822    /**
823     * Return this entry's hash code, following the behavior specified in {@link
824     * Multiset.Entry#hashCode}.
825     */
826    @Override
827    public int hashCode() {
828      E e = getElement();
829      return ((e == null) ? 0 : e.hashCode()) ^ getCount();
830    }
831
832    /**
833     * Returns a string representation of this multiset entry. The string representation consists of
834     * the associated element if the associated count is one, and otherwise the associated element
835     * followed by the characters " x " (space, x and space) followed by the count. Elements and
836     * counts are converted to strings as by {@code String.valueOf}.
837     */
838    @Override
839    public String toString() {
840      String text = String.valueOf(getElement());
841      int n = getCount();
842      return (n == 1) ? text : (text + " x " + n);
843    }
844  }
845
846  /** An implementation of {@link Multiset#equals}. */
847  static boolean equalsImpl(Multiset<?> multiset, @CheckForNull Object object) {
848    if (object == multiset) {
849      return true;
850    }
851    if (object instanceof Multiset) {
852      Multiset<?> that = (Multiset<?>) object;
853      /*
854       * We can't simply check whether the entry sets are equal, since that
855       * approach fails when a TreeMultiset has a comparator that returns 0
856       * when passed unequal elements.
857       */
858
859      if (multiset.size() != that.size() || multiset.entrySet().size() != that.entrySet().size()) {
860        return false;
861      }
862      for (Entry<?> entry : that.entrySet()) {
863        if (multiset.count(entry.getElement()) != entry.getCount()) {
864          return false;
865        }
866      }
867      return true;
868    }
869    return false;
870  }
871
872  /** An implementation of {@link Multiset#addAll}. */
873  static <E extends @Nullable Object> boolean addAllImpl(
874      Multiset<E> self, Collection<? extends E> elements) {
875    checkNotNull(self);
876    checkNotNull(elements);
877    if (elements instanceof Multiset) {
878      return addAllImpl(self, cast(elements));
879    } else if (elements.isEmpty()) {
880      return false;
881    } else {
882      return Iterators.addAll(self, elements.iterator());
883    }
884  }
885
886  /** A specialization of {@code addAllImpl} for when {@code elements} is itself a Multiset. */
887  private static <E extends @Nullable Object> boolean addAllImpl(
888      Multiset<E> self, Multiset<? extends E> elements) {
889    // It'd be nice if we could specialize for ImmutableMultiset here without also retaining
890    // its code when it's not in scope...
891    if (elements instanceof AbstractMapBasedMultiset) {
892      return addAllImpl(self, (AbstractMapBasedMultiset<? extends E>) elements);
893    } else if (elements.isEmpty()) {
894      return false;
895    } else {
896      for (Multiset.Entry<? extends E> entry : elements.entrySet()) {
897        self.add(entry.getElement(), entry.getCount());
898      }
899      return true;
900    }
901  }
902
903  /**
904   * A specialization of {@code addAllImpl} for when {@code elements} is an
905   * AbstractMapBasedMultiset.
906   */
907  private static <E extends @Nullable Object> boolean addAllImpl(
908      Multiset<E> self, AbstractMapBasedMultiset<? extends E> elements) {
909    if (elements.isEmpty()) {
910      return false;
911    }
912    elements.addTo(self);
913    return true;
914  }
915
916  /** An implementation of {@link Multiset#removeAll}. */
917  static boolean removeAllImpl(Multiset<?> self, Collection<?> elementsToRemove) {
918    Collection<?> collection =
919        (elementsToRemove instanceof Multiset)
920            ? ((Multiset<?>) elementsToRemove).elementSet()
921            : elementsToRemove;
922
923    return self.elementSet().removeAll(collection);
924  }
925
926  /** An implementation of {@link Multiset#retainAll}. */
927  static boolean retainAllImpl(Multiset<?> self, Collection<?> elementsToRetain) {
928    checkNotNull(elementsToRetain);
929    Collection<?> collection =
930        (elementsToRetain instanceof Multiset)
931            ? ((Multiset<?>) elementsToRetain).elementSet()
932            : elementsToRetain;
933
934    return self.elementSet().retainAll(collection);
935  }
936
937  /** An implementation of {@link Multiset#setCount(Object, int)}. */
938  static <E extends @Nullable Object> int setCountImpl(
939      Multiset<E> self, @ParametricNullness E element, int count) {
940    checkNonnegative(count, "count");
941
942    int oldCount = self.count(element);
943
944    int delta = count - oldCount;
945    if (delta > 0) {
946      self.add(element, delta);
947    } else if (delta < 0) {
948      self.remove(element, -delta);
949    }
950
951    return oldCount;
952  }
953
954  /** An implementation of {@link Multiset#setCount(Object, int, int)}. */
955  static <E extends @Nullable Object> boolean setCountImpl(
956      Multiset<E> self, @ParametricNullness E element, int oldCount, int newCount) {
957    checkNonnegative(oldCount, "oldCount");
958    checkNonnegative(newCount, "newCount");
959
960    if (self.count(element) == oldCount) {
961      self.setCount(element, newCount);
962      return true;
963    } else {
964      return false;
965    }
966  }
967
968  static <E extends @Nullable Object> Iterator<E> elementIterator(
969      Iterator<Entry<E>> entryIterator) {
970    return new TransformedIterator<Entry<E>, E>(entryIterator) {
971      @Override
972      @ParametricNullness
973      E transform(Entry<E> entry) {
974        return entry.getElement();
975      }
976    };
977  }
978
979  abstract static class ElementSet<E extends @Nullable Object> extends Sets.ImprovedAbstractSet<E> {
980    abstract Multiset<E> multiset();
981
982    @Override
983    public void clear() {
984      multiset().clear();
985    }
986
987    @Override
988    public boolean contains(@CheckForNull Object o) {
989      return multiset().contains(o);
990    }
991
992    @Override
993    public boolean containsAll(Collection<?> c) {
994      return multiset().containsAll(c);
995    }
996
997    @Override
998    public boolean isEmpty() {
999      return multiset().isEmpty();
1000    }
1001
1002    @Override
1003    public abstract Iterator<E> iterator();
1004
1005    @Override
1006    public boolean remove(@CheckForNull Object o) {
1007      return multiset().remove(o, Integer.MAX_VALUE) > 0;
1008    }
1009
1010    @Override
1011    public int size() {
1012      return multiset().entrySet().size();
1013    }
1014  }
1015
1016  abstract static class EntrySet<E extends @Nullable Object>
1017      extends Sets.ImprovedAbstractSet<Entry<E>> {
1018    abstract Multiset<E> multiset();
1019
1020    @Override
1021    public boolean contains(@CheckForNull Object o) {
1022      if (o instanceof Entry) {
1023        /*
1024         * The GWT compiler wrongly issues a warning here.
1025         */
1026        @SuppressWarnings("cast")
1027        Entry<?> entry = (Entry<?>) o;
1028        if (entry.getCount() <= 0) {
1029          return false;
1030        }
1031        int count = multiset().count(entry.getElement());
1032        return count == entry.getCount();
1033      }
1034      return false;
1035    }
1036
1037    // GWT compiler warning; see contains().
1038    @SuppressWarnings("cast")
1039    @Override
1040    public boolean remove(@CheckForNull Object object) {
1041      if (object instanceof Multiset.Entry) {
1042        Entry<?> entry = (Entry<?>) object;
1043        Object element = entry.getElement();
1044        int entryCount = entry.getCount();
1045        if (entryCount != 0) {
1046          // Safe as long as we never add a new entry, which we won't.
1047          // (Presumably it can still throw CCE/NPE but only if the underlying Multiset does.)
1048          @SuppressWarnings({"unchecked", "nullness"})
1049          Multiset<@Nullable Object> multiset = (Multiset<@Nullable Object>) multiset();
1050          return multiset.setCount(element, entryCount, 0);
1051        }
1052      }
1053      return false;
1054    }
1055
1056    @Override
1057    public void clear() {
1058      multiset().clear();
1059    }
1060  }
1061
1062  /** An implementation of {@link Multiset#iterator}. */
1063  static <E extends @Nullable Object> Iterator<E> iteratorImpl(Multiset<E> multiset) {
1064    return new MultisetIteratorImpl<E>(multiset, multiset.entrySet().iterator());
1065  }
1066
1067  static final class MultisetIteratorImpl<E extends @Nullable Object> implements Iterator<E> {
1068    private final Multiset<E> multiset;
1069    private final Iterator<Entry<E>> entryIterator;
1070    @CheckForNull private Entry<E> currentEntry;
1071
1072    /** Count of subsequent elements equal to current element */
1073    private int laterCount;
1074
1075    /** Count of all elements equal to current element */
1076    private int totalCount;
1077
1078    private boolean canRemove;
1079
1080    MultisetIteratorImpl(Multiset<E> multiset, Iterator<Entry<E>> entryIterator) {
1081      this.multiset = multiset;
1082      this.entryIterator = entryIterator;
1083    }
1084
1085    @Override
1086    public boolean hasNext() {
1087      return laterCount > 0 || entryIterator.hasNext();
1088    }
1089
1090    @Override
1091    @ParametricNullness
1092    public E next() {
1093      if (!hasNext()) {
1094        throw new NoSuchElementException();
1095      }
1096      if (laterCount == 0) {
1097        currentEntry = entryIterator.next();
1098        totalCount = laterCount = currentEntry.getCount();
1099      }
1100      laterCount--;
1101      canRemove = true;
1102      /*
1103       * requireNonNull is safe because laterCount starts at 0, forcing us to initialize
1104       * currentEntry above. After that, we never clear it.
1105       */
1106      return requireNonNull(currentEntry).getElement();
1107    }
1108
1109    @Override
1110    public void remove() {
1111      checkRemove(canRemove);
1112      if (totalCount == 1) {
1113        entryIterator.remove();
1114      } else {
1115        /*
1116         * requireNonNull is safe because canRemove is set to true only after we initialize
1117         * currentEntry (which we never subsequently clear).
1118         */
1119        multiset.remove(requireNonNull(currentEntry).getElement());
1120      }
1121      totalCount--;
1122      canRemove = false;
1123    }
1124  }
1125
1126  /** An implementation of {@link Multiset#size}. */
1127  static int linearTimeSizeImpl(Multiset<?> multiset) {
1128    long size = 0;
1129    for (Entry<?> entry : multiset.entrySet()) {
1130      size += entry.getCount();
1131    }
1132    return Ints.saturatedCast(size);
1133  }
1134
1135  /** Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557 */
1136  static <T extends @Nullable Object> Multiset<T> cast(Iterable<T> iterable) {
1137    return (Multiset<T>) iterable;
1138  }
1139
1140  /**
1141   * Returns a copy of {@code multiset} as an {@link ImmutableMultiset} whose iteration order is
1142   * highest count first, with ties broken by the iteration order of the original multiset.
1143   *
1144   * @since 11.0
1145   */
1146  @Beta
1147  public static <E> ImmutableMultiset<E> copyHighestCountFirst(Multiset<E> multiset) {
1148    Entry<E>[] entries = (Entry<E>[]) multiset.entrySet().toArray(new Entry[0]);
1149    Arrays.sort(entries, DecreasingCount.INSTANCE);
1150    return ImmutableMultiset.copyFromEntries(Arrays.asList(entries));
1151  }
1152
1153  private static final class DecreasingCount implements Comparator<Entry<?>> {
1154    static final DecreasingCount INSTANCE = new DecreasingCount();
1155
1156    @Override
1157    public int compare(Entry<?> entry1, Entry<?> entry2) {
1158      return entry2.getCount() - entry1.getCount(); // subtracting two nonnegative integers
1159    }
1160  }
1161
1162  /**
1163   * An {@link AbstractMultiset} with additional default implementations, some of them linear-time
1164   * implementations in terms of {@code elementSet} and {@code entrySet}.
1165   */
1166  private abstract static class ViewMultiset<E extends @Nullable Object>
1167      extends AbstractMultiset<E> {
1168    @Override
1169    public int size() {
1170      return linearTimeSizeImpl(this);
1171    }
1172
1173    @Override
1174    public void clear() {
1175      elementSet().clear();
1176    }
1177
1178    @Override
1179    public Iterator<E> iterator() {
1180      return iteratorImpl(this);
1181    }
1182
1183    @Override
1184    int distinctElements() {
1185      return elementSet().size();
1186    }
1187  }
1188}