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