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