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