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