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