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    
021    import com.google.common.annotations.GwtCompatible;
022    import com.google.common.annotations.GwtIncompatible;
023    
024    import java.io.IOException;
025    import java.io.ObjectInputStream;
026    import java.io.ObjectOutputStream;
027    import java.util.EnumMap;
028    import java.util.Iterator;
029    import java.util.concurrent.atomic.AtomicInteger;
030    
031    /**
032     * Multiset implementation backed by an {@link EnumMap}.
033     *
034     * @author Jared Levy
035     * @since 2 (imported from Google Collections Library)
036     */
037    @GwtCompatible(emulated = true)
038    public final class EnumMultiset<E extends Enum<E>>
039        extends AbstractMapBasedMultiset<E> {
040      /** Creates an empty {@code EnumMultiset}. */
041      public static <E extends Enum<E>> EnumMultiset<E> create(Class<E> type) {
042        return new EnumMultiset<E>(type);
043      }
044    
045      /**
046       * Creates a new {@code EnumMultiset} containing the specified elements.
047       *
048       * @param elements the elements that the multiset should contain
049       * @throws IllegalArgumentException if {@code elements} is empty
050       */
051      public static <E extends Enum<E>> EnumMultiset<E> create(
052          Iterable<E> elements) {
053        Iterator<E> iterator = elements.iterator();
054        checkArgument(iterator.hasNext(),
055            "EnumMultiset constructor passed empty Iterable");
056        EnumMultiset<E> multiset
057            = new EnumMultiset<E>(iterator.next().getDeclaringClass());
058        Iterables.addAll(multiset, elements);
059        return multiset;
060      }
061    
062      private transient Class<E> type;
063    
064      /** Creates an empty {@code EnumMultiset}. */
065      private EnumMultiset(Class<E> type) {
066        super(new EnumMap<E, AtomicInteger>(type));
067        this.type = type;
068      }
069    
070      @GwtIncompatible("java.io.ObjectOutputStream")
071      private void writeObject(ObjectOutputStream stream) throws IOException {
072        stream.defaultWriteObject();
073        stream.writeObject(type);
074        Serialization.writeMultiset(this, stream);
075      }
076    
077      /**
078       * @serialData the {@code Class<E>} for the enum type, the number of distinct
079       *     elements, the first element, its count, the second element, its count,
080       *     and so on
081       */
082      @GwtIncompatible("java.io.ObjectInputStream")
083      private void readObject(ObjectInputStream stream)
084          throws IOException, ClassNotFoundException {
085        stream.defaultReadObject();
086        @SuppressWarnings("unchecked") // reading data stored by writeObject
087        Class<E> localType = (Class<E>) stream.readObject();
088        type = localType;
089        setBackingMap(new EnumMap<E, AtomicInteger>(type));
090        Serialization.populateMultiset(this, stream);
091      }
092    
093      @GwtIncompatible("Not needed in emulated source")
094      private static final long serialVersionUID = 0;
095    }