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