001    /*
002     * Copyright (C) 2007 Google Inc.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package com.google.common.collect;
018    
019    import static com.google.common.base.Preconditions.checkArgument;
020    import static com.google.common.base.Preconditions.checkNotNull;
021    import static com.google.common.base.Preconditions.checkState;
022    
023    import com.google.common.annotations.GwtCompatible;
024    import com.google.common.base.Objects;
025    import com.google.common.collect.Multiset.Entry;
026    import com.google.common.primitives.Ints;
027    
028    import java.io.Serializable;
029    import java.util.AbstractSet;
030    import java.util.Collection;
031    import java.util.Collections;
032    import java.util.Iterator;
033    import java.util.NoSuchElementException;
034    import java.util.Set;
035    
036    import javax.annotation.Nullable;
037    
038    /**
039     * Provides static utility methods for creating and working with {@link
040     * Multiset} instances.
041     *
042     * @author Kevin Bourrillion
043     * @author Mike Bostock
044     * @author Louis Wasserman
045     * @since 2 (imported from Google Collections Library)
046     */
047    @GwtCompatible
048    public final class Multisets {
049      private Multisets() {}
050    
051      /**
052       * Returns an unmodifiable view of the specified multiset. Query operations on
053       * the returned multiset "read through" to the specified multiset, and
054       * attempts to modify the returned multiset result in an
055       * {@link UnsupportedOperationException}.
056       *
057       * <p>The returned multiset will be serializable if the specified multiset is
058       * serializable.
059       *
060       * @param multiset the multiset for which an unmodifiable view is to be
061       *     generated
062       * @return an unmodifiable view of the multiset
063       */
064      public static <E> Multiset<E> unmodifiableMultiset(
065          Multiset<? extends E> multiset) {
066        return new UnmodifiableMultiset<E>(checkNotNull(multiset));
067      }
068    
069      private static class UnmodifiableMultiset<E>
070          extends ForwardingMultiset<E> implements Serializable {
071        final Multiset<? extends E> delegate;
072    
073        UnmodifiableMultiset(Multiset<? extends E> delegate) {
074          this.delegate = delegate;
075        }
076    
077        @SuppressWarnings("unchecked")
078        @Override protected Multiset<E> delegate() {
079          // This is safe because all non-covariant methods are overriden
080          return (Multiset) delegate;
081        }
082    
083        transient Set<E> elementSet;
084    
085        @Override public Set<E> elementSet() {
086          Set<E> es = elementSet;
087          return (es == null)
088              ? elementSet = Collections.<E>unmodifiableSet(delegate.elementSet())
089              : es;
090        }
091    
092        transient Set<Multiset.Entry<E>> entrySet;
093    
094        @SuppressWarnings("unchecked")
095        @Override public Set<Multiset.Entry<E>> entrySet() {
096          Set<Multiset.Entry<E>> es = entrySet;
097          return (es == null)
098              // Safe because the returned set is made unmodifiable and Entry
099              // itself is readonly
100              ? entrySet = (Set) Collections.unmodifiableSet(delegate.entrySet())
101              : es;
102        }
103    
104        @SuppressWarnings("unchecked")
105        @Override public Iterator<E> iterator() {
106          // Safe because the returned Iterator is made unmodifiable
107          return (Iterator) Iterators.unmodifiableIterator(delegate.iterator());
108        }
109    
110        @Override public boolean add(E element) {
111          throw new UnsupportedOperationException();
112        }
113    
114        @Override public int add(E element, int occurences) {
115          throw new UnsupportedOperationException();
116        }
117    
118        @Override public boolean addAll(Collection<? extends E> elementsToAdd) {
119          throw new UnsupportedOperationException();
120        }
121    
122        @Override public boolean remove(Object element) {
123          throw new UnsupportedOperationException();
124        }
125    
126        @Override public int remove(Object element, int occurrences) {
127          throw new UnsupportedOperationException();
128        }
129    
130        @Override public boolean removeAll(Collection<?> elementsToRemove) {
131          throw new UnsupportedOperationException();
132        }
133    
134        @Override public boolean retainAll(Collection<?> elementsToRetain) {
135          throw new UnsupportedOperationException();
136        }
137    
138        @Override public void clear() {
139          throw new UnsupportedOperationException();
140        }
141    
142        @Override public int setCount(E element, int count) {
143          throw new UnsupportedOperationException();
144        }
145    
146        @Override public boolean setCount(E element, int oldCount, int newCount) {
147          throw new UnsupportedOperationException();
148        }
149    
150        private static final long serialVersionUID = 0;
151      }
152    
153      /**
154       * Returns an immutable multiset entry with the specified element and count.
155       *
156       * @param e the element to be associated with the returned entry
157       * @param n the count to be associated with the returned entry
158       * @throws IllegalArgumentException if {@code n} is negative
159       */
160      public static <E> Multiset.Entry<E> immutableEntry(
161          @Nullable final E e, final int n) {
162        checkArgument(n >= 0);
163        return new AbstractEntry<E>() {
164          public E getElement() {
165            return e;
166          }
167          public int getCount() {
168            return n;
169          }
170        };
171      }
172    
173      /**
174       * Returns a multiset view of the specified set. The multiset is backed by the
175       * set, so changes to the set are reflected in the multiset, and vice versa.
176       * If the set is modified while an iteration over the multiset is in progress
177       * (except through the iterator's own {@code remove} operation) the results of
178       * the iteration are undefined.
179       *
180       * <p>The multiset supports element removal, which removes the corresponding
181       * element from the set. It does not support the {@code add} or {@code addAll}
182       * operations, nor does it support the use of {@code setCount} to add
183       * elements.
184       *
185       * <p>The returned multiset will be serializable if the specified set is
186       * serializable. The multiset is threadsafe if the set is threadsafe.
187       *
188       * @param set the backing set for the returned multiset view
189       */
190      static <E> Multiset<E> forSet(Set<E> set) {
191        return new SetMultiset<E>(set);
192      }
193    
194      /** @see Multisets#forSet */
195      private static class SetMultiset<E> extends ForwardingCollection<E>
196          implements Multiset<E>, Serializable {
197        final Set<E> delegate;
198    
199        SetMultiset(Set<E> set) {
200          delegate = checkNotNull(set);
201        }
202    
203        @Override protected Set<E> delegate() {
204          return delegate;
205        }
206    
207        public int count(Object element) {
208          return delegate.contains(element) ? 1 : 0;
209        }
210    
211        public int add(E element, int occurrences) {
212          throw new UnsupportedOperationException();
213        }
214    
215        public int remove(Object element, int occurrences) {
216          if (occurrences == 0) {
217            return count(element);
218          }
219          checkArgument(occurrences > 0);
220          return delegate.remove(element) ? 1 : 0;
221        }
222    
223        transient Set<E> elementSet;
224    
225        public Set<E> elementSet() {
226          Set<E> es = elementSet;
227          return (es == null) ? elementSet = new ElementSet() : es;
228        }
229    
230        transient Set<Entry<E>> entrySet;
231    
232        public Set<Entry<E>> entrySet() {
233          Set<Entry<E>> es = entrySet;
234          return (es == null) ? entrySet = new EntrySet() : es;
235        }
236    
237        @Override public boolean add(E o) {
238          throw new UnsupportedOperationException();
239        }
240    
241        @Override public boolean addAll(Collection<? extends E> c) {
242          throw new UnsupportedOperationException();
243        }
244    
245        public int setCount(E element, int count) {
246          checkNonnegative(count, "count");
247    
248          if (count == count(element)) {
249            return count;
250          } else if (count == 0) {
251            remove(element);
252            return 1;
253          } else {
254            throw new UnsupportedOperationException();
255          }
256        }
257    
258        public boolean setCount(E element, int oldCount, int newCount) {
259          return setCountImpl(this, element, oldCount, newCount);
260        }
261    
262        @Override public boolean equals(@Nullable Object object) {
263          if (object instanceof Multiset) {
264            Multiset<?> that = (Multiset<?>) object;
265            return this.size() == that.size() && delegate.equals(that.elementSet());
266          }
267          return false;
268        }
269    
270        @Override public int hashCode() {
271          int sum = 0;
272          for (E e : this) {
273            sum += ((e == null) ? 0 : e.hashCode()) ^ 1;
274          }
275          return sum;
276        }
277    
278        /** @see SetMultiset#elementSet */
279        class ElementSet extends ForwardingSet<E> {
280          @Override protected Set<E> delegate() {
281            return delegate;
282          }
283    
284          @Override public boolean add(E o) {
285            throw new UnsupportedOperationException();
286          }
287    
288          @Override public boolean addAll(Collection<? extends E> c) {
289            throw new UnsupportedOperationException();
290          }
291        }
292    
293        /** @see SetMultiset#entrySet */
294        class EntrySet extends AbstractSet<Entry<E>> {
295          @Override public int size() {
296            return delegate.size();
297          }
298          @Override public Iterator<Entry<E>> iterator() {
299            return new Iterator<Entry<E>>() {
300              final Iterator<E> elements = delegate.iterator();
301    
302              public boolean hasNext() {
303                return elements.hasNext();
304              }
305              public Entry<E> next() {
306                return immutableEntry(elements.next(), 1);
307              }
308              public void remove() {
309                elements.remove();
310              }
311            };
312          }
313          // TODO(kevinb): faster contains, remove
314        }
315    
316        private static final long serialVersionUID = 0;
317      }
318    
319      /**
320       * Returns the expected number of distinct elements given the specified
321       * elements. The number of distinct elements is only computed if {@code
322       * elements} is an instance of {@code Multiset}; otherwise the default value
323       * of 11 is returned.
324       */
325      static int inferDistinctElements(Iterable<?> elements) {
326        if (elements instanceof Multiset) {
327          return ((Multiset<?>) elements).elementSet().size();
328        }
329        return 11; // initial capacity will be rounded up to 16
330      }
331    
332      /**
333       * Returns an unmodifiable <b>view</b> of the intersection of two multisets.
334       * An element's count in the multiset is the smaller of its counts in the two
335       * backing multisets. The iteration order of the returned multiset matches the
336       * element set of {@code multiset1}, with repeated occurrences of the same
337       * element appearing consecutively.
338       *
339       * <p>Results are undefined if {@code multiset1} and {@code multiset2} are
340       * based on different equivalence relations (as {@code HashMultiset} and
341       * {@code TreeMultiset} are).
342       *
343       * @since 2
344       */
345      public static <E> Multiset<E> intersection(
346          final Multiset<E> multiset1, final Multiset<?> multiset2) {
347        checkNotNull(multiset1);
348        checkNotNull(multiset2);
349    
350        return new AbstractMultiset<E>() {
351          @Override public int count(Object element) {
352            int count1 = multiset1.count(element);
353            return (count1 == 0) ? 0 : Math.min(count1, multiset2.count(element));
354          }
355    
356          @Override Set<E> createElementSet() {
357            return Sets.intersection(
358                multiset1.elementSet(), multiset2.elementSet());
359          }
360    
361          @Override public Set<Entry<E>> entrySet() {
362            return entrySet;
363          }
364    
365          final Set<Entry<E>> entrySet = new AbstractSet<Entry<E>>() {
366            @Override public Iterator<Entry<E>> iterator() {
367              final Iterator<Entry<E>> iterator1 = multiset1.entrySet().iterator();
368              return new AbstractIterator<Entry<E>>() {
369                @Override protected Entry<E> computeNext() {
370                  while (iterator1.hasNext()) {
371                    Entry<E> entry1 = iterator1.next();
372                    E element = entry1.getElement();
373                    int count
374                        = Math.min(entry1.getCount(), multiset2.count(element));
375                    if (count > 0) {
376                      return Multisets.immutableEntry(element, count);
377                    }
378                  }
379                  return endOfData();
380                }
381              };
382            }
383    
384            @Override public int size() {
385              return elementSet().size();
386            }
387    
388            @Override public boolean contains(Object o) {
389              if (o instanceof Entry) {
390                Entry<?> entry = (Entry<?>) o;
391                int entryCount = entry.getCount();
392                return (entryCount > 0)
393                    && (count(entry.getElement()) == entryCount);
394              }
395              return false;
396            }
397    
398            @Override public boolean isEmpty() {
399              return elementSet().isEmpty();
400            }
401          };
402        };
403      }
404    
405      /**
406       * Implementation of the {@code equals}, {@code hashCode}, and
407       * {@code toString} methods of {@link Multiset.Entry}.
408       */
409      abstract static class AbstractEntry<E> implements Multiset.Entry<E> {
410        /**
411         * Indicates whether an object equals this entry, following the behavior
412         * specified in {@link Multiset.Entry#equals}.
413         */
414        @Override public boolean equals(@Nullable Object object) {
415          if (object instanceof Multiset.Entry) {
416            Multiset.Entry<?> that = (Multiset.Entry<?>) object;
417            return this.getCount() == that.getCount()
418                && Objects.equal(this.getElement(), that.getElement());
419          }
420          return false;
421        }
422    
423        /**
424         * Return this entry's hash code, following the behavior specified in
425         * {@link Multiset.Entry#hashCode}.
426         */
427        @Override public int hashCode() {
428          E e = getElement();
429          return ((e == null) ? 0 : e.hashCode()) ^ getCount();
430        }
431    
432        /**
433         * Returns a string representation of this multiset entry. The string
434         * representation consists of the associated element if the associated count
435         * is one, and otherwise the associated element followed by the characters
436         * " x " (space, x and space) followed by the count. Elements and counts are
437         * converted to strings as by {@code String.valueOf}.
438         */
439        @Override public String toString() {
440          String text = String.valueOf(getElement());
441          int n = getCount();
442          return (n == 1) ? text : (text + " x " + n);
443        }
444      } 
445    
446      /**
447       * An implementation of {@link Multiset#equals}.
448       */
449      static boolean equalsImpl(Multiset<?> multiset, @Nullable Object object) {
450        if (object == multiset) {
451          return true;
452        }
453        if (object instanceof Multiset) {
454          Multiset<?> that = (Multiset<?>) object;
455          /*
456           * We can't simply check whether the entry sets are equal, since that
457           * approach fails when a TreeMultiset has a comparator that returns 0
458           * when passed unequal elements.
459           */
460    
461          if (multiset.size() != that.size()
462              || multiset.entrySet().size() != that.entrySet().size()) {
463            return false;
464          }
465          for (Entry<?> entry : that.entrySet()) {
466            if (multiset.count(entry.getElement()) != entry.getCount()) {
467              return false;
468            }
469          }
470          return true;
471        }
472        return false;
473      }
474    
475      /**
476       * An implementation of {@link Multiset#addAll}.
477       */
478      static <E> boolean addAllImpl(
479          Multiset<E> self, Collection<? extends E> elements) {
480        if (elements.isEmpty()) {
481          return false;
482        }
483        if (elements instanceof Multiset) {
484          Multiset<? extends E> that = cast(elements);
485          for (Entry<? extends E> entry : that.entrySet()) {
486            self.add(entry.getElement(), entry.getCount());
487          }
488        } else {
489          Iterators.addAll(self, elements.iterator());
490        }
491        return true;
492      }
493    
494      /**
495       * An implementation of {@link Multiset#removeAll}.
496       */
497      static boolean removeAllImpl(
498          Multiset<?> self, Collection<?> elementsToRemove) {
499        Collection<?> collection = (elementsToRemove instanceof Multiset)
500            ? ((Multiset<?>) elementsToRemove).elementSet() : elementsToRemove;
501    
502        return self.elementSet().removeAll(collection);
503      }
504    
505      /**
506       * An implementation of {@link Multiset#retainAll}.
507       */
508      static boolean retainAllImpl(
509          Multiset<?> self, Collection<?> elementsToRetain) {
510        Collection<?> collection = (elementsToRetain instanceof Multiset)
511            ? ((Multiset<?>) elementsToRetain).elementSet() : elementsToRetain;
512    
513        return self.elementSet().retainAll(collection);
514      }
515    
516      /**
517       * An implementation of {@link Multiset#setCount(Object, int)}.
518       */
519      static <E> int setCountImpl(Multiset<E> self, E element, int count) {
520        checkNonnegative(count, "count");
521    
522        int oldCount = self.count(element);
523    
524        int delta = count - oldCount;
525        if (delta > 0) {
526          self.add(element, delta);
527        } else if (delta < 0) {
528          self.remove(element, -delta);
529        }
530    
531        return oldCount;
532      }
533    
534      /**
535       * An implementation of {@link Multiset#setCount(Object, int, int)}.
536       */
537      static <E> boolean setCountImpl(
538          Multiset<E> self, E element, int oldCount, int newCount) {
539        checkNonnegative(oldCount, "oldCount");
540        checkNonnegative(newCount, "newCount");
541    
542        if (self.count(element) == oldCount) {
543          self.setCount(element, newCount);
544          return true;
545        } else {
546          return false;
547        }
548      }
549      
550      /**
551       * An implementation of {@link Multiset#elementSet}.
552       */
553      static <E> Set<E> elementSetImpl(Multiset<E> self){
554        return new ElementSetImpl<E>(self);
555      }
556      
557      private static final class ElementSetImpl<E> extends AbstractSet<E>
558          implements Serializable {
559        private final Multiset<E> multiset;
560        
561        ElementSetImpl(Multiset<E> multiset) {
562          this.multiset = multiset;
563        }
564    
565        @Override public boolean add(E e) {
566          throw new UnsupportedOperationException();
567        }
568    
569        @Override public boolean addAll(Collection<? extends E> c) {
570          throw new UnsupportedOperationException();
571        }
572    
573        @Override public void clear() {
574          multiset.clear();
575        }
576    
577        @Override public boolean contains(Object o) {
578          return multiset.contains(o);
579        }
580    
581        @Override public boolean containsAll(Collection<?> c) {
582          return multiset.containsAll(c);
583        }
584    
585        @Override public boolean isEmpty() {
586          return multiset.isEmpty();
587        }
588    
589        @Override public Iterator<E> iterator() {
590          final Iterator<Entry<E>> entryIterator = multiset.entrySet().iterator();
591          return new Iterator<E>() {
592    
593            @Override public boolean hasNext() {
594              return entryIterator.hasNext();
595            }
596    
597            @Override public E next() {
598              return entryIterator.next().getElement();
599            }
600    
601            @Override public void remove() {
602              entryIterator.remove();
603            }
604          };
605        }
606    
607        @Override public boolean remove(Object o) {
608          int count = multiset.count(o);
609          if (count > 0) {
610            multiset.remove(o, count);
611            return true;
612          }
613          return false;
614        }
615    
616        @Override public int size() {
617          return multiset.entrySet().size();
618        }
619    
620        private static final long serialVersionUID = 0;
621      }
622      
623      /**
624       * An implementation of {@link Multiset#iterator}.
625       */
626      static <E> Iterator<E> iteratorImpl(Multiset<E> multiset) {
627        return new MultisetIteratorImpl<E>(
628            multiset, multiset.entrySet().iterator());
629      }
630    
631      static final class MultisetIteratorImpl<E> implements Iterator<E> {
632        private final Multiset<E> multiset;
633        private final Iterator<Entry<E>> entryIterator;
634        private Entry<E> currentEntry;
635        /** Count of subsequent elements equal to current element */
636        private int laterCount;
637        /** Count of all elements equal to current element */
638        private int totalCount;
639        private boolean canRemove;
640    
641        MultisetIteratorImpl(
642            Multiset<E> multiset, Iterator<Entry<E>> entryIterator) {
643          this.multiset = multiset;
644          this.entryIterator = entryIterator;
645        }
646    
647        public boolean hasNext() {
648          return laterCount > 0 || entryIterator.hasNext();
649        }
650    
651        public E next() {
652          if (!hasNext()) {
653            throw new NoSuchElementException();
654          }
655          if (laterCount == 0) {
656            currentEntry = entryIterator.next();
657            totalCount = laterCount = currentEntry.getCount();
658          }
659          laterCount--;
660          canRemove = true;
661          return currentEntry.getElement();
662        }
663    
664        public void remove() {
665          checkState(
666              canRemove, "no calls to next() since the last call to remove()");
667          if (totalCount == 1) {
668            entryIterator.remove();
669          } else {
670            multiset.remove(currentEntry.getElement());
671          }
672          totalCount--;
673          canRemove = false;
674        }
675      }
676      
677      /**
678       * An implementation of {@link Multiset#size}.
679       */
680      static int sizeImpl(Multiset<?> multiset) {
681        long size = 0;
682        for (Entry<?> entry : multiset.entrySet()) {
683          size += entry.getCount();
684        }
685        return Ints.saturatedCast(size);
686      }
687    
688      static void checkNonnegative(int count, String name) {
689        checkArgument(count >= 0, "%s cannot be negative: %s", name, count);
690      }
691    
692      /**
693       * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
694       */
695      static <T> Multiset<T> cast(Iterable<T> iterable) {
696        return (Multiset<T>) iterable;
697      }
698    }