    001    /*
    002     * Copyright (C) 2007 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 License
    010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
    011     * or implied. See the License for the specific language governing permissions and limitations under
    012     * the License.
    013     */
    014
    015    package com.google.common.collect;
    016
    017    import static com.google.common.base.Preconditions.checkArgument;
    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.EnumMap;
    026    import java.util.Iterator;
    027
    028    /**
    029     * Multiset implementation backed by an {@link EnumMap}.
    030     *
    031     * <p>See the Guava User Guide article on <a href=
    032     * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
    033     * {@code Multiset}</a>.
    034     *
    035     * @author Jared Levy
    036     * @since 2.0 (imported from Google Collections Library)
    037     */
    038    @GwtCompatible(emulated = true)
    039    public final class EnumMultiset<E extends Enum<E>> 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       * <p>This implementation is highly efficient when {@code elements} is itself a {@link
    049       * Multiset}.
    050       *
    051       * @param elements the elements that the multiset should contain
    052       * @throws IllegalArgumentException if {@code elements} is empty
    053       */
    054      public static <E extends Enum<E>> EnumMultiset<E> create(Iterable<E> elements) {
    055        Iterator<E> iterator = elements.iterator();
    056        checkArgument(iterator.hasNext(), "EnumMultiset constructor passed empty Iterable");
    057        EnumMultiset<E> multiset = 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(WellBehavedMap.wrap(new EnumMap<E, Count>(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
    080       *             count, and so on
    081       */
    082      @GwtIncompatible("java.io.ObjectInputStream")
    083      private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
    084        stream.defaultReadObject();
    085        @SuppressWarnings("unchecked") // reading data stored by writeObject
    086        Class<E> localType = (Class<E>) stream.readObject();
    087        type = localType;
    088        setBackingMap(WellBehavedMap.wrap(new EnumMap<E, Count>(type)));
    089        Serialization.populateMultiset(this, stream);
    090      }
    091
    092      @GwtIncompatible("Not needed in emulated source")
    093      private static final long serialVersionUID = 0;
    094    }