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