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 015 package com.google.common.collect; 016 017 import static com.google.common.base.Preconditions.checkNotNull; 018 019 import com.google.common.annotations.Beta; 020 import com.google.common.annotations.GwtIncompatible; 021 022 import java.io.Serializable; 023 import java.util.Arrays; 024 import java.util.Collection; 025 import java.util.Collections; 026 import java.util.Comparator; 027 import java.util.Iterator; 028 import java.util.List; 029 030 /** 031 * An immutable {@code SortedMultiset} that stores its elements in a sorted array. Some instances 032 * are ordered by an explicit comparator, while others follow the natural sort ordering of their 033 * elements. Either way, null elements are not supported. 034 * 035 * <p>Unlike {@link Multisets#unmodifiableSortedMultiset}, which is a <i>view</i> of a separate 036 * collection that can still change, an instance of {@code ImmutableSortedMultiset} contains its 037 * own private data and will <i>never</i> change. This class is convenient for {@code public static 038 * final} multisets ("constant multisets") and also lets you easily make a "defensive copy" of a 039 * set provided to your class by a caller. 040 * 041 * <p>The multisets returned by the {@link #headMultiset}, {@link #tailMultiset}, and 042 * {@link #subMultiset} methods share the same array as the original multiset, preventing that 043 * array from being garbage collected. If this is a concern, the data may be copied into a 044 * correctly-sized array by calling {@link #copyOfSorted}. 045 * 046 * <p><b>Note on element equivalence:</b> The {@link #contains(Object)}, 047 * {@link #containsAll(Collection)}, and {@link #equals(Object)} implementations must check whether 048 * a provided object is equivalent to an element in the collection. Unlike most collections, an 049 * {@code ImmutableSortedMultiset} doesn't use {@link Object#equals} to determine if two elements 050 * are equivalent. Instead, with an explicit comparator, the following relation determines whether 051 * elements {@code x} and {@code y} are equivalent: 052 * 053 * <pre> {@code 054 * 055 * {(x, y) | comparator.compare(x, y) == 0}}</pre> 056 * 057 * With natural ordering of elements, the following relation determines whether two elements are 058 * equivalent: 059 * 060 * <pre> {@code 061 * 062 * {(x, y) | x.compareTo(y) == 0}}</pre> 063 * 064 * <b>Warning:</b> Like most multisets, an {@code ImmutableSortedMultiset} will not function 065 * correctly if an element is modified after being placed in the multiset. For this reason, and to 066 * avoid general confusion, it is strongly recommended to place only immutable objects into this 067 * collection. 068 * 069 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as it has no public or 070 * protected constructors. Thus, instances of this type are guaranteed to be immutable. 071 * 072 * <p>See the Guava User Guide article on <a href= 073 * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained"> 074 * immutable collections</a>. 075 * 076 * @author Louis Wasserman 077 * @since 12.0 078 */ 079 @Beta 080 @GwtIncompatible("hasn't been tested yet") 081 public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultisetFauxverideShim<E> 082 implements SortedMultiset<E> { 083 // TODO(user): GWT compatibility 084 085 private static final Comparator<Comparable> NATURAL_ORDER = Ordering.natural(); 086 087 private static final ImmutableSortedMultiset<Comparable> NATURAL_EMPTY_MULTISET = 088 new EmptyImmutableSortedMultiset<Comparable>(NATURAL_ORDER); 089 090 /** 091 * Returns the empty immutable sorted multiset. 092 */ 093 @SuppressWarnings("unchecked") 094 public static <E> ImmutableSortedMultiset<E> of() { 095 return (ImmutableSortedMultiset) NATURAL_EMPTY_MULTISET; 096 } 097 098 /** 099 * Returns an immutable sorted multiset containing a single element. 100 */ 101 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E element) { 102 return RegularImmutableSortedMultiset.createFromSorted( 103 NATURAL_ORDER, ImmutableList.of(Multisets.immutableEntry(checkNotNull(element), 1))); 104 } 105 106 /** 107 * Returns an immutable sorted multiset containing the given elements sorted by their natural 108 * ordering. 109 * 110 * @throws NullPointerException if any element is null 111 */ 112 @SuppressWarnings("unchecked") 113 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2) { 114 return copyOf(Ordering.natural(), Arrays.asList(e1, e2)); 115 } 116 117 /** 118 * Returns an immutable sorted multiset containing the given elements sorted by their natural 119 * ordering. 120 * 121 * @throws NullPointerException if any element is null 122 */ 123 @SuppressWarnings("unchecked") 124 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) { 125 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3)); 126 } 127 128 /** 129 * Returns an immutable sorted multiset containing the given elements sorted by their natural 130 * ordering. 131 * 132 * @throws NullPointerException if any element is null 133 */ 134 @SuppressWarnings("unchecked") 135 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 136 E e1, E e2, E e3, E e4) { 137 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4)); 138 } 139 140 /** 141 * Returns an immutable sorted multiset containing the given elements sorted by their natural 142 * ordering. 143 * 144 * @throws NullPointerException if any element is null 145 */ 146 @SuppressWarnings("unchecked") 147 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 148 E e1, E e2, E e3, E e4, E e5) { 149 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4, e5)); 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 @SuppressWarnings("unchecked") 159 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 160 E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { 161 int size = remaining.length + 6; 162 List<E> all = Lists.newArrayListWithCapacity(size); 163 Collections.addAll(all, e1, e2, e3, e4, e5, e6); 164 Collections.addAll(all, remaining); 165 return copyOf(Ordering.natural(), all); 166 } 167 168 /** 169 * Returns an immutable sorted multiset containing the given elements sorted by their natural 170 * ordering. 171 * 172 * @throws NullPointerException if any of {@code elements} is null 173 */ 174 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> copyOf(E[] elements) { 175 return copyOf(Ordering.natural(), Arrays.asList(elements)); 176 } 177 178 /** 179 * Returns an immutable sorted multiset containing the given elements sorted by their natural 180 * ordering. To create a copy of a {@code SortedMultiset} that preserves the 181 * comparator, call {@link #copyOfSorted} instead. This method iterates over {@code elements} at 182 * most once. 183 * 184 * <p>Note that if {@code s} is a {@code multiset<String>}, then {@code 185 * ImmutableSortedMultiset.copyOf(s)} returns an {@code ImmutableSortedMultiset<String>} 186 * containing each of the strings in {@code s}, while {@code ImmutableSortedMultiset.of(s)} 187 * returns an {@code ImmutableSortedMultiset<multiset<String>>} containing one element (the given 188 * multiset itself). 189 * 190 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 191 * safe to do so. The exact circumstances under which a copy will or will not be performed are 192 * undocumented and subject to change. 193 * 194 * <p>This method is not type-safe, as it may be called on elements that are not mutually 195 * comparable. 196 * 197 * @throws ClassCastException if the elements are not mutually comparable 198 * @throws NullPointerException if any of {@code elements} is null 199 */ 200 public static <E> ImmutableSortedMultiset<E> copyOf(Iterable<? extends E> elements) { 201 // Hack around E not being a subtype of Comparable. 202 // Unsafe, see ImmutableSortedMultisetFauxverideShim. 203 @SuppressWarnings("unchecked") 204 Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural(); 205 return copyOf(naturalOrder, elements); 206 } 207 208 /** 209 * Returns an immutable sorted multiset containing the given elements sorted by their natural 210 * ordering. 211 * 212 * <p>This method is not type-safe, as it may be called on elements that are not mutually 213 * comparable. 214 * 215 * @throws ClassCastException if the elements are not mutually comparable 216 * @throws NullPointerException if any of {@code elements} is null 217 */ 218 public static <E> ImmutableSortedMultiset<E> copyOf(Iterator<? extends E> elements) { 219 // Hack around E not being a subtype of Comparable. 220 // Unsafe, see ImmutableSortedMultisetFauxverideShim. 221 @SuppressWarnings("unchecked") 222 Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural(); 223 return copyOfInternal(naturalOrder, elements); 224 } 225 226 /** 227 * Returns an immutable sorted multiset containing the given elements sorted by the given {@code 228 * Comparator}. 229 * 230 * @throws NullPointerException if {@code comparator} or any of {@code elements} is null 231 */ 232 public static <E> ImmutableSortedMultiset<E> copyOf( 233 Comparator<? super E> comparator, Iterator<? extends E> elements) { 234 checkNotNull(comparator); 235 return copyOfInternal(comparator, elements); 236 } 237 238 /** 239 * Returns an immutable sorted multiset containing the given elements sorted by the given {@code 240 * Comparator}. This method iterates over {@code elements} at most once. 241 * 242 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 243 * safe to do so. The exact circumstances under which a copy will or will not be performed are 244 * undocumented and subject to change. 245 * 246 * @throws NullPointerException if {@code comparator} or any of {@code elements} is null 247 */ 248 public static <E> ImmutableSortedMultiset<E> copyOf( 249 Comparator<? super E> comparator, Iterable<? extends E> elements) { 250 checkNotNull(comparator); 251 return copyOfInternal(comparator, elements); 252 } 253 254 /** 255 * Returns an immutable sorted multiset containing the elements of a sorted multiset, sorted by 256 * the same {@code Comparator}. That behavior differs from {@link #copyOf(Iterable)}, which 257 * always uses the natural ordering of the elements. 258 * 259 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 260 * safe to do so. The exact circumstances under which a copy will or will not be performed are 261 * undocumented and subject to change. 262 * 263 * <p>This method is safe to use even when {@code sortedMultiset} is a synchronized or concurrent 264 * collection that is currently being modified by another thread. 265 * 266 * @throws NullPointerException if {@code sortedMultiset} or any of its elements is null 267 */ 268 @SuppressWarnings("unchecked") 269 public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) { 270 Comparator<? super E> comparator = sortedMultiset.comparator(); 271 if (comparator == null) { 272 comparator = (Comparator<? super E>) NATURAL_ORDER; 273 } 274 return copyOfInternal(comparator, sortedMultiset); 275 } 276 277 @SuppressWarnings("unchecked") 278 private static <E> ImmutableSortedMultiset<E> copyOfInternal( 279 Comparator<? super E> comparator, Iterable<? extends E> iterable) { 280 if (SortedIterables.hasSameComparator(comparator, iterable) 281 && iterable instanceof ImmutableSortedMultiset<?>) { 282 ImmutableSortedMultiset<E> multiset = (ImmutableSortedMultiset<E>) iterable; 283 if (!multiset.isPartialView()) { 284 return (ImmutableSortedMultiset<E>) iterable; 285 } 286 } 287 ImmutableList<Entry<E>> entries = 288 (ImmutableList) ImmutableList.copyOf(SortedIterables.sortedCounts(comparator, iterable)); 289 if (entries.isEmpty()) { 290 return emptyMultiset(comparator); 291 } 292 verifyEntries(entries); 293 return RegularImmutableSortedMultiset.createFromSorted(comparator, entries); 294 } 295 296 private static <E> ImmutableSortedMultiset<E> copyOfInternal( 297 Comparator<? super E> comparator, Iterator<? extends E> iterator) { 298 @SuppressWarnings("unchecked") // We can safely cast from IL<Entry<? extends E>> to IL<Entry<E>> 299 ImmutableList<Entry<E>> entries = 300 (ImmutableList) ImmutableList.copyOf(SortedIterables.sortedCounts(comparator, iterator)); 301 if (entries.isEmpty()) { 302 return emptyMultiset(comparator); 303 } 304 verifyEntries(entries); 305 return RegularImmutableSortedMultiset.createFromSorted(comparator, entries); 306 } 307 308 private static <E> void verifyEntries(Collection<Entry<E>> entries) { 309 for (Entry<E> entry : entries) { 310 checkNotNull(entry.getElement()); 311 } 312 } 313 314 @SuppressWarnings("unchecked") 315 static <E> ImmutableSortedMultiset<E> emptyMultiset(Comparator<? super E> comparator) { 316 if (NATURAL_ORDER.equals(comparator)) { 317 return (ImmutableSortedMultiset) NATURAL_EMPTY_MULTISET; 318 } 319 return new EmptyImmutableSortedMultiset<E>(comparator); 320 } 321 322 private final transient Comparator<? super E> comparator; 323 324 ImmutableSortedMultiset(Comparator<? super E> comparator) { 325 this.comparator = checkNotNull(comparator); 326 } 327 328 @Override 329 public Comparator<? super E> comparator() { 330 return comparator; 331 } 332 333 // Pretend the comparator can compare anything. If it turns out it can't 334 // compare two elements, it'll throw a CCE. Only methods that are specified to 335 // throw CCE should call this. 336 @SuppressWarnings("unchecked") 337 Comparator<Object> unsafeComparator() { 338 return (Comparator<Object>) comparator; 339 } 340 341 private transient Comparator<? super E> reverseComparator; 342 343 Comparator<? super E> reverseComparator() { 344 Comparator<? super E> result = reverseComparator; 345 if (result == null) { 346 return reverseComparator = Ordering.from(comparator).<E>reverse(); 347 } 348 return result; 349 } 350 351 private transient ImmutableSortedSet<E> elementSet; 352 353 @Override 354 public ImmutableSortedSet<E> elementSet() { 355 ImmutableSortedSet<E> result = elementSet; 356 if (result == null) { 357 return elementSet = createElementSet(); 358 } 359 return result; 360 } 361 362 abstract ImmutableSortedSet<E> createElementSet(); 363 364 abstract ImmutableSortedSet<E> createDescendingElementSet(); 365 366 transient ImmutableSortedMultiset<E> descendingMultiset; 367 368 @Override 369 public ImmutableSortedMultiset<E> descendingMultiset() { 370 ImmutableSortedMultiset<E> result = descendingMultiset; 371 if (result == null) { 372 return descendingMultiset = new DescendingImmutableSortedMultiset<E>(this); 373 } 374 return result; 375 } 376 377 /** 378 * {@inheritDoc} 379 * 380 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 381 * 382 * @throws UnsupportedOperationException always 383 */ 384 @Override 385 public final Entry<E> pollFirstEntry() { 386 throw new UnsupportedOperationException(); 387 } 388 389 /** 390 * {@inheritDoc} 391 * 392 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 393 * 394 * @throws UnsupportedOperationException always 395 */ 396 @Override 397 public Entry<E> pollLastEntry() { 398 throw new UnsupportedOperationException(); 399 } 400 401 @Override 402 public abstract ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType); 403 404 @Override 405 public ImmutableSortedMultiset<E> subMultiset( 406 E lowerBound, BoundType lowerBoundType, E upperBound, BoundType upperBoundType) { 407 return tailMultiset(lowerBound, lowerBoundType).headMultiset(upperBound, upperBoundType); 408 } 409 410 @Override 411 public abstract ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType); 412 413 /** 414 * Returns a builder that creates immutable sorted multisets with an explicit comparator. If the 415 * comparator has a more general type than the set being generated, such as creating a {@code 416 * SortedMultiset<Integer>} with a {@code Comparator<Number>}, use the {@link Builder} 417 * constructor instead. 418 * 419 * @throws NullPointerException if {@code comparator} is null 420 */ 421 public static <E> Builder<E> orderedBy(Comparator<E> comparator) { 422 return new Builder<E>(comparator); 423 } 424 425 /** 426 * Returns a builder that creates immutable sorted multisets whose elements are ordered by the 427 * reverse of their natural ordering. 428 * 429 * <p>Note: the type parameter {@code E} extends {@code Comparable<E>} 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<E>> Builder<E> reverseOrder() { 434 return new Builder<E>(Ordering.natural().reverse()); 435 } 436 437 /** 438 * Returns a builder that creates immutable sorted multisets whose elements are ordered by their 439 * natural ordering. The sorted multisets use {@link Ordering#natural()} as the comparator. This 440 * method provides more type-safety than {@link #builder}, as it can be called only for classes 441 * that implement {@link Comparable}. 442 * 443 * <p>Note: the type parameter {@code E} extends {@code Comparable<E>} rather than {@code 444 * Comparable<? super E>} as a workaround for javac <a 445 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>. 446 */ 447 public static <E extends Comparable<E>> Builder<E> naturalOrder() { 448 return new Builder<E>(Ordering.natural()); 449 } 450 451 /** 452 * A builder for creating immutable multiset instances, especially {@code public static final} 453 * multisets ("constant multisets"). Example: 454 * 455 * <pre> {@code 456 * 457 * public static final ImmutableSortedMultiset<Bean> BEANS = 458 * new ImmutableSortedMultiset.Builder<Bean>() 459 * .addCopies(Bean.COCOA, 4) 460 * .addCopies(Bean.GARDEN, 6) 461 * .addCopies(Bean.RED, 8) 462 * .addCopies(Bean.BLACK_EYED, 10) 463 * .build();}</pre> 464 * 465 * Builder instances can be reused; it is safe to call {@link #build} multiple times to build 466 * multiple multisets in series. 467 * 468 * @since 12.0 469 */ 470 public static class Builder<E> extends ImmutableMultiset.Builder<E> { 471 private final Comparator<? super E> comparator; 472 473 /** 474 * Creates a new builder. The returned builder is equivalent to the builder generated by 475 * {@link ImmutableSortedMultiset#orderedBy(Comparator)}. 476 */ 477 public Builder(Comparator<? super E> comparator) { 478 super(TreeMultiset.<E>create(comparator)); 479 this.comparator = checkNotNull(comparator); 480 } 481 482 /** 483 * Adds {@code element} to the {@code ImmutableSortedMultiset}. 484 * 485 * @param element the element to add 486 * @return this {@code Builder} object 487 * @throws NullPointerException if {@code element} is null 488 */ 489 @Override 490 public Builder<E> add(E element) { 491 super.add(element); 492 return this; 493 } 494 495 /** 496 * Adds a number of occurrences of an element to this {@code ImmutableSortedMultiset}. 497 * 498 * @param element the element to add 499 * @param occurrences the number of occurrences of the element to add. May be zero, in which 500 * case no change will be made. 501 * @return this {@code Builder} object 502 * @throws NullPointerException if {@code element} is null 503 * @throws IllegalArgumentException if {@code occurrences} is negative, or if this operation 504 * would result in more than {@link Integer#MAX_VALUE} occurrences of the element 505 */ 506 @Override 507 public Builder<E> addCopies(E element, int occurrences) { 508 super.addCopies(element, occurrences); 509 return this; 510 } 511 512 /** 513 * Adds or removes the necessary occurrences of an element such that the element attains the 514 * desired count. 515 * 516 * @param element the element to add or remove occurrences of 517 * @param count the desired count of the element in this multiset 518 * @return this {@code Builder} object 519 * @throws NullPointerException if {@code element} is null 520 * @throws IllegalArgumentException if {@code count} is negative 521 */ 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 elements to add 532 * @return this {@code Builder} object 533 * @throws NullPointerException if {@code elements} is null or contains a null element 534 */ 535 @Override 536 public Builder<E> add(E... elements) { 537 super.add(elements); 538 return this; 539 } 540 541 /** 542 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 543 * 544 * @param elements the {@code Iterable} to add to the {@code ImmutableSortedMultiset} 545 * @return this {@code Builder} object 546 * @throws NullPointerException if {@code elements} is null or contains a null element 547 */ 548 @Override 549 public Builder<E> addAll(Iterable<? extends E> elements) { 550 super.addAll(elements); 551 return this; 552 } 553 554 /** 555 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 556 * 557 * @param elements the elements to add to the {@code ImmutableSortedMultiset} 558 * @return this {@code Builder} object 559 * @throws NullPointerException if {@code elements} is null or contains a null element 560 */ 561 @Override 562 public Builder<E> addAll(Iterator<? extends E> elements) { 563 super.addAll(elements); 564 return this; 565 } 566 567 /** 568 * Returns a newly-created {@code ImmutableSortedMultiset} based on the contents of the {@code 569 * Builder}. 570 */ 571 @Override 572 public ImmutableSortedMultiset<E> build() { 573 return copyOf(comparator, contents); 574 } 575 } 576 577 private static final class SerializedForm implements Serializable { 578 Comparator comparator; 579 Object[] elements; 580 int[] counts; 581 582 SerializedForm(SortedMultiset<?> multiset) { 583 this.comparator = multiset.comparator(); 584 int n = multiset.entrySet().size(); 585 elements = new Object[n]; 586 counts = new int[n]; 587 int i = 0; 588 for (Entry<?> entry : multiset.entrySet()) { 589 elements[i] = entry.getElement(); 590 counts[i] = entry.getCount(); 591 i++; 592 } 593 } 594 595 @SuppressWarnings("unchecked") 596 Object readResolve() { 597 int n = elements.length; 598 Builder<Object> builder = orderedBy(comparator); 599 for (int i = 0; i < n; i++) { 600 builder.addCopies(elements[i], counts[i]); 601 } 602 return builder.build(); 603 } 604 } 605 606 @Override 607 Object writeReplace() { 608 return new SerializedForm(this); 609 } 610 }