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