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.LinkedHashMap;
026    import java.util.concurrent.atomic.AtomicInteger;
027    
028    /**
029     * A {@code Multiset} implementation with predictable iteration order. Its
030     * iterator orders elements according to when the first occurrence of the
031     * element was added. When the multiset contains multiple instances of an
032     * element, those instances are consecutive in the iteration order. If all
033     * occurrences of an element are removed, after which that element is added to
034     * the multiset, the element will appear at the end of the iteration.
035     *
036     * @author Kevin Bourrillion
037     * @author Jared Levy
038     * @since 2 (imported from Google Collections Library)
039     */
040    @GwtCompatible(serializable = true, emulated = true)
041    @SuppressWarnings("serial") // we're overriding default serialization
042    public final class LinkedHashMultiset<E> extends AbstractMapBasedMultiset<E> {
043    
044      /**
045       * Creates a new, empty {@code LinkedHashMultiset} using the default initial
046       * capacity.
047       */
048      public static <E> LinkedHashMultiset<E> create() {
049        return new LinkedHashMultiset<E>();
050      }
051    
052      /**
053       * Creates a new, empty {@code LinkedHashMultiset} with the specified expected
054       * number of distinct elements.
055       *
056       * @param distinctElements the expected number of distinct elements
057       * @throws IllegalArgumentException if {@code distinctElements} is negative
058       */
059      public static <E> LinkedHashMultiset<E> create(int distinctElements) {
060        return new LinkedHashMultiset<E>(distinctElements);
061      }
062    
063      /**
064       * Creates a new {@code LinkedHashMultiset} containing the specified elements.
065       *
066       * @param elements the elements that the multiset should contain
067       */
068      public static <E> LinkedHashMultiset<E> create(
069          Iterable<? extends E> elements) {
070        LinkedHashMultiset<E> multiset =
071            create(Multisets.inferDistinctElements(elements));
072        Iterables.addAll(multiset, elements);
073        return multiset;
074      }
075    
076      private LinkedHashMultiset() {
077        super(new LinkedHashMap<E, AtomicInteger>());
078      }
079    
080      private LinkedHashMultiset(int distinctElements) {
081        // Could use newLinkedHashMapWithExpectedSize() if it existed
082        super(new LinkedHashMap<E, AtomicInteger>(Maps.capacity(distinctElements)));
083      }
084    
085      /**
086       * @serialData the number of distinct elements, the first element, its count,
087       *     the second element, its count, and so on
088       */
089      @GwtIncompatible("java.io.ObjectOutputStream")
090      private void writeObject(ObjectOutputStream stream) throws IOException {
091        stream.defaultWriteObject();
092        Serialization.writeMultiset(this, stream);
093      }
094    
095      @GwtIncompatible("java.io.ObjectInputStream")
096      private void readObject(ObjectInputStream stream)
097          throws IOException, ClassNotFoundException {
098        stream.defaultReadObject();
099        int distinctElements = Serialization.readCount(stream);
100        setBackingMap(new LinkedHashMap<E, AtomicInteger>(
101            Maps.capacity(distinctElements)));
102        Serialization.populateMultiset(this, stream, distinctElements);
103      }
104    
105      @GwtIncompatible("not needed in emulated source")
106      private static final long serialVersionUID = 0;
107    }