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