001    /*
002     * Copyright (C) 2007 The Guava Authors
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 com.google.common.annotations.GwtCompatible;
020    import com.google.common.annotations.GwtIncompatible;
021    
022    import java.io.IOException;
023    import java.io.ObjectInputStream;
024    import java.io.ObjectOutputStream;
025    import java.util.HashMap;
026    
027    /**
028     * Multiset implementation backed by a {@link HashMap}.
029     *
030     * @author Kevin Bourrillion
031     * @author Jared Levy
032     * @since 2.0 (imported from Google Collections Library)
033     */
034    @GwtCompatible(serializable = true, emulated = true)
035    public final class HashMultiset<E> extends AbstractMapBasedMultiset<E> {
036    
037      /**
038       * Creates a new, empty {@code HashMultiset} using the default initial
039       * capacity.
040       */
041      public static <E> HashMultiset<E> create() {
042        return new HashMultiset<E>();
043      }
044    
045      /**
046       * Creates a new, empty {@code HashMultiset} with the specified expected
047       * number of distinct elements.
048       *
049       * @param distinctElements the expected number of distinct elements
050       * @throws IllegalArgumentException if {@code distinctElements} is negative
051       */
052      public static <E> HashMultiset<E> create(int distinctElements) {
053        return new HashMultiset<E>(distinctElements);
054      }
055    
056      /**
057       * Creates a new {@code HashMultiset} containing the specified elements.
058       * 
059       * <p>This implementation is highly efficient when {@code elements} is itself
060       * a {@link Multiset}.
061       * 
062       * @param elements the elements that the multiset should contain
063       */
064      public static <E> HashMultiset<E> create(Iterable<? extends E> elements) {
065        HashMultiset<E> multiset =
066            create(Multisets.inferDistinctElements(elements));
067        Iterables.addAll(multiset, elements);
068        return multiset;
069      }
070    
071      private HashMultiset() {
072        super(new HashMap<E, Count>());
073      }
074    
075      private HashMultiset(int distinctElements) {
076        super(Maps.<E, Count>newHashMapWithExpectedSize(distinctElements));
077      }
078    
079      /**
080       * @serialData the number of distinct elements, the first element, its count,
081       *     the second element, its count, and so on
082       */
083      @GwtIncompatible("java.io.ObjectOutputStream")
084      private void writeObject(ObjectOutputStream stream) throws IOException {
085        stream.defaultWriteObject();
086        Serialization.writeMultiset(this, stream);
087      }
088    
089      @GwtIncompatible("java.io.ObjectInputStream")
090      private void readObject(ObjectInputStream stream)
091          throws IOException, ClassNotFoundException {
092        stream.defaultReadObject();
093        int distinctElements = Serialization.readCount(stream);
094        setBackingMap(
095            Maps.<E, Count>newHashMapWithExpectedSize(distinctElements));
096        Serialization.populateMultiset(this, stream, distinctElements);
097      }
098    
099      @GwtIncompatible("Not needed in emulated source.")
100      private static final long serialVersionUID = 0;
101    }