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.common.annotations.VisibleForTesting; 022import com.google.common.math.IntMath; 023import com.google.errorprone.annotations.CanIgnoreReturnValue; 024import com.google.errorprone.annotations.DoNotCall; 025import com.google.errorprone.annotations.concurrent.LazyInit; 026import java.io.Serializable; 027import java.util.Arrays; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.Comparator; 031import java.util.Iterator; 032import java.util.List; 033 034/** 035 * A {@link SortedMultiset} whose contents will never change, with many other important properties 036 * detailed at {@link ImmutableCollection}. 037 * 038 * <p><b>Warning:</b> as with any sorted collection, you are strongly advised not to use a {@link 039 * Comparator} or {@link Comparable} type whose comparison behavior is <i>inconsistent with 040 * equals</i>. That is, {@code a.compareTo(b)} or {@code comparator.compare(a, b)} should equal zero 041 * <i>if and only if</i> {@code a.equals(b)}. If this advice is not followed, the resulting 042 * collection will not correctly obey its specification. 043 * 044 * <p>See the Guava User Guide article on <a href= 045 * "https://github.com/google/guava/wiki/ImmutableCollectionsExplained"> immutable collections</a>. 046 * 047 * @author Louis Wasserman 048 * @since 12.0 049 */ 050@GwtIncompatible // hasn't been tested yet 051public abstract class ImmutableSortedMultiset<E> extends ImmutableSortedMultisetFauxverideShim<E> 052 implements SortedMultiset<E> { 053 // TODO(lowasser): GWT compatibility 054 055 /** Returns the empty immutable sorted multiset. */ 056 @SuppressWarnings("unchecked") 057 public static <E> ImmutableSortedMultiset<E> of() { 058 return (ImmutableSortedMultiset) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; 059 } 060 061 /** Returns an immutable sorted multiset containing a single element. */ 062 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E element) { 063 RegularImmutableSortedSet<E> elementSet = 064 (RegularImmutableSortedSet<E>) ImmutableSortedSet.of(element); 065 long[] cumulativeCounts = {0, 1}; 066 return new RegularImmutableSortedMultiset<E>(elementSet, cumulativeCounts, 0, 1); 067 } 068 069 /** 070 * Returns an immutable sorted multiset containing the given elements sorted by their natural 071 * ordering. 072 * 073 * @throws NullPointerException if any element is null 074 */ 075 @SuppressWarnings("unchecked") 076 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2) { 077 return copyOf(Ordering.natural(), Arrays.asList(e1, e2)); 078 } 079 080 /** 081 * Returns an immutable sorted multiset containing the given elements sorted by their natural 082 * ordering. 083 * 084 * @throws NullPointerException if any element is null 085 */ 086 @SuppressWarnings("unchecked") 087 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) { 088 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3)); 089 } 090 091 /** 092 * Returns an immutable sorted multiset containing the given elements sorted by their natural 093 * ordering. 094 * 095 * @throws NullPointerException if any element is null 096 */ 097 @SuppressWarnings("unchecked") 098 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 099 E e1, E e2, E e3, E e4) { 100 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4)); 101 } 102 103 /** 104 * Returns an immutable sorted multiset containing the given elements sorted by their natural 105 * ordering. 106 * 107 * @throws NullPointerException if any element is null 108 */ 109 @SuppressWarnings("unchecked") 110 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 111 E e1, E e2, E e3, E e4, E e5) { 112 return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4, e5)); 113 } 114 115 /** 116 * Returns an immutable sorted multiset containing the given elements sorted by their natural 117 * ordering. 118 * 119 * @throws NullPointerException if any element is null 120 */ 121 @SuppressWarnings("unchecked") 122 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of( 123 E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) { 124 int size = remaining.length + 6; 125 List<E> all = Lists.newArrayListWithCapacity(size); 126 Collections.addAll(all, e1, e2, e3, e4, e5, e6); 127 Collections.addAll(all, remaining); 128 return copyOf(Ordering.natural(), all); 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 of {@code elements} is null 136 */ 137 public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> copyOf(E[] elements) { 138 return copyOf(Ordering.natural(), Arrays.asList(elements)); 139 } 140 141 /** 142 * Returns an immutable sorted multiset containing the given elements sorted by their natural 143 * ordering. To create a copy of a {@code SortedMultiset} that preserves the comparator, call 144 * {@link #copyOfSorted} instead. This method iterates over {@code elements} at most once. 145 * 146 * <p>Note that if {@code s} is a {@code Multiset<String>}, then {@code 147 * ImmutableSortedMultiset.copyOf(s)} returns an {@code ImmutableSortedMultiset<String>} 148 * containing each of the strings in {@code s}, while {@code ImmutableSortedMultiset.of(s)} 149 * returns an {@code ImmutableSortedMultiset<Multiset<String>>} containing one element (the given 150 * multiset itself). 151 * 152 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 153 * safe to do so. The exact circumstances under which a copy will or will not be performed are 154 * undocumented and subject to change. 155 * 156 * <p>This method is not type-safe, as it may be called on elements that are not mutually 157 * comparable. 158 * 159 * @throws ClassCastException if the elements are not mutually comparable 160 * @throws NullPointerException if any of {@code elements} is null 161 */ 162 public static <E> ImmutableSortedMultiset<E> copyOf(Iterable<? extends E> elements) { 163 // Hack around E not being a subtype of Comparable. 164 // Unsafe, see ImmutableSortedMultisetFauxverideShim. 165 @SuppressWarnings("unchecked") 166 Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural(); 167 return copyOf(naturalOrder, elements); 168 } 169 170 /** 171 * Returns an immutable sorted multiset containing the given elements sorted by their natural 172 * ordering. 173 * 174 * <p>This method is not type-safe, as it may be called on elements that are not mutually 175 * comparable. 176 * 177 * @throws ClassCastException if the elements are not mutually comparable 178 * @throws NullPointerException if any of {@code elements} is null 179 */ 180 public static <E> ImmutableSortedMultiset<E> copyOf(Iterator<? extends E> elements) { 181 // Hack around E not being a subtype of Comparable. 182 // Unsafe, see ImmutableSortedMultisetFauxverideShim. 183 @SuppressWarnings("unchecked") 184 Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural(); 185 return copyOf(naturalOrder, elements); 186 } 187 188 /** 189 * Returns an immutable sorted multiset containing the given elements sorted by the given {@code 190 * Comparator}. 191 * 192 * @throws NullPointerException if {@code comparator} or any of {@code elements} is null 193 */ 194 public static <E> ImmutableSortedMultiset<E> copyOf( 195 Comparator<? super E> comparator, Iterator<? extends E> elements) { 196 checkNotNull(comparator); 197 return new Builder<E>(comparator).addAll(elements).build(); 198 } 199 200 /** 201 * Returns an immutable sorted multiset containing the given elements sorted by the given {@code 202 * Comparator}. This method iterates over {@code elements} at most once. 203 * 204 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 205 * safe to do so. The exact circumstances under which a copy will or will not be performed are 206 * undocumented and subject to change. 207 * 208 * @throws NullPointerException if {@code comparator} or any of {@code elements} is null 209 */ 210 @SuppressWarnings("unchecked") 211 public static <E> ImmutableSortedMultiset<E> copyOf( 212 Comparator<? super E> comparator, Iterable<? extends E> elements) { 213 if (elements instanceof ImmutableSortedMultiset) { 214 @SuppressWarnings("unchecked") // immutable collections are always safe for covariant casts 215 ImmutableSortedMultiset<E> multiset = (ImmutableSortedMultiset<E>) elements; 216 if (comparator.equals(multiset.comparator())) { 217 if (multiset.isPartialView()) { 218 return copyOfSortedEntries(comparator, multiset.entrySet().asList()); 219 } else { 220 return multiset; 221 } 222 } 223 } 224 return new ImmutableSortedMultiset.Builder<E>(comparator).addAll(elements).build(); 225 } 226 227 /** 228 * Returns an immutable sorted multiset containing the elements of a sorted multiset, sorted by 229 * the same {@code Comparator}. That behavior differs from {@link #copyOf(Iterable)}, which always 230 * uses the natural ordering of the elements. 231 * 232 * <p>Despite the method name, this method attempts to avoid actually copying the data when it is 233 * safe to do so. The exact circumstances under which a copy will or will not be performed are 234 * undocumented and subject to change. 235 * 236 * <p>This method is safe to use even when {@code sortedMultiset} is a synchronized or concurrent 237 * collection that is currently being modified by another thread. 238 * 239 * @throws NullPointerException if {@code sortedMultiset} or any of its elements is null 240 */ 241 public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) { 242 return copyOfSortedEntries( 243 sortedMultiset.comparator(), Lists.newArrayList(sortedMultiset.entrySet())); 244 } 245 246 private static <E> ImmutableSortedMultiset<E> copyOfSortedEntries( 247 Comparator<? super E> comparator, Collection<Entry<E>> entries) { 248 if (entries.isEmpty()) { 249 return emptyMultiset(comparator); 250 } 251 ImmutableList.Builder<E> elementsBuilder = new ImmutableList.Builder<E>(entries.size()); 252 long[] cumulativeCounts = new long[entries.size() + 1]; 253 int i = 0; 254 for (Entry<E> entry : entries) { 255 elementsBuilder.add(entry.getElement()); 256 cumulativeCounts[i + 1] = cumulativeCounts[i] + entry.getCount(); 257 i++; 258 } 259 return new RegularImmutableSortedMultiset<E>( 260 new RegularImmutableSortedSet<E>(elementsBuilder.build(), comparator), 261 cumulativeCounts, 262 0, 263 entries.size()); 264 } 265 266 @SuppressWarnings("unchecked") 267 static <E> ImmutableSortedMultiset<E> emptyMultiset(Comparator<? super E> comparator) { 268 if (Ordering.natural().equals(comparator)) { 269 return (ImmutableSortedMultiset<E>) RegularImmutableSortedMultiset.NATURAL_EMPTY_MULTISET; 270 } else { 271 return new RegularImmutableSortedMultiset<E>(comparator); 272 } 273 } 274 275 ImmutableSortedMultiset() {} 276 277 @Override 278 public final Comparator<? super E> comparator() { 279 return elementSet().comparator(); 280 } 281 282 @Override 283 public abstract ImmutableSortedSet<E> elementSet(); 284 285 @LazyInit transient ImmutableSortedMultiset<E> descendingMultiset; 286 287 @Override 288 public ImmutableSortedMultiset<E> descendingMultiset() { 289 ImmutableSortedMultiset<E> result = descendingMultiset; 290 if (result == null) { 291 return descendingMultiset = 292 this.isEmpty() 293 ? emptyMultiset(Ordering.from(comparator()).reverse()) 294 : new DescendingImmutableSortedMultiset<E>(this); 295 } 296 return result; 297 } 298 299 /** 300 * {@inheritDoc} 301 * 302 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 303 * 304 * @throws UnsupportedOperationException always 305 * @deprecated Unsupported operation. 306 */ 307 @CanIgnoreReturnValue 308 @Deprecated 309 @Override 310 @DoNotCall("Always throws UnsupportedOperationException") 311 public final Entry<E> pollFirstEntry() { 312 throw new UnsupportedOperationException(); 313 } 314 315 /** 316 * {@inheritDoc} 317 * 318 * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}. 319 * 320 * @throws UnsupportedOperationException always 321 * @deprecated Unsupported operation. 322 */ 323 @CanIgnoreReturnValue 324 @Deprecated 325 @Override 326 @DoNotCall("Always throws UnsupportedOperationException") 327 public final Entry<E> pollLastEntry() { 328 throw new UnsupportedOperationException(); 329 } 330 331 @Override 332 public abstract ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType); 333 334 @Override 335 public ImmutableSortedMultiset<E> subMultiset( 336 E lowerBound, BoundType lowerBoundType, E upperBound, BoundType upperBoundType) { 337 checkArgument( 338 comparator().compare(lowerBound, upperBound) <= 0, 339 "Expected lowerBound <= upperBound but %s > %s", 340 lowerBound, 341 upperBound); 342 return tailMultiset(lowerBound, lowerBoundType).headMultiset(upperBound, upperBoundType); 343 } 344 345 @Override 346 public abstract ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType); 347 348 /** 349 * Returns a builder that creates immutable sorted multisets with an explicit comparator. If the 350 * comparator has a more general type than the set being generated, such as creating a {@code 351 * SortedMultiset<Integer>} with a {@code Comparator<Number>}, use the {@link Builder} constructor 352 * instead. 353 * 354 * @throws NullPointerException if {@code comparator} is null 355 */ 356 public static <E> Builder<E> orderedBy(Comparator<E> comparator) { 357 return new Builder<E>(comparator); 358 } 359 360 /** 361 * Returns a builder that creates immutable sorted multisets whose elements are ordered by the 362 * reverse of their natural ordering. 363 * 364 * <p>Note: the type parameter {@code E} extends {@code Comparable<?>} rather than {@code 365 * Comparable<? super E>} as a workaround for javac <a 366 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>. 367 */ 368 public static <E extends Comparable<?>> Builder<E> reverseOrder() { 369 return new Builder<E>(Ordering.natural().reverse()); 370 } 371 372 /** 373 * Returns a builder that creates immutable sorted multisets whose elements are ordered by their 374 * natural ordering. The sorted multisets use {@link Ordering#natural()} as the comparator. This 375 * method provides more type-safety than {@link #builder}, as it can be called only for classes 376 * that implement {@link Comparable}. 377 * 378 * <p>Note: the type parameter {@code E} extends {@code Comparable<?>} rather than {@code 379 * Comparable<? super E>} as a workaround for javac <a 380 * href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6468354">bug 6468354</a>. 381 */ 382 public static <E extends Comparable<?>> Builder<E> naturalOrder() { 383 return new Builder<E>(Ordering.natural()); 384 } 385 386 /** 387 * A builder for creating immutable multiset instances, especially {@code public static final} 388 * multisets ("constant multisets"). Example: 389 * 390 * <pre>{@code 391 * public static final ImmutableSortedMultiset<Bean> BEANS = 392 * new ImmutableSortedMultiset.Builder<Bean>(colorComparator()) 393 * .addCopies(Bean.COCOA, 4) 394 * .addCopies(Bean.GARDEN, 6) 395 * .addCopies(Bean.RED, 8) 396 * .addCopies(Bean.BLACK_EYED, 10) 397 * .build(); 398 * }</pre> 399 * 400 * <p>Builder instances can be reused; it is safe to call {@link #build} multiple times to build 401 * multiple multisets in series. 402 * 403 * @since 12.0 404 */ 405 public static class Builder<E> extends ImmutableMultiset.Builder<E> { 406 /* 407 * We keep an array of elements and counts. Periodically -- when we need more room in the 408 * array, or when we're building, or the like -- we sort, deduplicate, and combine the counts. 409 * Negative counts indicate a setCount operation with ~counts[i]. 410 */ 411 412 private final Comparator<? super E> comparator; 413 414 @VisibleForTesting E[] elements; 415 private int[] counts; 416 417 /* 418 * The number of used positions in the elements array. We deduplicate periodically, so this 419 * may fluctuate up and down. 420 */ 421 private int length; 422 423 // True if we just called build() and the elements array is being used by a created ISM, meaning 424 // we shouldn't modify that array further. 425 private boolean forceCopyElements; 426 427 /** 428 * Creates a new builder. The returned builder is equivalent to the builder generated by {@link 429 * ImmutableSortedMultiset#orderedBy(Comparator)}. 430 */ 431 @SuppressWarnings("unchecked") 432 public Builder(Comparator<? super E> comparator) { 433 super(true); // doesn't allocate hash table in supertype 434 this.comparator = checkNotNull(comparator); 435 this.elements = (E[]) new Object[ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY]; 436 this.counts = new int[ImmutableCollection.Builder.DEFAULT_INITIAL_CAPACITY]; 437 } 438 439 /** Check if we need to do deduplication and coalescing, and if so, do it. */ 440 private void maintenance() { 441 if (length == elements.length) { 442 dedupAndCoalesce(true); 443 } else if (forceCopyElements) { 444 this.elements = Arrays.copyOf(elements, elements.length); 445 // we don't currently need to copy the counts array, because we don't use it directly 446 // in built ISMs 447 } 448 forceCopyElements = false; 449 } 450 451 private void dedupAndCoalesce(boolean maybeExpand) { 452 if (length == 0) { 453 return; 454 } 455 E[] sortedElements = Arrays.copyOf(elements, length); 456 Arrays.sort(sortedElements, comparator); 457 int uniques = 1; 458 for (int i = 1; i < sortedElements.length; i++) { 459 if (comparator.compare(sortedElements[uniques - 1], sortedElements[i]) < 0) { 460 sortedElements[uniques] = sortedElements[i]; 461 uniques++; 462 } 463 } 464 Arrays.fill(sortedElements, uniques, length, null); 465 if (maybeExpand && uniques * 4 > length * 3) { 466 // lots of nonduplicated elements, expand the array by 50% 467 sortedElements = 468 Arrays.copyOf(sortedElements, IntMath.saturatedAdd(length, length / 2 + 1)); 469 } 470 int[] sortedCounts = new int[sortedElements.length]; 471 for (int i = 0; i < length; i++) { 472 int index = Arrays.binarySearch(sortedElements, 0, uniques, elements[i], comparator); 473 if (counts[i] >= 0) { 474 sortedCounts[index] += counts[i]; 475 } else { 476 sortedCounts[index] = ~counts[i]; 477 } 478 } 479 // Note that we're not getting rid, yet, of elements with count 0. We'll do that in build(). 480 this.elements = sortedElements; 481 this.counts = sortedCounts; 482 this.length = uniques; 483 } 484 485 /** 486 * Adds {@code element} to the {@code ImmutableSortedMultiset}. 487 * 488 * @param element the element to add 489 * @return this {@code Builder} object 490 * @throws NullPointerException if {@code element} is null 491 */ 492 @CanIgnoreReturnValue 493 @Override 494 public Builder<E> add(E element) { 495 return addCopies(element, 1); 496 } 497 498 /** 499 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 500 * 501 * @param elements the elements to add 502 * @return this {@code Builder} object 503 * @throws NullPointerException if {@code elements} is null or contains a null element 504 */ 505 @CanIgnoreReturnValue 506 @Override 507 public Builder<E> add(E... elements) { 508 for (E element : elements) { 509 add(element); 510 } 511 return this; 512 } 513 514 /** 515 * Adds a number of occurrences of an element to this {@code ImmutableSortedMultiset}. 516 * 517 * @param element the element to add 518 * @param occurrences the number of occurrences of the element to add. May be zero, in which 519 * case no change will be made. 520 * @return this {@code Builder} object 521 * @throws NullPointerException if {@code element} is null 522 * @throws IllegalArgumentException if {@code occurrences} is negative, or if this operation 523 * would result in more than {@link Integer#MAX_VALUE} occurrences of the element 524 */ 525 @CanIgnoreReturnValue 526 @Override 527 public Builder<E> addCopies(E element, int occurrences) { 528 checkNotNull(element); 529 CollectPreconditions.checkNonnegative(occurrences, "occurrences"); 530 if (occurrences == 0) { 531 return this; 532 } 533 maintenance(); 534 elements[length] = element; 535 counts[length] = occurrences; 536 length++; 537 return this; 538 } 539 540 /** 541 * Adds or removes the necessary occurrences of an element such that the element attains the 542 * desired count. 543 * 544 * @param element the element to add or remove occurrences of 545 * @param count the desired count of the element in this multiset 546 * @return this {@code Builder} object 547 * @throws NullPointerException if {@code element} is null 548 * @throws IllegalArgumentException if {@code count} is negative 549 */ 550 @CanIgnoreReturnValue 551 @Override 552 public Builder<E> setCount(E element, int count) { 553 checkNotNull(element); 554 CollectPreconditions.checkNonnegative(count, "count"); 555 maintenance(); 556 elements[length] = element; 557 counts[length] = ~count; 558 length++; 559 return this; 560 } 561 562 /** 563 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 564 * 565 * @param elements the {@code Iterable} to add to the {@code ImmutableSortedMultiset} 566 * @return this {@code Builder} object 567 * @throws NullPointerException if {@code elements} is null or contains a null element 568 */ 569 @CanIgnoreReturnValue 570 @Override 571 public Builder<E> addAll(Iterable<? extends E> elements) { 572 if (elements instanceof Multiset) { 573 for (Entry<? extends E> entry : ((Multiset<? extends E>) elements).entrySet()) { 574 addCopies(entry.getElement(), entry.getCount()); 575 } 576 } else { 577 for (E e : elements) { 578 add(e); 579 } 580 } 581 return this; 582 } 583 584 /** 585 * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}. 586 * 587 * @param elements the elements to add to the {@code ImmutableSortedMultiset} 588 * @return this {@code Builder} object 589 * @throws NullPointerException if {@code elements} is null or contains a null element 590 */ 591 @CanIgnoreReturnValue 592 @Override 593 public Builder<E> addAll(Iterator<? extends E> elements) { 594 while (elements.hasNext()) { 595 add(elements.next()); 596 } 597 return this; 598 } 599 600 private void dedupAndCoalesceAndDeleteEmpty() { 601 dedupAndCoalesce(false); 602 603 // If there was a setCount(elem, 0), those elements are still present. Eliminate them. 604 int size = 0; 605 for (int i = 0; i < length; i++) { 606 if (counts[i] > 0) { 607 elements[size] = elements[i]; 608 counts[size] = counts[i]; 609 size++; 610 } 611 } 612 Arrays.fill(elements, size, length, null); 613 Arrays.fill(counts, size, length, 0); 614 length = size; 615 } 616 617 /** 618 * Returns a newly-created {@code ImmutableSortedMultiset} based on the contents of the {@code 619 * Builder}. 620 */ 621 @Override 622 public ImmutableSortedMultiset<E> build() { 623 dedupAndCoalesceAndDeleteEmpty(); 624 if (length == 0) { 625 return emptyMultiset(comparator); 626 } 627 RegularImmutableSortedSet<E> elementSet = 628 (RegularImmutableSortedSet<E>) ImmutableSortedSet.construct(comparator, length, elements); 629 long[] cumulativeCounts = new long[length + 1]; 630 for (int i = 0; i < length; i++) { 631 cumulativeCounts[i + 1] = cumulativeCounts[i] + counts[i]; 632 } 633 forceCopyElements = true; 634 return new RegularImmutableSortedMultiset<E>(elementSet, cumulativeCounts, 0, length); 635 } 636 } 637 638 private static final class SerializedForm<E> implements Serializable { 639 final Comparator<? super E> comparator; 640 final E[] elements; 641 final int[] counts; 642 643 @SuppressWarnings("unchecked") 644 SerializedForm(SortedMultiset<E> multiset) { 645 this.comparator = multiset.comparator(); 646 int n = multiset.entrySet().size(); 647 elements = (E[]) new Object[n]; 648 counts = new int[n]; 649 int i = 0; 650 for (Entry<E> entry : multiset.entrySet()) { 651 elements[i] = entry.getElement(); 652 counts[i] = entry.getCount(); 653 i++; 654 } 655 } 656 657 Object readResolve() { 658 int n = elements.length; 659 Builder<E> builder = new Builder<>(comparator); 660 for (int i = 0; i < n; i++) { 661 builder.addCopies(elements[i], counts[i]); 662 } 663 return builder.build(); 664 } 665 } 666 667 @Override 668 Object writeReplace() { 669 return new SerializedForm<E>(this); 670 } 671}