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 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 }