aboutsummaryrefslogtreecommitdiff
path: root/android/guava/src/com/google/common/collect/LinkedHashMultimap.java
diff options
context:
space:
mode:
Diffstat (limited to 'android/guava/src/com/google/common/collect/LinkedHashMultimap.java')
-rw-r--r--android/guava/src/com/google/common/collect/LinkedHashMultimap.java590
1 files changed, 0 insertions, 590 deletions
diff --git a/android/guava/src/com/google/common/collect/LinkedHashMultimap.java b/android/guava/src/com/google/common/collect/LinkedHashMultimap.java
deleted file mode 100644
index 361661705..000000000
--- a/android/guava/src/com/google/common/collect/LinkedHashMultimap.java
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.collect.CollectPreconditions.checkNonnegative;
-import static com.google.common.collect.CollectPreconditions.checkRemove;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.j2objc.annotations.WeakOuter;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import org.checkerframework.checker.nullness.compatqual.NullableDecl;
-
-/**
- * Implementation of {@code Multimap} that does not allow duplicate key-value entries and that
- * returns collections whose iterators follow the ordering in which the data was added to the
- * multimap.
- *
- * <p>The collections returned by {@code keySet}, {@code keys}, and {@code asMap} iterate through
- * the keys in the order they were first added to the multimap. Similarly, {@code get}, {@code
- * removeAll}, and {@code replaceValues} return collections that iterate through the values in the
- * order they were added. The collections generated by {@code entries} and {@code values} iterate
- * across the key-value mappings in the order they were added to the multimap.
- *
- * <p>The iteration ordering of the collections generated by {@code keySet}, {@code keys}, and
- * {@code asMap} has a few subtleties. As long as the set of keys remains unchanged, adding or
- * removing mappings does not affect the key iteration order. However, if you remove all values
- * associated with a key and then add the key back to the multimap, that key will come last in the
- * key iteration order.
- *
- * <p>The multimap does not store duplicate key-value pairs. Adding a new key-value pair equal to an
- * existing key-value pair has no effect.
- *
- * <p>Keys and values may be null. All optional multimap methods are supported, and all returned
- * views are modifiable.
- *
- * <p>This class is not threadsafe when any concurrent operations update the multimap. Concurrent
- * read operations will work correctly. To allow concurrent update operations, wrap your multimap
- * with a call to {@link Multimaps#synchronizedSetMultimap}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "https://github.com/google/guava/wiki/NewCollectionTypesExplained#multimap"> {@code
- * Multimap}</a>.
- *
- * @author Jared Levy
- * @author Louis Wasserman
- * @since 2.0
- */
-@GwtCompatible(serializable = true, emulated = true)
-public final class LinkedHashMultimap<K, V>
- extends LinkedHashMultimapGwtSerializationDependencies<K, V> {
-
- /** Creates a new, empty {@code LinkedHashMultimap} with the default initial capacities. */
- public static <K, V> LinkedHashMultimap<K, V> create() {
- return new LinkedHashMultimap<>(DEFAULT_KEY_CAPACITY, DEFAULT_VALUE_SET_CAPACITY);
- }
-
- /**
- * Constructs an empty {@code LinkedHashMultimap} with enough capacity to hold the specified
- * numbers of keys and values without rehashing.
- *
- * @param expectedKeys the expected number of distinct keys
- * @param expectedValuesPerKey the expected average number of values per key
- * @throws IllegalArgumentException if {@code expectedKeys} or {@code expectedValuesPerKey} is
- * negative
- */
- public static <K, V> LinkedHashMultimap<K, V> create(int expectedKeys, int expectedValuesPerKey) {
- return new LinkedHashMultimap<>(
- Maps.capacity(expectedKeys), Maps.capacity(expectedValuesPerKey));
- }
-
- /**
- * Constructs a {@code LinkedHashMultimap} with the same mappings as the specified multimap. If a
- * key-value mapping appears multiple times in the input multimap, it only appears once in the
- * constructed multimap. The new multimap has the same {@link Multimap#entries()} iteration order
- * as the input multimap, except for excluding duplicate mappings.
- *
- * @param multimap the multimap whose contents are copied to this multimap
- */
- public static <K, V> LinkedHashMultimap<K, V> create(
- Multimap<? extends K, ? extends V> multimap) {
- LinkedHashMultimap<K, V> result = create(multimap.keySet().size(), DEFAULT_VALUE_SET_CAPACITY);
- result.putAll(multimap);
- return result;
- }
-
- private interface ValueSetLink<K, V> {
- ValueSetLink<K, V> getPredecessorInValueSet();
-
- ValueSetLink<K, V> getSuccessorInValueSet();
-
- void setPredecessorInValueSet(ValueSetLink<K, V> entry);
-
- void setSuccessorInValueSet(ValueSetLink<K, V> entry);
- }
-
- private static <K, V> void succeedsInValueSet(ValueSetLink<K, V> pred, ValueSetLink<K, V> succ) {
- pred.setSuccessorInValueSet(succ);
- succ.setPredecessorInValueSet(pred);
- }
-
- private static <K, V> void succeedsInMultimap(ValueEntry<K, V> pred, ValueEntry<K, V> succ) {
- pred.setSuccessorInMultimap(succ);
- succ.setPredecessorInMultimap(pred);
- }
-
- private static <K, V> void deleteFromValueSet(ValueSetLink<K, V> entry) {
- succeedsInValueSet(entry.getPredecessorInValueSet(), entry.getSuccessorInValueSet());
- }
-
- private static <K, V> void deleteFromMultimap(ValueEntry<K, V> entry) {
- succeedsInMultimap(entry.getPredecessorInMultimap(), entry.getSuccessorInMultimap());
- }
-
- /**
- * LinkedHashMultimap entries are in no less than three coexisting linked lists: a bucket in the
- * hash table for a {@code Set<V>} associated with a key, the linked list of insertion-ordered
- * entries in that {@code Set<V>}, and the linked list of entries in the LinkedHashMultimap as a
- * whole.
- */
- @VisibleForTesting
- static final class ValueEntry<K, V> extends ImmutableEntry<K, V> implements ValueSetLink<K, V> {
- final int smearedValueHash;
-
- @NullableDecl ValueEntry<K, V> nextInValueBucket;
-
- @NullableDecl ValueSetLink<K, V> predecessorInValueSet;
- @NullableDecl ValueSetLink<K, V> successorInValueSet;
-
- @NullableDecl ValueEntry<K, V> predecessorInMultimap;
- @NullableDecl ValueEntry<K, V> successorInMultimap;
-
- ValueEntry(
- @NullableDecl K key,
- @NullableDecl V value,
- int smearedValueHash,
- @NullableDecl ValueEntry<K, V> nextInValueBucket) {
- super(key, value);
- this.smearedValueHash = smearedValueHash;
- this.nextInValueBucket = nextInValueBucket;
- }
-
- boolean matchesValue(@NullableDecl Object v, int smearedVHash) {
- return smearedValueHash == smearedVHash && Objects.equal(getValue(), v);
- }
-
- @Override
- public ValueSetLink<K, V> getPredecessorInValueSet() {
- return predecessorInValueSet;
- }
-
- @Override
- public ValueSetLink<K, V> getSuccessorInValueSet() {
- return successorInValueSet;
- }
-
- @Override
- public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
- predecessorInValueSet = entry;
- }
-
- @Override
- public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
- successorInValueSet = entry;
- }
-
- public ValueEntry<K, V> getPredecessorInMultimap() {
- return predecessorInMultimap;
- }
-
- public ValueEntry<K, V> getSuccessorInMultimap() {
- return successorInMultimap;
- }
-
- public void setSuccessorInMultimap(ValueEntry<K, V> multimapSuccessor) {
- this.successorInMultimap = multimapSuccessor;
- }
-
- public void setPredecessorInMultimap(ValueEntry<K, V> multimapPredecessor) {
- this.predecessorInMultimap = multimapPredecessor;
- }
- }
-
- private static final int DEFAULT_KEY_CAPACITY = 16;
- private static final int DEFAULT_VALUE_SET_CAPACITY = 2;
- @VisibleForTesting static final double VALUE_SET_LOAD_FACTOR = 1.0;
-
- @VisibleForTesting transient int valueSetCapacity = DEFAULT_VALUE_SET_CAPACITY;
- private transient ValueEntry<K, V> multimapHeaderEntry;
-
- private LinkedHashMultimap(int keyCapacity, int valueSetCapacity) {
- super(Platform.<K, Collection<V>>newLinkedHashMapWithExpectedSize(keyCapacity));
- checkNonnegative(valueSetCapacity, "expectedValuesPerKey");
-
- this.valueSetCapacity = valueSetCapacity;
- this.multimapHeaderEntry = new ValueEntry<>(null, null, 0, null);
- succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>Creates an empty {@code LinkedHashSet} for a collection of values for one key.
- *
- * @return a new {@code LinkedHashSet} containing a collection of values for one key
- */
- @Override
- Set<V> createCollection() {
- return Platform.newLinkedHashSetWithExpectedSize(valueSetCapacity);
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>Creates a decorated insertion-ordered set that also keeps track of the order in which
- * key-value pairs are added to the multimap.
- *
- * @param key key to associate with values in the collection
- * @return a new decorated set containing a collection of values for one key
- */
- @Override
- Collection<V> createCollection(K key) {
- return new ValueSet(key, valueSetCapacity);
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>If {@code values} is not empty and the multimap already contains a mapping for {@code key},
- * the {@code keySet()} ordering is unchanged. However, the provided values always come last in
- * the {@link #entries()} and {@link #values()} iteration orderings.
- */
- @CanIgnoreReturnValue
- @Override
- public Set<V> replaceValues(@NullableDecl K key, Iterable<? extends V> values) {
- return super.replaceValues(key, values);
- }
-
- /**
- * Returns a set of all key-value pairs. Changes to the returned set will update the underlying
- * multimap, and vice versa. The entries set does not support the {@code add} or {@code addAll}
- * operations.
- *
- * <p>The iterator generated by the returned set traverses the entries in the order they were
- * added to the multimap.
- *
- * <p>Each entry is an immutable snapshot of a key-value mapping in the multimap, taken at the
- * time the entry is returned by a method call to the collection or its iterator.
- */
- @Override
- public Set<Entry<K, V>> entries() {
- return super.entries();
- }
-
- /**
- * Returns a view collection of all <i>distinct</i> keys contained in this multimap. Note that the
- * key set contains a key if and only if this multimap maps that key to at least one value.
- *
- * <p>The iterator generated by the returned set traverses the keys in the order they were first
- * added to the multimap.
- *
- * <p>Changes to the returned set will update the underlying multimap, and vice versa. However,
- * <i>adding</i> to the returned set is not possible.
- */
- @Override
- public Set<K> keySet() {
- return super.keySet();
- }
-
- /**
- * Returns a collection of all values in the multimap. Changes to the returned collection will
- * update the underlying multimap, and vice versa.
- *
- * <p>The iterator generated by the returned collection traverses the values in the order they
- * were added to the multimap.
- */
- @Override
- public Collection<V> values() {
- return super.values();
- }
-
- @VisibleForTesting
- @WeakOuter
- final class ValueSet extends Sets.ImprovedAbstractSet<V> implements ValueSetLink<K, V> {
- /*
- * We currently use a fixed load factor of 1.0, a bit higher than normal to reduce memory
- * consumption.
- */
-
- private final K key;
- @VisibleForTesting ValueEntry<K, V>[] hashTable;
- private int size = 0;
- private int modCount = 0;
-
- // We use the set object itself as the end of the linked list, avoiding an unnecessary
- // entry object per key.
- private ValueSetLink<K, V> firstEntry;
- private ValueSetLink<K, V> lastEntry;
-
- ValueSet(K key, int expectedValues) {
- this.key = key;
- this.firstEntry = this;
- this.lastEntry = this;
- // Round expected values up to a power of 2 to get the table size.
- int tableSize = Hashing.closedTableSize(expectedValues, VALUE_SET_LOAD_FACTOR);
-
- @SuppressWarnings("unchecked")
- ValueEntry<K, V>[] hashTable = new ValueEntry[tableSize];
- this.hashTable = hashTable;
- }
-
- private int mask() {
- return hashTable.length - 1;
- }
-
- @Override
- public ValueSetLink<K, V> getPredecessorInValueSet() {
- return lastEntry;
- }
-
- @Override
- public ValueSetLink<K, V> getSuccessorInValueSet() {
- return firstEntry;
- }
-
- @Override
- public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
- lastEntry = entry;
- }
-
- @Override
- public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
- firstEntry = entry;
- }
-
- @Override
- public Iterator<V> iterator() {
- return new Iterator<V>() {
- ValueSetLink<K, V> nextEntry = firstEntry;
- @NullableDecl ValueEntry<K, V> toRemove;
- int expectedModCount = modCount;
-
- private void checkForComodification() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
-
- @Override
- public boolean hasNext() {
- checkForComodification();
- return nextEntry != ValueSet.this;
- }
-
- @Override
- public V next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- ValueEntry<K, V> entry = (ValueEntry<K, V>) nextEntry;
- V result = entry.getValue();
- toRemove = entry;
- nextEntry = entry.getSuccessorInValueSet();
- return result;
- }
-
- @Override
- public void remove() {
- checkForComodification();
- checkRemove(toRemove != null);
- ValueSet.this.remove(toRemove.getValue());
- expectedModCount = modCount;
- toRemove = null;
- }
- };
- }
-
- @Override
- public int size() {
- return size;
- }
-
- @Override
- public boolean contains(@NullableDecl Object o) {
- int smearedHash = Hashing.smearedHash(o);
- for (ValueEntry<K, V> entry = hashTable[smearedHash & mask()];
- entry != null;
- entry = entry.nextInValueBucket) {
- if (entry.matchesValue(o, smearedHash)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean add(@NullableDecl V value) {
- int smearedHash = Hashing.smearedHash(value);
- int bucket = smearedHash & mask();
- ValueEntry<K, V> rowHead = hashTable[bucket];
- for (ValueEntry<K, V> entry = rowHead; entry != null; entry = entry.nextInValueBucket) {
- if (entry.matchesValue(value, smearedHash)) {
- return false;
- }
- }
-
- ValueEntry<K, V> newEntry = new ValueEntry<>(key, value, smearedHash, rowHead);
- succeedsInValueSet(lastEntry, newEntry);
- succeedsInValueSet(newEntry, this);
- succeedsInMultimap(multimapHeaderEntry.getPredecessorInMultimap(), newEntry);
- succeedsInMultimap(newEntry, multimapHeaderEntry);
- hashTable[bucket] = newEntry;
- size++;
- modCount++;
- rehashIfNecessary();
- return true;
- }
-
- private void rehashIfNecessary() {
- if (Hashing.needsResizing(size, hashTable.length, VALUE_SET_LOAD_FACTOR)) {
- @SuppressWarnings("unchecked")
- ValueEntry<K, V>[] hashTable = new ValueEntry[this.hashTable.length * 2];
- this.hashTable = hashTable;
- int mask = hashTable.length - 1;
- for (ValueSetLink<K, V> entry = firstEntry;
- entry != this;
- entry = entry.getSuccessorInValueSet()) {
- ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
- int bucket = valueEntry.smearedValueHash & mask;
- valueEntry.nextInValueBucket = hashTable[bucket];
- hashTable[bucket] = valueEntry;
- }
- }
- }
-
- @CanIgnoreReturnValue
- @Override
- public boolean remove(@NullableDecl Object o) {
- int smearedHash = Hashing.smearedHash(o);
- int bucket = smearedHash & mask();
- ValueEntry<K, V> prev = null;
- for (ValueEntry<K, V> entry = hashTable[bucket];
- entry != null;
- prev = entry, entry = entry.nextInValueBucket) {
- if (entry.matchesValue(o, smearedHash)) {
- if (prev == null) {
- // first entry in the bucket
- hashTable[bucket] = entry.nextInValueBucket;
- } else {
- prev.nextInValueBucket = entry.nextInValueBucket;
- }
- deleteFromValueSet(entry);
- deleteFromMultimap(entry);
- size--;
- modCount++;
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void clear() {
- Arrays.fill(hashTable, null);
- size = 0;
- for (ValueSetLink<K, V> entry = firstEntry;
- entry != this;
- entry = entry.getSuccessorInValueSet()) {
- ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
- deleteFromMultimap(valueEntry);
- }
- succeedsInValueSet(this, this);
- modCount++;
- }
- }
-
- @Override
- Iterator<Entry<K, V>> entryIterator() {
- return new Iterator<Entry<K, V>>() {
- ValueEntry<K, V> nextEntry = multimapHeaderEntry.successorInMultimap;
- @NullableDecl ValueEntry<K, V> toRemove;
-
- @Override
- public boolean hasNext() {
- return nextEntry != multimapHeaderEntry;
- }
-
- @Override
- public Entry<K, V> next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- ValueEntry<K, V> result = nextEntry;
- toRemove = result;
- nextEntry = nextEntry.successorInMultimap;
- return result;
- }
-
- @Override
- public void remove() {
- checkRemove(toRemove != null);
- LinkedHashMultimap.this.remove(toRemove.getKey(), toRemove.getValue());
- toRemove = null;
- }
- };
- }
-
- @Override
- Iterator<V> valueIterator() {
- return Maps.valueIterator(entryIterator());
- }
-
- @Override
- public void clear() {
- super.clear();
- succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
- }
-
- /**
- * @serialData the expected values per key, the number of distinct keys, the number of entries,
- * and the entries in order
- */
- @GwtIncompatible // java.io.ObjectOutputStream
- private void writeObject(ObjectOutputStream stream) throws IOException {
- stream.defaultWriteObject();
- stream.writeInt(keySet().size());
- for (K key : keySet()) {
- stream.writeObject(key);
- }
- stream.writeInt(size());
- for (Entry<K, V> entry : entries()) {
- stream.writeObject(entry.getKey());
- stream.writeObject(entry.getValue());
- }
- }
-
- @GwtIncompatible // java.io.ObjectInputStream
- private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
- stream.defaultReadObject();
- multimapHeaderEntry = new ValueEntry<>(null, null, 0, null);
- succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
- valueSetCapacity = DEFAULT_VALUE_SET_CAPACITY;
- int distinctKeys = stream.readInt();
- Map<K, Collection<V>> map = Platform.newLinkedHashMapWithExpectedSize(12);
- for (int i = 0; i < distinctKeys; i++) {
- @SuppressWarnings("unchecked")
- K key = (K) stream.readObject();
- map.put(key, createCollection(key));
- }
- int entries = stream.readInt();
- for (int i = 0; i < entries; i++) {
- @SuppressWarnings("unchecked")
- K key = (K) stream.readObject();
- @SuppressWarnings("unchecked")
- V value = (V) stream.readObject();
- map.get(key).add(value);
- }
- setMap(map);
- }
-
- @GwtIncompatible // java serialization not supported
- private static final long serialVersionUID = 1;
-}