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