Coverage Summary for Class: ImmutableSortedMultiset (com.google.common.collect)
| Class | Method, % | Line, % |
|---|---|---|
| ImmutableSortedMultiset | 9.7% (3/31) | 7.8% (6/77) |
| ImmutableSortedMultiset$Builder | 0% (0/8) | 0% (0/14) |
| ImmutableSortedMultiset$SerializedForm | 0% (0/2) | 0% (0/16) |
| Total | 7.3% (3/41) | 5.6% (6/107) |
1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 * express or implied. See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 15 package com.google.common.collect; 16 17 import static com.google.common.base.Preconditions.checkArgument; 18 import static com.google.common.base.Preconditions.checkNotNull; 19 20 import com.google.common.annotations.GwtIncompatible; 21 import com.google.errorprone.annotations.CanIgnoreReturnValue; 22 import com.google.errorprone.annotations.DoNotCall; 23 import com.google.errorprone.annotations.concurrent.LazyInit; 24 import java.io.Serializable; 25 import java.util.Arrays; 26 import java.util.Collection; 27 import java.util.Collections; 28 import java.util.Comparator; 29 import java.util.Iterator; 30 import java.util.List; 31 import java.util.function.Function; 32 import java.util.function.ToIntFunction; 33 import java.util.stream.Collector; 34 import javax.annotation.CheckForNull; 35 import org.checkerframework.checker.nullness.qual.Nullable; 36 37 /** 38 * A {@link SortedMultiset} whose contents will never change, with many other important properties 39 * detailed at {@link ImmutableCollection}. 40 * 41 * <p><b>Warning:</b> as with any sorted collection, you are strongly advised not to use a {@link 42 * Comparator} or {@link Comparable} type whose comparison behavior is <i>inconsistent with 43 * equals</i>. That is, {@code a.compareTo(b)} or {@code comparator.compare(a, b)} should equal zero 44 * <i>if and only if</i> {@code a.equals(b)}. If this advice is not followed, the resulting 45 * collection will not correctly obey its specification. 46 * 47 * <p>See the Guava User Guide article on <a href= 48 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> immutable collections</a>. 49 * 50 * @author Louis Wasserman 51 * @since 12.0 52 */ 53 @GwtIncompatible // hasn't been tested yet 54 @ElementTypesAreNonnullByDefault 55 public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultisetFauxverideShim<E> 56 implements SortedMultiset<E> { 57 // TODO(lowasser): GWT compatibility 58 59 /** 60 * Returns a {@code Collector} that accumulates the input elements into a new {@code 61 * ImmutableMultiset}. Elements are sorted by the specified comparator. 62 * 63 * <p><b>Warning:</b> {@code comparator} should be <i>consistent with {@code equals}</i> as 64 * explained in the {@link Comparator} documentation. 65 * 66 * @since 21.0 67 */ 68 public static <E> Collector<E, ?, ImmutableSortedMultiset<E>> toImmutableSortedMultiset( 69 Comparator<? super E> comparator) { 70 return toImmutableSortedMultiset(comparator, Function.identity(), e -> 1); 71 } 72 73 /** 74 * Returns a {@code Collector} that accumulates elements into an {@code ImmutableSortedMultiset} 75 * whose elements are the result of applying {@code elementFunction} to the inputs, with counts 76 * equal to the result of applying {@code countFunction} to the inputs. 77 * 78 * <p>If the mapped elements contain duplicates (according to {@code comparator}), the first 79 * occurrence in encounter order appears in the resulting multiset, with count equal to the sum of 80 * the outputs of {@code countFunction.applyAsInt(t)} for each {@code t} mapped to that element. 81 * 82 * @since 22.0 83 */ 84 public static <T extends @Nullable Object, E> 85 Collector<T, ?, ImmutableSortedMultiset<E>> toImmutableSortedMultiset( 86 Comparator<? super E> comparator, 87 Function<? super T, ? extends E> elementFunction, 88 ToIntFunction<? super T> countFunction) { 89 checkNotNull(comparator); 90 checkNotNull(elementFunction); 91 checkNotNull(countFunction); 92 return Collector.of( 93 () -> TreeMultiset.create(comparator), 94 (multiset, t) -> 95 multiset.add(checkNotNull(elementFunction.apply(t)), countFunction.applyAsInt(t)), 96 (multiset1, multiset2) -> { 97 multiset1.addAll(multiset2); 98 return multiset1; 99 }, 100 (Multiset<E> multiset) -> copyOfSortedEntries(comparator, multiset.entrySet())); 101 } 102 103 /** 104 * Returns the empty immutable sorted multiset. 105 * 106 * <p><b>Performance note:</b> the instance returned is a singleton. 107 */ 108 @SuppressWarnings("unchecked") 109 public static <E> ImmutableSortedMultiset<E> of() { 110 return (ImmutableSortedMultiset) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; 111 } 112 113 /** Returns an immutable sorted multiset containing a single element. */ 114 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E element) { 115 RegularImmutableSortedSet<E> elementSet = 116 (RegularImmutableSortedSet<E>) ImmutableSortedSet.of(element); 117 long[] cumulativeCounts = {0, 1}; 118 return new RegularImmutableSortedMultiset<E>(elementSet, cumulativeCounts, 0, 1); 119 } 120 121 /** 122 * Returns an immutable sorted multiset containing the given elements sorted by their natural 123 * ordering. 124 * 125 * @throws NullPointerException if any element is null 126 */ 127 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2) { 128 return copyOf(Ordering.natural(), Arrays.asList(e1, e2)); 129 } 130 131 /** 132 * Returns an immutable sorted multiset containing the given elements sorted by their natural 133 * ordering. 134 * 135 * @throws NullPointerException if any element is null 136 */ 137 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) { 138 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3)); 139 } 140 141 /** 142 * Returns an immutable sorted multiset containing the given elements sorted by their natural 143 * ordering. 144 * 145 * @throws NullPointerException if any element is null 146 */ 147 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 148 E e1, E e2, E e3, E e4) { 149 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4)); 150 } 151 152 /** 153 * Returns an immutable sorted multiset containing the given elements sorted by their natural 154 * ordering. 155 * 156 * @throws NullPointerException if any element is null 157 */ 158 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 159 E e1, E e2, E e3, E e4, E e5) { 160 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4, e5)); 161 } 162 163 /** 164 * Returns an immutable sorted multiset containing the given elements sorted by their natural 165 * ordering. 166 * 167 * @throws NullPointerException if any element is null 168 */ 169 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 170 E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { 171 int size = remaining.length + 6; 172 List<E> all = Lists.newArrayListWithCapacity(size); 173 Collections.addAll(all, e1, e2, e3, e4, e5, e6); 174 Collections.addAll(all, remaining); 175 return copyOf(Ordering.natural(), all); 176 } 177 178 /** 179 * Returns an immutable sorted multiset containing the given elements sorted by their natural 180 * ordering. 181 * 182 * @throws NullPointerException if any of {@code elements} is null 183 */ 184 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> copyOf(E[] elements) { 185 return copyOf(Ordering.natural(), Arrays.asList(elements)); 186 } 187 188 /** 189 * Returns an immutable sorted multiset containing the given elements sorted by their natural 190 * ordering. To create a copy of a {@code SortedMultiset} that preserves the comparator, call 191 * {@link #copyOfSorted} instead. This method iterates over {@code elements} at most once. 192 * 193 * <p>Note that if {@code s} is a {@code Multiset<String>}, then {@code 194 * ImmutableSortedMultiset.copyOf(s)} returns an {@code ImmutableSortedMultiset<String>} 195 * containing each of the strings in {@code s}, while {@code ImmutableSortedMultiset.of(s)} 196 * returns an {@code ImmutableSortedMultiset<Multiset<String>>} containing one element (the given 197 * multiset itself). 198 * 199 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 200 * safe to do so. The exact circumstances under which a copy will or will not be performed are 201 * undocumented and subject to change. 202 * 203 * <p>This method is not type-safe, as it may be called on elements that are not mutually 204 * comparable. 205 * 206 * @throws ClassCastException if the elements are not mutually comparable 207 * @throws NullPointerException if any of {@code elements} is null 208 */ 209 public static <E> ImmutableSortedMultiset<E> copyOf(Iterable<? extends E> elements) { 210 // Hack around E not being a subtype of Comparable. 211 // Unsafe, see ImmutableSortedMultisetFauxverideShim. 212 @SuppressWarnings("unchecked") 213 Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural(); 214 return copyOf(naturalOrder, elements); 215 } 216 217 /** 218 * Returns an immutable sorted multiset containing the given elements sorted by their natural 219 * ordering. 220 * 221 * <p>This method is not type-safe, as it may be called on elements that are not mutually 222 * comparable. 223 * 224 * @throws ClassCastException if the elements are not mutually comparable 225 * @throws NullPointerException if any of {@code elements} is null 226 */ 227 public static <E> ImmutableSortedMultiset<E> copyOf(Iterator<? extends E> elements) { 228 // Hack around E not being a subtype of Comparable. 229 // Unsafe, see ImmutableSortedMultisetFauxverideShim. 230 @SuppressWarnings("unchecked") 231 Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural(); 232 return copyOf(naturalOrder, elements); 233 } 234 235 /** 236 * Returns an immutable sorted multiset containing the given elements sorted by the given {@code 237 * Comparator}. 238 * 239 * @throws NullPointerException if {@code comparator} or any of {@code elements} is null 240 */ 241 public static <E> ImmutableSortedMultiset<E> copyOf( 242 Comparator<? super E> comparator, Iterator<? extends E> elements) { 243 checkNotNull(comparator); 244 return new Builder<E>(comparator).addAll(elements).build(); 245 } 246 247 /** 248 * Returns an immutable sorted multiset containing the given elements sorted by the given {@code 249 * Comparator}. This method iterates over {@code elements} at most once. 250 * 251 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 252 * safe to do so. The exact circumstances under which a copy will or will not be performed are 253 * undocumented and subject to change. 254 * 255 * @throws NullPointerException if {@code comparator} or any of {@code elements} is null 256 */ 257 public static <E> ImmutableSortedMultiset<E> copyOf( 258 Comparator<? super E> comparator, Iterable<? extends E> elements) { 259 if (elements instanceof ImmutableSortedMultiset) { 260 @SuppressWarnings("unchecked") // immutable collections are always safe for covariant casts 261 ImmutableSortedMultiset<E> multiset = (ImmutableSortedMultiset<E>) elements; 262 if (comparator.equals(multiset.comparator())) { 263 if (multiset.isPartialView()) { 264 return copyOfSortedEntries(comparator, multiset.entrySet().asList()); 265 } else { 266 return multiset; 267 } 268 } 269 } 270 elements = Lists.newArrayList(elements); // defensive copy 271 TreeMultiset<E> sortedCopy = TreeMultiset.create(checkNotNull(comparator)); 272 Iterables.addAll(sortedCopy, elements); 273 return copyOfSortedEntries(comparator, sortedCopy.entrySet()); 274 } 275 276 /** 277 * Returns an immutable sorted multiset containing the elements of a sorted multiset, sorted by 278 * the same {@code Comparator}. That behavior differs from {@link #copyOf(Iterable)}, which always 279 * uses the natural ordering of the elements. 280 * 281 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 282 * safe to do so. The exact circumstances under which a copy will or will not be performed are 283 * undocumented and subject to change. 284 * 285 * <p>This method is safe to use even when {@code sortedMultiset} is a synchronized or concurrent 286 * collection that is currently being modified by another thread. 287 * 288 * @throws NullPointerException if {@code sortedMultiset} or any of its elements is null 289 */ 290 public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) { 291 return copyOfSortedEntries( 292 sortedMultiset.comparator(), Lists.newArrayList(sortedMultiset.entrySet())); 293 } 294 295 private static <E> ImmutableSortedMultiset<E> copyOfSortedEntries( 296 Comparator<? super E> comparator, Collection<Entry<E>> entries) { 297 if (entries.isEmpty()) { 298 return emptyMultiset(comparator); 299 } 300 ImmutableList.Builder<E> elementsBuilder = new ImmutableList.Builder<E>(entries.size()); 301 long[] cumulativeCounts = new long[entries.size() + 1]; 302 int i = 0; 303 for (Entry<E> entry : entries) { 304 elementsBuilder.add(entry.getElement()); 305 cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount(); 306 i++; 307 } 308 return new RegularImmutableSortedMultiset<E>( 309 new RegularImmutableSortedSet<E>(elementsBuilder.build(), comparator), 310 cumulativeCounts, 311 0, 312 entries.size()); 313 } 314 315 @SuppressWarnings("unchecked") 316 static <E> ImmutableSortedMultiset<E> emptyMultiset(Comparator<? super E> comparator) { 317 if (Ordering.natural().equals(comparator)) { 318 return (ImmutableSortedMultiset<E>) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; 319 } else { 320 return new RegularImmutableSortedMultiset<E>(comparator); 321 } 322 } 323 324 ImmutableSortedMultiset() {} 325 326 @Override 327 public final Comparator<? super E> comparator() { 328 return elementSet().comparator(); 329 } 330 331 @Override 332 public abstract ImmutableSortedSet<E> elementSet(); 333 334 @LazyInit @CheckForNull transient ImmutableSortedMultiset<E> descendingMultiset; 335 336 @Override 337 public ImmutableSortedMultiset<E> descendingMultiset() { 338 ImmutableSortedMultiset<E> result = descendingMultiset; 339 if (result == null) { 340 return descendingMultiset = 341 this.isEmpty() 342 ? emptyMultiset(Ordering.from(comparator()).reverse()) 343 : new DescendingImmutableSortedMultiset<E>(this); 344 } 345 return result; 346 } 347 348 /** 349 * {@inheritDoc} 350 * 351 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 352 * 353 * @throws UnsupportedOperationException always 354 * @deprecated Unsupported operation. 355 */ 356 @CanIgnoreReturnValue 357 @Deprecated 358 @Override 359 @DoNotCall("Always throws UnsupportedOperationException") 360 @CheckForNull 361 public final Entry<E> pollFirstEntry() { 362 throw new UnsupportedOperationException(); 363 } 364 365 /** 366 * {@inheritDoc} 367 * 368 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 369 * 370 * @throws UnsupportedOperationException always 371 * @deprecated Unsupported operation. 372 */ 373 @CanIgnoreReturnValue 374 @Deprecated 375 @Override 376 @DoNotCall("Always throws UnsupportedOperationException") 377 @CheckForNull 378 public final Entry<E> pollLastEntry() { 379 throw new UnsupportedOperationException(); 380 } 381 382 @Override 383 public abstract ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType); 384 385 @Override 386 public ImmutableSortedMultiset<E> subMultiset( 387 E lowerBound, BoundType lowerBoundType, E upperBound, BoundType upperBoundType) { 388 checkArgument( 389 comparator().compare(lowerBound, upperBound) <= 0, 390 "Expected lowerBound <= upperBound but %s > %s", 391 lowerBound, 392 upperBound); 393 return tailMultiset(lowerBound, lowerBoundType).headMultiset(upperBound, upperBoundType); 394 } 395 396 @Override 397 public abstract ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType); 398 399 /** 400 * Returns a builder that creates immutable sorted multisets with an explicit comparator. If the 401 * comparator has a more general type than the set being generated, such as creating a {@code 402 * SortedMultiset<Integer>} with a {@code Comparator<Number>}, use the {@link Builder} constructor 403 * instead. 404 * 405 * @throws NullPointerException if {@code comparator} is null 406 */ 407 public static <E> Builder<E> orderedBy(Comparator<E> comparator) { 408 return new Builder<E>(comparator); 409 } 410 411 /** 412 * Returns a builder that creates immutable sorted multisets whose elements are ordered by the 413 * reverse of their natural ordering. 414 * 415 * <p>Note: the type parameter {@code E} extends {@code Comparable<?>} rather than {@code 416 * Comparable<? super E>} as a workaround for javac <a 417 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>. 418 */ 419 public static <E extends Comparable<?>> Builder<E> reverseOrder() { 420 return new Builder<E>(Ordering.natural().reverse()); 421 } 422 423 /** 424 * Returns a builder that creates immutable sorted multisets whose elements are ordered by their 425 * natural ordering. The sorted multisets use {@link Ordering#natural()} as the comparator. This 426 * method provides more type-safety than {@link #builder}, as it can be called only for classes 427 * that implement {@link Comparable}. 428 * 429 * <p>Note: the type parameter {@code E} extends {@code Comparable<?>} rather than {@code 430 * Comparable<? super E>} as a workaround for javac <a 431 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>. 432 */ 433 public static <E extends Comparable<?>> Builder<E> naturalOrder() { 434 return new Builder<E>(Ordering.natural()); 435 } 436 437 /** 438 * A builder for creating immutable multiset instances, especially {@code public static final} 439 * multisets ("constant multisets"). Example: 440 * 441 * <pre>{@code 442 * public static final ImmutableSortedMultiset<Bean> BEANS = 443 * new ImmutableSortedMultiset.Builder<Bean>(colorComparator()) 444 * .addCopies(Bean.COCOA, 4) 445 * .addCopies(Bean.GARDEN, 6) 446 * .addCopies(Bean.RED, 8) 447 * .addCopies(Bean.BLACK_EYED, 10) 448 * .build(); 449 * }</pre> 450 * 451 * <p>Builder instances can be reused; it is safe to call {@link #build} multiple times to build 452 * multiple multisets in series. 453 * 454 * @since 12.0 455 */ 456 public static class Builder<E> extends ImmutableMultiset.Builder<E> { 457 /** 458 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 459 * ImmutableSortedMultiset#orderedBy(Comparator)}. 460 */ 461 public Builder(Comparator<? super E> comparator) { 462 super(TreeMultiset.<E>create(checkNotNull(comparator))); 463 } 464 465 /** 466 * Adds {@code element} to the {@code ImmutableSortedMultiset}. 467 * 468 * @param element the element to add 469 * @return this {@code Builder} object 470 * @throws NullPointerException if {@code element} is null 471 */ 472 @CanIgnoreReturnValue 473 @Override 474 public Builder<E> add(E element) { 475 super.add(element); 476 return this; 477 } 478 479 /** 480 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 481 * 482 * @param elements the elements to add 483 * @return this {@code Builder} object 484 * @throws NullPointerException if {@code elements} is null or contains a null element 485 */ 486 @CanIgnoreReturnValue 487 @Override 488 public Builder<E> add(E... elements) { 489 super.add(elements); 490 return this; 491 } 492 493 /** 494 * Adds a number of occurrences of an element to this {@code ImmutableSortedMultiset}. 495 * 496 * @param element the element to add 497 * @param occurrences the number of occurrences of the element to add. May be zero, in which 498 * case no change will be made. 499 * @return this {@code Builder} object 500 * @throws NullPointerException if {@code element} is null 501 * @throws IllegalArgumentException if {@code occurrences} is negative, or if this operation 502 * would result in more than {@link Integer#MAX_VALUE} occurrences of the element 503 */ 504 @CanIgnoreReturnValue 505 @Override 506 public Builder<E> addCopies(E element, int occurrences) { 507 super.addCopies(element, occurrences); 508 return this; 509 } 510 511 /** 512 * Adds or removes the necessary occurrences of an element such that the element attains the 513 * desired count. 514 * 515 * @param element the element to add or remove occurrences of 516 * @param count the desired count of the element in this multiset 517 * @return this {@code Builder} object 518 * @throws NullPointerException if {@code element} is null 519 * @throws IllegalArgumentException if {@code count} is negative 520 */ 521 @CanIgnoreReturnValue 522 @Override 523 public Builder<E> setCount(E element, int count) { 524 super.setCount(element, count); 525 return this; 526 } 527 528 /** 529 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 530 * 531 * @param elements the {@code Iterable} to add to the {@code ImmutableSortedMultiset} 532 * @return this {@code Builder} object 533 * @throws NullPointerException if {@code elements} is null or contains a null element 534 */ 535 @CanIgnoreReturnValue 536 @Override 537 public Builder<E> addAll(Iterable<? extends E> elements) { 538 super.addAll(elements); 539 return this; 540 } 541 542 /** 543 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 544 * 545 * @param elements the elements to add to the {@code ImmutableSortedMultiset} 546 * @return this {@code Builder} object 547 * @throws NullPointerException if {@code elements} is null or contains a null element 548 */ 549 @CanIgnoreReturnValue 550 @Override 551 public Builder<E> addAll(Iterator<? extends E> elements) { 552 super.addAll(elements); 553 return this; 554 } 555 556 /** 557 * Returns a newly-created {@code ImmutableSortedMultiset} based on the contents of the {@code 558 * Builder}. 559 */ 560 @Override 561 public ImmutableSortedMultiset<E> build() { 562 return copyOfSorted((SortedMultiset<E>) contents); 563 } 564 } 565 566 private static final class SerializedForm<E> implements Serializable { 567 final Comparator<? super E> comparator; 568 final E[] elements; 569 final int[] counts; 570 571 @SuppressWarnings("unchecked") 572 SerializedForm(SortedMultiset<E> multiset) { 573 this.comparator = multiset.comparator(); 574 int n = multiset.entrySet().size(); 575 elements = (E[]) new Object[n]; 576 counts = new int[n]; 577 int i = 0; 578 for (Entry<E> entry : multiset.entrySet()) { 579 elements[i] = entry.getElement(); 580 counts[i] = entry.getCount(); 581 i++; 582 } 583 } 584 585 Object readResolve() { 586 int n = elements.length; 587 Builder<E> builder = new Builder<>(comparator); 588 for (int i = 0; i < n; i++) { 589 builder.addCopies(elements[i], counts[i]); 590 } 591 return builder.build(); 592 } 593 } 594 595 @Override 596 Object writeReplace() { 597 return new SerializedForm<E>(this); 598 } 599 }