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