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 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>> extends AbstractMapBasedMultiset<E> {
039      /** Creates an empty {@code EnumMultiset}. */
040      public static <E extends Enum<E>> EnumMultiset<E> create(Class<E> type) {
041        return new EnumMultiset<E>(type);
042      }
043    
044      /**
045       * Creates a new {@code EnumMultiset} containing the specified elements.
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, AtomicInteger>(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, AtomicInteger>(type)));
085        Serialization.populateMultiset(this, stream);
086      }
087    
088      @GwtIncompatible("Not needed in emulated source")
089      private static final long serialVersionUID = 0;
090    }