diff options
Diffstat (limited to 'android/guava/src/com/google/common/collect/Multimaps.java')
-rw-r--r-- | android/guava/src/com/google/common/collect/Multimaps.java | 2079 |
1 files changed, 0 insertions, 2079 deletions
diff --git a/android/guava/src/com/google/common/collect/Multimaps.java b/android/guava/src/com/google/common/collect/Multimaps.java deleted file mode 100644 index c0d921e4f..000000000 --- a/android/guava/src/com/google/common/collect/Multimaps.java +++ /dev/null @@ -1,2079 +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.base.Preconditions.checkNotNull; -import static com.google.common.collect.CollectPreconditions.checkNonnegative; -import static com.google.common.collect.CollectPreconditions.checkRemove; - -import com.google.common.annotations.Beta; -import com.google.common.annotations.GwtCompatible; -import com.google.common.annotations.GwtIncompatible; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.base.Supplier; -import com.google.common.collect.Maps.EntryTransformer; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.j2objc.annotations.Weak; -import com.google.j2objc.annotations.WeakOuter; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.AbstractCollection; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.NavigableSet; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.SortedSet; -import org.checkerframework.checker.nullness.compatqual.MonotonicNonNullDecl; -import org.checkerframework.checker.nullness.compatqual.NullableDecl; - -/** - * Provides static methods acting on or generating a {@code Multimap}. - * - * <p>See the Guava User Guide article on <a href= - * "https://github.com/google/guava/wiki/CollectionUtilitiesExplained#multimaps"> {@code - * Multimaps}</a>. - * - * @author Jared Levy - * @author Robert Konigsberg - * @author Mike Bostock - * @author Louis Wasserman - * @since 2.0 - */ -@GwtCompatible(emulated = true) -public final class Multimaps { - private Multimaps() {} - - /** - * Creates a new {@code Multimap} backed by {@code map}, whose internal value collections are - * generated by {@code factory}. - * - * <p><b>Warning: do not use</b> this method when the collections returned by {@code factory} - * implement either {@link List} or {@code Set}! Use the more specific method {@link - * #newListMultimap}, {@link #newSetMultimap} or {@link #newSortedSetMultimap} instead, to avoid - * very surprising behavior from {@link Multimap#equals}. - * - * <p>The {@code factory}-generated and {@code map} classes determine the multimap iteration - * order. They also specify the behavior of the {@code equals}, {@code hashCode}, and {@code - * toString} methods for the multimap and its returned views. However, the multimap's {@code get} - * method returns instances of a different class than {@code factory.get()} does. - * - * <p>The multimap is serializable if {@code map}, {@code factory}, the collections generated by - * {@code factory}, and the multimap contents are all serializable. - * - * <p>The multimap is not threadsafe when any concurrent operations update the multimap, even if - * {@code map} and the instances generated by {@code factory} are. Concurrent read operations will - * work correctly. To allow concurrent update operations, wrap the multimap with a call to {@link - * #synchronizedMultimap}. - * - * <p>Call this method only when the simpler methods {@link ArrayListMultimap#create()}, {@link - * HashMultimap#create()}, {@link LinkedHashMultimap#create()}, {@link - * LinkedListMultimap#create()}, {@link TreeMultimap#create()}, and {@link - * TreeMultimap#create(Comparator, Comparator)} won't suffice. - * - * <p>Note: the multimap assumes complete ownership over of {@code map} and the collections - * returned by {@code factory}. Those objects should not be manually updated and they should not - * use soft, weak, or phantom references. - * - * @param map place to store the mapping from each key to its corresponding values - * @param factory supplier of new, empty collections that will each hold all values for a given - * key - * @throws IllegalArgumentException if {@code map} is not empty - */ - public static <K, V> Multimap<K, V> newMultimap( - Map<K, Collection<V>> map, final Supplier<? extends Collection<V>> factory) { - return new CustomMultimap<>(map, factory); - } - - private static class CustomMultimap<K, V> extends AbstractMapBasedMultimap<K, V> { - transient Supplier<? extends Collection<V>> factory; - - CustomMultimap(Map<K, Collection<V>> map, Supplier<? extends Collection<V>> factory) { - super(map); - this.factory = checkNotNull(factory); - } - - @Override - Set<K> createKeySet() { - return createMaybeNavigableKeySet(); - } - - @Override - Map<K, Collection<V>> createAsMap() { - return createMaybeNavigableAsMap(); - } - - @Override - protected Collection<V> createCollection() { - return factory.get(); - } - - @Override - <E> Collection<E> unmodifiableCollectionSubclass(Collection<E> collection) { - if (collection instanceof NavigableSet) { - return Sets.unmodifiableNavigableSet((NavigableSet<E>) collection); - } else if (collection instanceof SortedSet) { - return Collections.unmodifiableSortedSet((SortedSet<E>) collection); - } else if (collection instanceof Set) { - return Collections.unmodifiableSet((Set<E>) collection); - } else if (collection instanceof List) { - return Collections.unmodifiableList((List<E>) collection); - } else { - return Collections.unmodifiableCollection(collection); - } - } - - @Override - Collection<V> wrapCollection(K key, Collection<V> collection) { - if (collection instanceof List) { - return wrapList(key, (List<V>) collection, null); - } else if (collection instanceof NavigableSet) { - return new WrappedNavigableSet(key, (NavigableSet<V>) collection, null); - } else if (collection instanceof SortedSet) { - return new WrappedSortedSet(key, (SortedSet<V>) collection, null); - } else if (collection instanceof Set) { - return new WrappedSet(key, (Set<V>) collection); - } else { - return new WrappedCollection(key, collection, null); - } - } - - // can't use Serialization writeMultimap and populateMultimap methods since - // there's no way to generate the empty backing map. - - /** @serialData the factory and the backing map */ - @GwtIncompatible // java.io.ObjectOutputStream - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.defaultWriteObject(); - stream.writeObject(factory); - stream.writeObject(backingMap()); - } - - @GwtIncompatible // java.io.ObjectInputStream - @SuppressWarnings("unchecked") // reading data stored by writeObject - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - factory = (Supplier<? extends Collection<V>>) stream.readObject(); - Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject(); - setMap(map); - } - - @GwtIncompatible // java serialization not supported - private static final long serialVersionUID = 0; - } - - /** - * Creates a new {@code ListMultimap} that uses the provided map and factory. It can generate a - * multimap based on arbitrary {@link Map} and {@link List} classes. - * - * <p>The {@code factory}-generated and {@code map} classes determine the multimap iteration - * order. They also specify the behavior of the {@code equals}, {@code hashCode}, and {@code - * toString} methods for the multimap and its returned views. The multimap's {@code get}, {@code - * removeAll}, and {@code replaceValues} methods return {@code RandomAccess} lists if the factory - * does. However, the multimap's {@code get} method returns instances of a different class than - * does {@code factory.get()}. - * - * <p>The multimap is serializable if {@code map}, {@code factory}, the lists generated by {@code - * factory}, and the multimap contents are all serializable. - * - * <p>The multimap is not threadsafe when any concurrent operations update the multimap, even if - * {@code map} and the instances generated by {@code factory} are. Concurrent read operations will - * work correctly. To allow concurrent update operations, wrap the multimap with a call to {@link - * #synchronizedListMultimap}. - * - * <p>Call this method only when the simpler methods {@link ArrayListMultimap#create()} and {@link - * LinkedListMultimap#create()} won't suffice. - * - * <p>Note: the multimap assumes complete ownership over of {@code map} and the lists returned by - * {@code factory}. Those objects should not be manually updated, they should be empty when - * provided, and they should not use soft, weak, or phantom references. - * - * @param map place to store the mapping from each key to its corresponding values - * @param factory supplier of new, empty lists that will each hold all values for a given key - * @throws IllegalArgumentException if {@code map} is not empty - */ - public static <K, V> ListMultimap<K, V> newListMultimap( - Map<K, Collection<V>> map, final Supplier<? extends List<V>> factory) { - return new CustomListMultimap<>(map, factory); - } - - private static class CustomListMultimap<K, V> extends AbstractListMultimap<K, V> { - transient Supplier<? extends List<V>> factory; - - CustomListMultimap(Map<K, Collection<V>> map, Supplier<? extends List<V>> factory) { - super(map); - this.factory = checkNotNull(factory); - } - - @Override - Set<K> createKeySet() { - return createMaybeNavigableKeySet(); - } - - @Override - Map<K, Collection<V>> createAsMap() { - return createMaybeNavigableAsMap(); - } - - @Override - protected List<V> createCollection() { - return factory.get(); - } - - /** @serialData the factory and the backing map */ - @GwtIncompatible // java.io.ObjectOutputStream - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.defaultWriteObject(); - stream.writeObject(factory); - stream.writeObject(backingMap()); - } - - @GwtIncompatible // java.io.ObjectInputStream - @SuppressWarnings("unchecked") // reading data stored by writeObject - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - factory = (Supplier<? extends List<V>>) stream.readObject(); - Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject(); - setMap(map); - } - - @GwtIncompatible // java serialization not supported - private static final long serialVersionUID = 0; - } - - /** - * Creates a new {@code SetMultimap} that uses the provided map and factory. It can generate a - * multimap based on arbitrary {@link Map} and {@link Set} classes. - * - * <p>The {@code factory}-generated and {@code map} classes determine the multimap iteration - * order. They also specify the behavior of the {@code equals}, {@code hashCode}, and {@code - * toString} methods for the multimap and its returned views. However, the multimap's {@code get} - * method returns instances of a different class than {@code factory.get()} does. - * - * <p>The multimap is serializable if {@code map}, {@code factory}, the sets generated by {@code - * factory}, and the multimap contents are all serializable. - * - * <p>The multimap is not threadsafe when any concurrent operations update the multimap, even if - * {@code map} and the instances generated by {@code factory} are. Concurrent read operations will - * work correctly. To allow concurrent update operations, wrap the multimap with a call to {@link - * #synchronizedSetMultimap}. - * - * <p>Call this method only when the simpler methods {@link HashMultimap#create()}, {@link - * LinkedHashMultimap#create()}, {@link TreeMultimap#create()}, and {@link - * TreeMultimap#create(Comparator, Comparator)} won't suffice. - * - * <p>Note: the multimap assumes complete ownership over of {@code map} and the sets returned by - * {@code factory}. Those objects should not be manually updated and they should not use soft, - * weak, or phantom references. - * - * @param map place to store the mapping from each key to its corresponding values - * @param factory supplier of new, empty sets that will each hold all values for a given key - * @throws IllegalArgumentException if {@code map} is not empty - */ - public static <K, V> SetMultimap<K, V> newSetMultimap( - Map<K, Collection<V>> map, final Supplier<? extends Set<V>> factory) { - return new CustomSetMultimap<>(map, factory); - } - - private static class CustomSetMultimap<K, V> extends AbstractSetMultimap<K, V> { - transient Supplier<? extends Set<V>> factory; - - CustomSetMultimap(Map<K, Collection<V>> map, Supplier<? extends Set<V>> factory) { - super(map); - this.factory = checkNotNull(factory); - } - - @Override - Set<K> createKeySet() { - return createMaybeNavigableKeySet(); - } - - @Override - Map<K, Collection<V>> createAsMap() { - return createMaybeNavigableAsMap(); - } - - @Override - protected Set<V> createCollection() { - return factory.get(); - } - - @Override - <E> Collection<E> unmodifiableCollectionSubclass(Collection<E> collection) { - if (collection instanceof NavigableSet) { - return Sets.unmodifiableNavigableSet((NavigableSet<E>) collection); - } else if (collection instanceof SortedSet) { - return Collections.unmodifiableSortedSet((SortedSet<E>) collection); - } else { - return Collections.unmodifiableSet((Set<E>) collection); - } - } - - @Override - Collection<V> wrapCollection(K key, Collection<V> collection) { - if (collection instanceof NavigableSet) { - return new WrappedNavigableSet(key, (NavigableSet<V>) collection, null); - } else if (collection instanceof SortedSet) { - return new WrappedSortedSet(key, (SortedSet<V>) collection, null); - } else { - return new WrappedSet(key, (Set<V>) collection); - } - } - - /** @serialData the factory and the backing map */ - @GwtIncompatible // java.io.ObjectOutputStream - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.defaultWriteObject(); - stream.writeObject(factory); - stream.writeObject(backingMap()); - } - - @GwtIncompatible // java.io.ObjectInputStream - @SuppressWarnings("unchecked") // reading data stored by writeObject - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - factory = (Supplier<? extends Set<V>>) stream.readObject(); - Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject(); - setMap(map); - } - - @GwtIncompatible // not needed in emulated source - private static final long serialVersionUID = 0; - } - - /** - * Creates a new {@code SortedSetMultimap} that uses the provided map and factory. It can generate - * a multimap based on arbitrary {@link Map} and {@link SortedSet} classes. - * - * <p>The {@code factory}-generated and {@code map} classes determine the multimap iteration - * order. They also specify the behavior of the {@code equals}, {@code hashCode}, and {@code - * toString} methods for the multimap and its returned views. However, the multimap's {@code get} - * method returns instances of a different class than {@code factory.get()} does. - * - * <p>The multimap is serializable if {@code map}, {@code factory}, the sets generated by {@code - * factory}, and the multimap contents are all serializable. - * - * <p>The multimap is not threadsafe when any concurrent operations update the multimap, even if - * {@code map} and the instances generated by {@code factory} are. Concurrent read operations will - * work correctly. To allow concurrent update operations, wrap the multimap with a call to {@link - * #synchronizedSortedSetMultimap}. - * - * <p>Call this method only when the simpler methods {@link TreeMultimap#create()} and {@link - * TreeMultimap#create(Comparator, Comparator)} won't suffice. - * - * <p>Note: the multimap assumes complete ownership over of {@code map} and the sets returned by - * {@code factory}. Those objects should not be manually updated and they should not use soft, - * weak, or phantom references. - * - * @param map place to store the mapping from each key to its corresponding values - * @param factory supplier of new, empty sorted sets that will each hold all values for a given - * key - * @throws IllegalArgumentException if {@code map} is not empty - */ - public static <K, V> SortedSetMultimap<K, V> newSortedSetMultimap( - Map<K, Collection<V>> map, final Supplier<? extends SortedSet<V>> factory) { - return new CustomSortedSetMultimap<>(map, factory); - } - - private static class CustomSortedSetMultimap<K, V> extends AbstractSortedSetMultimap<K, V> { - transient Supplier<? extends SortedSet<V>> factory; - transient Comparator<? super V> valueComparator; - - CustomSortedSetMultimap(Map<K, Collection<V>> map, Supplier<? extends SortedSet<V>> factory) { - super(map); - this.factory = checkNotNull(factory); - valueComparator = factory.get().comparator(); - } - - @Override - Set<K> createKeySet() { - return createMaybeNavigableKeySet(); - } - - @Override - Map<K, Collection<V>> createAsMap() { - return createMaybeNavigableAsMap(); - } - - @Override - protected SortedSet<V> createCollection() { - return factory.get(); - } - - @Override - public Comparator<? super V> valueComparator() { - return valueComparator; - } - - /** @serialData the factory and the backing map */ - @GwtIncompatible // java.io.ObjectOutputStream - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.defaultWriteObject(); - stream.writeObject(factory); - stream.writeObject(backingMap()); - } - - @GwtIncompatible // java.io.ObjectInputStream - @SuppressWarnings("unchecked") // reading data stored by writeObject - private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { - stream.defaultReadObject(); - factory = (Supplier<? extends SortedSet<V>>) stream.readObject(); - valueComparator = factory.get().comparator(); - Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject(); - setMap(map); - } - - @GwtIncompatible // not needed in emulated source - private static final long serialVersionUID = 0; - } - - /** - * Copies each key-value mapping in {@code source} into {@code dest}, with its key and value - * reversed. - * - * <p>If {@code source} is an {@link ImmutableMultimap}, consider using {@link - * ImmutableMultimap#inverse} instead. - * - * @param source any multimap - * @param dest the multimap to copy into; usually empty - * @return {@code dest} - */ - @CanIgnoreReturnValue - public static <K, V, M extends Multimap<K, V>> M invertFrom( - Multimap<? extends V, ? extends K> source, M dest) { - checkNotNull(dest); - for (Map.Entry<? extends V, ? extends K> entry : source.entries()) { - dest.put(entry.getValue(), entry.getKey()); - } - return dest; - } - - /** - * Returns a synchronized (thread-safe) multimap backed by the specified multimap. In order to - * guarantee serial access, it is critical that <b>all</b> access to the backing multimap is - * accomplished through the returned multimap. - * - * <p>It is imperative that the user manually synchronize on the returned multimap when accessing - * any of its collection views: - * - * <pre>{@code - * Multimap<K, V> multimap = Multimaps.synchronizedMultimap( - * HashMultimap.<K, V>create()); - * ... - * Collection<V> values = multimap.get(key); // Needn't be in synchronized block - * ... - * synchronized (multimap) { // Synchronizing on multimap, not values! - * Iterator<V> i = values.iterator(); // Must be in synchronized block - * while (i.hasNext()) { - * foo(i.next()); - * } - * } - * }</pre> - * - * <p>Failure to follow this advice may result in non-deterministic behavior. - * - * <p>Note that the generated multimap's {@link Multimap#removeAll} and {@link - * Multimap#replaceValues} methods return collections that aren't synchronized. - * - * <p>The returned multimap will be serializable if the specified multimap is serializable. - * - * @param multimap the multimap to be wrapped in a synchronized view - * @return a synchronized view of the specified multimap - */ - public static <K, V> Multimap<K, V> synchronizedMultimap(Multimap<K, V> multimap) { - return Synchronized.multimap(multimap, null); - } - - /** - * Returns an unmodifiable view of the specified multimap. Query operations on the returned - * multimap "read through" to the specified multimap, and attempts to modify the returned - * multimap, either directly or through the multimap's views, result in an {@code - * UnsupportedOperationException}. - * - * <p>The returned multimap will be serializable if the specified multimap is serializable. - * - * @param delegate the multimap for which an unmodifiable view is to be returned - * @return an unmodifiable view of the specified multimap - */ - public static <K, V> Multimap<K, V> unmodifiableMultimap(Multimap<K, V> delegate) { - if (delegate instanceof UnmodifiableMultimap || delegate instanceof ImmutableMultimap) { - return delegate; - } - return new UnmodifiableMultimap<>(delegate); - } - - /** - * Simply returns its argument. - * - * @deprecated no need to use this - * @since 10.0 - */ - @Deprecated - public static <K, V> Multimap<K, V> unmodifiableMultimap(ImmutableMultimap<K, V> delegate) { - return checkNotNull(delegate); - } - - private static class UnmodifiableMultimap<K, V> extends ForwardingMultimap<K, V> - implements Serializable { - final Multimap<K, V> delegate; - @MonotonicNonNullDecl transient Collection<Entry<K, V>> entries; - @MonotonicNonNullDecl transient Multiset<K> keys; - @MonotonicNonNullDecl transient Set<K> keySet; - @MonotonicNonNullDecl transient Collection<V> values; - @MonotonicNonNullDecl transient Map<K, Collection<V>> map; - - UnmodifiableMultimap(final Multimap<K, V> delegate) { - this.delegate = checkNotNull(delegate); - } - - @Override - protected Multimap<K, V> delegate() { - return delegate; - } - - @Override - public void clear() { - throw new UnsupportedOperationException(); - } - - @Override - public Map<K, Collection<V>> asMap() { - Map<K, Collection<V>> result = map; - if (result == null) { - result = - map = - Collections.unmodifiableMap( - Maps.transformValues( - delegate.asMap(), - new Function<Collection<V>, Collection<V>>() { - @Override - public Collection<V> apply(Collection<V> collection) { - return unmodifiableValueCollection(collection); - } - })); - } - return result; - } - - @Override - public Collection<Entry<K, V>> entries() { - Collection<Entry<K, V>> result = entries; - if (result == null) { - entries = result = unmodifiableEntries(delegate.entries()); - } - return result; - } - - @Override - public Collection<V> get(K key) { - return unmodifiableValueCollection(delegate.get(key)); - } - - @Override - public Multiset<K> keys() { - Multiset<K> result = keys; - if (result == null) { - keys = result = Multisets.unmodifiableMultiset(delegate.keys()); - } - return result; - } - - @Override - public Set<K> keySet() { - Set<K> result = keySet; - if (result == null) { - keySet = result = Collections.unmodifiableSet(delegate.keySet()); - } - return result; - } - - @Override - public boolean put(K key, V value) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean putAll(K key, Iterable<? extends V> values) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean putAll(Multimap<? extends K, ? extends V> multimap) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean remove(Object key, Object value) { - throw new UnsupportedOperationException(); - } - - @Override - public Collection<V> removeAll(Object key) { - throw new UnsupportedOperationException(); - } - - @Override - public Collection<V> replaceValues(K key, Iterable<? extends V> values) { - throw new UnsupportedOperationException(); - } - - @Override - public Collection<V> values() { - Collection<V> result = values; - if (result == null) { - values = result = Collections.unmodifiableCollection(delegate.values()); - } - return result; - } - - private static final long serialVersionUID = 0; - } - - private static class UnmodifiableListMultimap<K, V> extends UnmodifiableMultimap<K, V> - implements ListMultimap<K, V> { - UnmodifiableListMultimap(ListMultimap<K, V> delegate) { - super(delegate); - } - - @Override - public ListMultimap<K, V> delegate() { - return (ListMultimap<K, V>) super.delegate(); - } - - @Override - public List<V> get(K key) { - return Collections.unmodifiableList(delegate().get(key)); - } - - @Override - public List<V> removeAll(Object key) { - throw new UnsupportedOperationException(); - } - - @Override - public List<V> replaceValues(K key, Iterable<? extends V> values) { - throw new UnsupportedOperationException(); - } - - private static final long serialVersionUID = 0; - } - - private static class UnmodifiableSetMultimap<K, V> extends UnmodifiableMultimap<K, V> - implements SetMultimap<K, V> { - UnmodifiableSetMultimap(SetMultimap<K, V> delegate) { - super(delegate); - } - - @Override - public SetMultimap<K, V> delegate() { - return (SetMultimap<K, V>) super.delegate(); - } - - @Override - public Set<V> get(K key) { - /* - * Note that this doesn't return a SortedSet when delegate is a - * SortedSetMultiset, unlike (SortedSet<V>) super.get(). - */ - return Collections.unmodifiableSet(delegate().get(key)); - } - - @Override - public Set<Map.Entry<K, V>> entries() { - return Maps.unmodifiableEntrySet(delegate().entries()); - } - - @Override - public Set<V> removeAll(Object key) { - throw new UnsupportedOperationException(); - } - - @Override - public Set<V> replaceValues(K key, Iterable<? extends V> values) { - throw new UnsupportedOperationException(); - } - - private static final long serialVersionUID = 0; - } - - private static class UnmodifiableSortedSetMultimap<K, V> extends UnmodifiableSetMultimap<K, V> - implements SortedSetMultimap<K, V> { - UnmodifiableSortedSetMultimap(SortedSetMultimap<K, V> delegate) { - super(delegate); - } - - @Override - public SortedSetMultimap<K, V> delegate() { - return (SortedSetMultimap<K, V>) super.delegate(); - } - - @Override - public SortedSet<V> get(K key) { - return Collections.unmodifiableSortedSet(delegate().get(key)); - } - - @Override - public SortedSet<V> removeAll(Object key) { - throw new UnsupportedOperationException(); - } - - @Override - public SortedSet<V> replaceValues(K key, Iterable<? extends V> values) { - throw new UnsupportedOperationException(); - } - - @Override - public Comparator<? super V> valueComparator() { - return delegate().valueComparator(); - } - - private static final long serialVersionUID = 0; - } - - /** - * Returns a synchronized (thread-safe) {@code SetMultimap} backed by the specified multimap. - * - * <p>You must follow the warnings described in {@link #synchronizedMultimap}. - * - * <p>The returned multimap will be serializable if the specified multimap is serializable. - * - * @param multimap the multimap to be wrapped - * @return a synchronized view of the specified multimap - */ - public static <K, V> SetMultimap<K, V> synchronizedSetMultimap(SetMultimap<K, V> multimap) { - return Synchronized.setMultimap(multimap, null); - } - - /** - * Returns an unmodifiable view of the specified {@code SetMultimap}. Query operations on the - * returned multimap "read through" to the specified multimap, and attempts to modify the returned - * multimap, either directly or through the multimap's views, result in an {@code - * UnsupportedOperationException}. - * - * <p>The returned multimap will be serializable if the specified multimap is serializable. - * - * @param delegate the multimap for which an unmodifiable view is to be returned - * @return an unmodifiable view of the specified multimap - */ - public static <K, V> SetMultimap<K, V> unmodifiableSetMultimap(SetMultimap<K, V> delegate) { - if (delegate instanceof UnmodifiableSetMultimap || delegate instanceof ImmutableSetMultimap) { - return delegate; - } - return new UnmodifiableSetMultimap<>(delegate); - } - - /** - * Simply returns its argument. - * - * @deprecated no need to use this - * @since 10.0 - */ - @Deprecated - public static <K, V> SetMultimap<K, V> unmodifiableSetMultimap( - ImmutableSetMultimap<K, V> delegate) { - return checkNotNull(delegate); - } - - /** - * Returns a synchronized (thread-safe) {@code SortedSetMultimap} backed by the specified - * multimap. - * - * <p>You must follow the warnings described in {@link #synchronizedMultimap}. - * - * <p>The returned multimap will be serializable if the specified multimap is serializable. - * - * @param multimap the multimap to be wrapped - * @return a synchronized view of the specified multimap - */ - public static <K, V> SortedSetMultimap<K, V> synchronizedSortedSetMultimap( - SortedSetMultimap<K, V> multimap) { - return Synchronized.sortedSetMultimap(multimap, null); - } - - /** - * Returns an unmodifiable view of the specified {@code SortedSetMultimap}. Query operations on - * the returned multimap "read through" to the specified multimap, and attempts to modify the - * returned multimap, either directly or through the multimap's views, result in an {@code - * UnsupportedOperationException}. - * - * <p>The returned multimap will be serializable if the specified multimap is serializable. - * - * @param delegate the multimap for which an unmodifiable view is to be returned - * @return an unmodifiable view of the specified multimap - */ - public static <K, V> SortedSetMultimap<K, V> unmodifiableSortedSetMultimap( - SortedSetMultimap<K, V> delegate) { - if (delegate instanceof UnmodifiableSortedSetMultimap) { - return delegate; - } - return new UnmodifiableSortedSetMultimap<>(delegate); - } - - /** - * Returns a synchronized (thread-safe) {@code ListMultimap} backed by the specified multimap. - * - * <p>You must follow the warnings described in {@link #synchronizedMultimap}. - * - * @param multimap the multimap to be wrapped - * @return a synchronized view of the specified multimap - */ - public static <K, V> ListMultimap<K, V> synchronizedListMultimap(ListMultimap<K, V> multimap) { - return Synchronized.listMultimap(multimap, null); - } - - /** - * Returns an unmodifiable view of the specified {@code ListMultimap}. Query operations on the - * returned multimap "read through" to the specified multimap, and attempts to modify the returned - * multimap, either directly or through the multimap's views, result in an {@code - * UnsupportedOperationException}. - * - * <p>The returned multimap will be serializable if the specified multimap is serializable. - * - * @param delegate the multimap for which an unmodifiable view is to be returned - * @return an unmodifiable view of the specified multimap - */ - public static <K, V> ListMultimap<K, V> unmodifiableListMultimap(ListMultimap<K, V> delegate) { - if (delegate instanceof UnmodifiableListMultimap || delegate instanceof ImmutableListMultimap) { - return delegate; - } - return new UnmodifiableListMultimap<>(delegate); - } - - /** - * Simply returns its argument. - * - * @deprecated no need to use this - * @since 10.0 - */ - @Deprecated - public static <K, V> ListMultimap<K, V> unmodifiableListMultimap( - ImmutableListMultimap<K, V> delegate) { - return checkNotNull(delegate); - } - - /** - * Returns an unmodifiable view of the specified collection, preserving the interface for - * instances of {@code SortedSet}, {@code Set}, {@code List} and {@code Collection}, in that order - * of preference. - * - * @param collection the collection for which to return an unmodifiable view - * @return an unmodifiable view of the collection - */ - private static <V> Collection<V> unmodifiableValueCollection(Collection<V> collection) { - if (collection instanceof SortedSet) { - return Collections.unmodifiableSortedSet((SortedSet<V>) collection); - } else if (collection instanceof Set) { - return Collections.unmodifiableSet((Set<V>) collection); - } else if (collection instanceof List) { - return Collections.unmodifiableList((List<V>) collection); - } - return Collections.unmodifiableCollection(collection); - } - - /** - * Returns an unmodifiable view of the specified collection of entries. The {@link Entry#setValue} - * operation throws an {@link UnsupportedOperationException}. If the specified collection is a - * {@code Set}, the returned collection is also a {@code Set}. - * - * @param entries the entries for which to return an unmodifiable view - * @return an unmodifiable view of the entries - */ - private static <K, V> Collection<Entry<K, V>> unmodifiableEntries( - Collection<Entry<K, V>> entries) { - if (entries instanceof Set) { - return Maps.unmodifiableEntrySet((Set<Entry<K, V>>) entries); - } - return new Maps.UnmodifiableEntries<>(Collections.unmodifiableCollection(entries)); - } - - /** - * Returns {@link ListMultimap#asMap multimap.asMap()}, with its type corrected from {@code Map<K, - * Collection<V>>} to {@code Map<K, List<V>>}. - * - * @since 15.0 - */ - @Beta - @SuppressWarnings("unchecked") - // safe by specification of ListMultimap.asMap() - public static <K, V> Map<K, List<V>> asMap(ListMultimap<K, V> multimap) { - return (Map<K, List<V>>) (Map<K, ?>) multimap.asMap(); - } - - /** - * Returns {@link SetMultimap#asMap multimap.asMap()}, with its type corrected from {@code Map<K, - * Collection<V>>} to {@code Map<K, Set<V>>}. - * - * @since 15.0 - */ - @Beta - @SuppressWarnings("unchecked") - // safe by specification of SetMultimap.asMap() - public static <K, V> Map<K, Set<V>> asMap(SetMultimap<K, V> multimap) { - return (Map<K, Set<V>>) (Map<K, ?>) multimap.asMap(); - } - - /** - * Returns {@link SortedSetMultimap#asMap multimap.asMap()}, with its type corrected from {@code - * Map<K, Collection<V>>} to {@code Map<K, SortedSet<V>>}. - * - * @since 15.0 - */ - @Beta - @SuppressWarnings("unchecked") - // safe by specification of SortedSetMultimap.asMap() - public static <K, V> Map<K, SortedSet<V>> asMap(SortedSetMultimap<K, V> multimap) { - return (Map<K, SortedSet<V>>) (Map<K, ?>) multimap.asMap(); - } - - /** - * Returns {@link Multimap#asMap multimap.asMap()}. This is provided for parity with the other - * more strongly-typed {@code asMap()} implementations. - * - * @since 15.0 - */ - @Beta - public static <K, V> Map<K, Collection<V>> asMap(Multimap<K, V> multimap) { - return multimap.asMap(); - } - - /** - * Returns a multimap view of the specified map. The multimap is backed by the map, so changes to - * the map are reflected in the multimap, and vice versa. If the map is modified while an - * iteration over one of the multimap's collection views is in progress (except through the - * iterator's own {@code remove} operation, or through the {@code setValue} operation on a map - * entry returned by the iterator), the results of the iteration are undefined. - * - * <p>The multimap supports mapping removal, which removes the corresponding mapping from the map. - * It does not support any operations which might add mappings, such as {@code put}, {@code - * putAll} or {@code replaceValues}. - * - * <p>The returned multimap will be serializable if the specified map is serializable. - * - * @param map the backing map for the returned multimap view - */ - public static <K, V> SetMultimap<K, V> forMap(Map<K, V> map) { - return new MapMultimap<>(map); - } - - /** @see Multimaps#forMap */ - private static class MapMultimap<K, V> extends AbstractMultimap<K, V> - implements SetMultimap<K, V>, Serializable { - final Map<K, V> map; - - MapMultimap(Map<K, V> map) { - this.map = checkNotNull(map); - } - - @Override - public int size() { - return map.size(); - } - - @Override - public boolean containsKey(Object key) { - return map.containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return map.containsValue(value); - } - - @Override - public boolean containsEntry(Object key, Object value) { - return map.entrySet().contains(Maps.immutableEntry(key, value)); - } - - @Override - public Set<V> get(final K key) { - return new Sets.ImprovedAbstractSet<V>() { - @Override - public Iterator<V> iterator() { - return new Iterator<V>() { - int i; - - @Override - public boolean hasNext() { - return (i == 0) && map.containsKey(key); - } - - @Override - public V next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - i++; - return map.get(key); - } - - @Override - public void remove() { - checkRemove(i == 1); - i = -1; - map.remove(key); - } - }; - } - - @Override - public int size() { - return map.containsKey(key) ? 1 : 0; - } - }; - } - - @Override - public boolean put(K key, V value) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean putAll(K key, Iterable<? extends V> values) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean putAll(Multimap<? extends K, ? extends V> multimap) { - throw new UnsupportedOperationException(); - } - - @Override - public Set<V> replaceValues(K key, Iterable<? extends V> values) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean remove(Object key, Object value) { - return map.entrySet().remove(Maps.immutableEntry(key, value)); - } - - @Override - public Set<V> removeAll(Object key) { - Set<V> values = new HashSet<V>(2); - if (!map.containsKey(key)) { - return values; - } - values.add(map.remove(key)); - return values; - } - - @Override - public void clear() { - map.clear(); - } - - @Override - Set<K> createKeySet() { - return map.keySet(); - } - - @Override - Collection<V> createValues() { - return map.values(); - } - - @Override - public Set<Entry<K, V>> entries() { - return map.entrySet(); - } - - @Override - Collection<Entry<K, V>> createEntries() { - throw new AssertionError("unreachable"); - } - - @Override - Multiset<K> createKeys() { - return new Multimaps.Keys<K, V>(this); - } - - @Override - Iterator<Entry<K, V>> entryIterator() { - return map.entrySet().iterator(); - } - - @Override - Map<K, Collection<V>> createAsMap() { - return new AsMap<>(this); - } - - @Override - public int hashCode() { - return map.hashCode(); - } - - private static final long serialVersionUID = 7845222491160860175L; - } - - /** - * Returns a view of a multimap where each value is transformed by a function. All other - * properties of the multimap, such as iteration order, are left intact. For example, the code: - * - * <pre>{@code - * Multimap<String, Integer> multimap = - * ImmutableSetMultimap.of("a", 2, "b", -3, "b", -3, "a", 4, "c", 6); - * Function<Integer, String> square = new Function<Integer, String>() { - * public String apply(Integer in) { - * return Integer.toString(in * in); - * } - * }; - * Multimap<String, String> transformed = - * Multimaps.transformValues(multimap, square); - * System.out.println(transformed); - * }</pre> - * - * ... prints {@code {a=[4, 16], b=[9, 9], c=[36]}}. - * - * <p>Changes in the underlying multimap are reflected in this view. Conversely, this view - * supports removal operations, and these are reflected in the underlying multimap. - * - * <p>It's acceptable for the underlying multimap to contain null keys, and even null values - * provided that the function is capable of accepting null input. The transformed multimap might - * contain null values, if the function sometimes gives a null result. - * - * <p>The returned multimap is not thread-safe or serializable, even if the underlying multimap - * is. The {@code equals} and {@code hashCode} methods of the returned multimap are meaningless, - * since there is not a definition of {@code equals} or {@code hashCode} for general collections, - * and {@code get()} will return a general {@code Collection} as opposed to a {@code List} or a - * {@code Set}. - * - * <p>The function is applied lazily, invoked when needed. This is necessary for the returned - * multimap to be a view, but it means that the function will be applied many times for bulk - * operations like {@link Multimap#containsValue} and {@code Multimap.toString()}. For this to - * perform well, {@code function} should be fast. To avoid lazy evaluation when the returned - * multimap doesn't need to be a view, copy the returned multimap into a new multimap of your - * choosing. - * - * @since 7.0 - */ - public static <K, V1, V2> Multimap<K, V2> transformValues( - Multimap<K, V1> fromMultimap, final Function<? super V1, V2> function) { - checkNotNull(function); - EntryTransformer<K, V1, V2> transformer = Maps.asEntryTransformer(function); - return transformEntries(fromMultimap, transformer); - } - - /** - * Returns a view of a {@code ListMultimap} where each value is transformed by a function. All - * other properties of the multimap, such as iteration order, are left intact. For example, the - * code: - * - * <pre>{@code - * ListMultimap<String, Integer> multimap - * = ImmutableListMultimap.of("a", 4, "a", 16, "b", 9); - * Function<Integer, Double> sqrt = - * new Function<Integer, Double>() { - * public Double apply(Integer in) { - * return Math.sqrt((int) in); - * } - * }; - * ListMultimap<String, Double> transformed = Multimaps.transformValues(map, - * sqrt); - * System.out.println(transformed); - * }</pre> - * - * ... prints {@code {a=[2.0, 4.0], b=[3.0]}}. - * - * <p>Changes in the underlying multimap are reflected in this view. Conversely, this view - * supports removal operations, and these are reflected in the underlying multimap. - * - * <p>It's acceptable for the underlying multimap to contain null keys, and even null values - * provided that the function is capable of accepting null input. The transformed multimap might - * contain null values, if the function sometimes gives a null result. - * - * <p>The returned multimap is not thread-safe or serializable, even if the underlying multimap - * is. - * - * <p>The function is applied lazily, invoked when needed. This is necessary for the returned - * multimap to be a view, but it means that the function will be applied many times for bulk - * operations like {@link Multimap#containsValue} and {@code Multimap.toString()}. For this to - * perform well, {@code function} should be fast. To avoid lazy evaluation when the returned - * multimap doesn't need to be a view, copy the returned multimap into a new multimap of your - * choosing. - * - * @since 7.0 - */ - public static <K, V1, V2> ListMultimap<K, V2> transformValues( - ListMultimap<K, V1> fromMultimap, final Function<? super V1, V2> function) { - checkNotNull(function); - EntryTransformer<K, V1, V2> transformer = Maps.asEntryTransformer(function); - return transformEntries(fromMultimap, transformer); - } - - /** - * Returns a view of a multimap whose values are derived from the original multimap's entries. In - * contrast to {@link #transformValues}, this method's entry-transformation logic may depend on - * the key as well as the value. - * - * <p>All other properties of the transformed multimap, such as iteration order, are left intact. - * For example, the code: - * - * <pre>{@code - * SetMultimap<String, Integer> multimap = - * ImmutableSetMultimap.of("a", 1, "a", 4, "b", -6); - * EntryTransformer<String, Integer, String> transformer = - * new EntryTransformer<String, Integer, String>() { - * public String transformEntry(String key, Integer value) { - * return (value >= 0) ? key : "no" + key; - * } - * }; - * Multimap<String, String> transformed = - * Multimaps.transformEntries(multimap, transformer); - * System.out.println(transformed); - * }</pre> - * - * ... prints {@code {a=[a, a], b=[nob]}}. - * - * <p>Changes in the underlying multimap are reflected in this view. Conversely, this view - * supports removal operations, and these are reflected in the underlying multimap. - * - * <p>It's acceptable for the underlying multimap to contain null keys and null values provided - * that the transformer is capable of accepting null inputs. The transformed multimap might - * contain null values if the transformer sometimes gives a null result. - * - * <p>The returned multimap is not thread-safe or serializable, even if the underlying multimap - * is. The {@code equals} and {@code hashCode} methods of the returned multimap are meaningless, - * since there is not a definition of {@code equals} or {@code hashCode} for general collections, - * and {@code get()} will return a general {@code Collection} as opposed to a {@code List} or a - * {@code Set}. - * - * <p>The transformer is applied lazily, invoked when needed. This is necessary for the returned - * multimap to be a view, but it means that the transformer will be applied many times for bulk - * operations like {@link Multimap#containsValue} and {@link Object#toString}. For this to perform - * well, {@code transformer} should be fast. To avoid lazy evaluation when the returned multimap - * doesn't need to be a view, copy the returned multimap into a new multimap of your choosing. - * - * <p><b>Warning:</b> This method assumes that for any instance {@code k} of {@code - * EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also of - * type {@code K}. Using an {@code EntryTransformer} key type for which this may not hold, such as - * {@code ArrayList}, may risk a {@code ClassCastException} when calling methods on the - * transformed multimap. - * - * @since 7.0 - */ - public static <K, V1, V2> Multimap<K, V2> transformEntries( - Multimap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer) { - return new TransformedEntriesMultimap<>(fromMap, transformer); - } - - /** - * Returns a view of a {@code ListMultimap} whose values are derived from the original multimap's - * entries. In contrast to {@link #transformValues(ListMultimap, Function)}, this method's - * entry-transformation logic may depend on the key as well as the value. - * - * <p>All other properties of the transformed multimap, such as iteration order, are left intact. - * For example, the code: - * - * <pre>{@code - * Multimap<String, Integer> multimap = - * ImmutableMultimap.of("a", 1, "a", 4, "b", 6); - * EntryTransformer<String, Integer, String> transformer = - * new EntryTransformer<String, Integer, String>() { - * public String transformEntry(String key, Integer value) { - * return key + value; - * } - * }; - * Multimap<String, String> transformed = - * Multimaps.transformEntries(multimap, transformer); - * System.out.println(transformed); - * }</pre> - * - * ... prints {@code {"a"=["a1", "a4"], "b"=["b6"]}}. - * - * <p>Changes in the underlying multimap are reflected in this view. Conversely, this view - * supports removal operations, and these are reflected in the underlying multimap. - * - * <p>It's acceptable for the underlying multimap to contain null keys and null values provided - * that the transformer is capable of accepting null inputs. The transformed multimap might - * contain null values if the transformer sometimes gives a null result. - * - * <p>The returned multimap is not thread-safe or serializable, even if the underlying multimap - * is. - * - * <p>The transformer is applied lazily, invoked when needed. This is necessary for the returned - * multimap to be a view, but it means that the transformer will be applied many times for bulk - * operations like {@link Multimap#containsValue} and {@link Object#toString}. For this to perform - * well, {@code transformer} should be fast. To avoid lazy evaluation when the returned multimap - * doesn't need to be a view, copy the returned multimap into a new multimap of your choosing. - * - * <p><b>Warning:</b> This method assumes that for any instance {@code k} of {@code - * EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also of - * type {@code K}. Using an {@code EntryTransformer} key type for which this may not hold, such as - * {@code ArrayList}, may risk a {@code ClassCastException} when calling methods on the - * transformed multimap. - * - * @since 7.0 - */ - public static <K, V1, V2> ListMultimap<K, V2> transformEntries( - ListMultimap<K, V1> fromMap, EntryTransformer<? super K, ? super V1, V2> transformer) { - return new TransformedEntriesListMultimap<>(fromMap, transformer); - } - - private static class TransformedEntriesMultimap<K, V1, V2> extends AbstractMultimap<K, V2> { - final Multimap<K, V1> fromMultimap; - final EntryTransformer<? super K, ? super V1, V2> transformer; - - TransformedEntriesMultimap( - Multimap<K, V1> fromMultimap, - final EntryTransformer<? super K, ? super V1, V2> transformer) { - this.fromMultimap = checkNotNull(fromMultimap); - this.transformer = checkNotNull(transformer); - } - - Collection<V2> transform(K key, Collection<V1> values) { - Function<? super V1, V2> function = Maps.asValueToValueFunction(transformer, key); - if (values instanceof List) { - return Lists.transform((List<V1>) values, function); - } else { - return Collections2.transform(values, function); - } - } - - @Override - Map<K, Collection<V2>> createAsMap() { - return Maps.transformEntries( - fromMultimap.asMap(), - new EntryTransformer<K, Collection<V1>, Collection<V2>>() { - @Override - public Collection<V2> transformEntry(K key, Collection<V1> value) { - return transform(key, value); - } - }); - } - - @Override - public void clear() { - fromMultimap.clear(); - } - - @Override - public boolean containsKey(Object key) { - return fromMultimap.containsKey(key); - } - - @Override - Collection<Entry<K, V2>> createEntries() { - return new Entries(); - } - - @Override - Iterator<Entry<K, V2>> entryIterator() { - return Iterators.transform( - fromMultimap.entries().iterator(), Maps.<K, V1, V2>asEntryToEntryFunction(transformer)); - } - - @Override - public Collection<V2> get(final K key) { - return transform(key, fromMultimap.get(key)); - } - - @Override - public boolean isEmpty() { - return fromMultimap.isEmpty(); - } - - @Override - Set<K> createKeySet() { - return fromMultimap.keySet(); - } - - @Override - Multiset<K> createKeys() { - return fromMultimap.keys(); - } - - @Override - public boolean put(K key, V2 value) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean putAll(K key, Iterable<? extends V2> values) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean putAll(Multimap<? extends K, ? extends V2> multimap) { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("unchecked") - @Override - public boolean remove(Object key, Object value) { - return get((K) key).remove(value); - } - - @SuppressWarnings("unchecked") - @Override - public Collection<V2> removeAll(Object key) { - return transform((K) key, fromMultimap.removeAll(key)); - } - - @Override - public Collection<V2> replaceValues(K key, Iterable<? extends V2> values) { - throw new UnsupportedOperationException(); - } - - @Override - public int size() { - return fromMultimap.size(); - } - - @Override - Collection<V2> createValues() { - return Collections2.transform( - fromMultimap.entries(), Maps.<K, V1, V2>asEntryToValueFunction(transformer)); - } - } - - private static final class TransformedEntriesListMultimap<K, V1, V2> - extends TransformedEntriesMultimap<K, V1, V2> implements ListMultimap<K, V2> { - - TransformedEntriesListMultimap( - ListMultimap<K, V1> fromMultimap, EntryTransformer<? super K, ? super V1, V2> transformer) { - super(fromMultimap, transformer); - } - - @Override - List<V2> transform(K key, Collection<V1> values) { - return Lists.transform((List<V1>) values, Maps.asValueToValueFunction(transformer, key)); - } - - @Override - public List<V2> get(K key) { - return transform(key, fromMultimap.get(key)); - } - - @SuppressWarnings("unchecked") - @Override - public List<V2> removeAll(Object key) { - return transform((K) key, fromMultimap.removeAll(key)); - } - - @Override - public List<V2> replaceValues(K key, Iterable<? extends V2> values) { - throw new UnsupportedOperationException(); - } - } - - /** - * Creates an index {@code ImmutableListMultimap} that contains the results of applying a - * specified function to each item in an {@code Iterable} of values. Each value will be stored as - * a value in the resulting multimap, yielding a multimap with the same size as the input - * iterable. The key used to store that value in the multimap will be the result of calling the - * function on that value. The resulting multimap is created as an immutable snapshot. In the - * returned multimap, keys appear in the order they are first encountered, and the values - * corresponding to each key appear in the same order as they are encountered. - * - * <p>For example, - * - * <pre>{@code - * List<String> badGuys = - * Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde"); - * Function<String, Integer> stringLengthFunction = ...; - * Multimap<Integer, String> index = - * Multimaps.index(badGuys, stringLengthFunction); - * System.out.println(index); - * }</pre> - * - * <p>prints - * - * <pre>{@code - * {4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]} - * }</pre> - * - * <p>The returned multimap is serializable if its keys and values are all serializable. - * - * @param values the values to use when constructing the {@code ImmutableListMultimap} - * @param keyFunction the function used to produce the key for each value - * @return {@code ImmutableListMultimap} mapping the result of evaluating the function {@code - * keyFunction} on each value in the input collection to that value - * @throws NullPointerException if any element of {@code values} is {@code null}, or if {@code - * keyFunction} produces {@code null} for any key - */ - public static <K, V> ImmutableListMultimap<K, V> index( - Iterable<V> values, Function<? super V, K> keyFunction) { - return index(values.iterator(), keyFunction); - } - - /** - * Creates an index {@code ImmutableListMultimap} that contains the results of applying a - * specified function to each item in an {@code Iterator} of values. Each value will be stored as - * a value in the resulting multimap, yielding a multimap with the same size as the input - * iterator. The key used to store that value in the multimap will be the result of calling the - * function on that value. The resulting multimap is created as an immutable snapshot. In the - * returned multimap, keys appear in the order they are first encountered, and the values - * corresponding to each key appear in the same order as they are encountered. - * - * <p>For example, - * - * <pre>{@code - * List<String> badGuys = - * Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde"); - * Function<String, Integer> stringLengthFunction = ...; - * Multimap<Integer, String> index = - * Multimaps.index(badGuys.iterator(), stringLengthFunction); - * System.out.println(index); - * }</pre> - * - * <p>prints - * - * <pre>{@code - * {4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]} - * }</pre> - * - * <p>The returned multimap is serializable if its keys and values are all serializable. - * - * @param values the values to use when constructing the {@code ImmutableListMultimap} - * @param keyFunction the function used to produce the key for each value - * @return {@code ImmutableListMultimap} mapping the result of evaluating the function {@code - * keyFunction} on each value in the input collection to that value - * @throws NullPointerException if any element of {@code values} is {@code null}, or if {@code - * keyFunction} produces {@code null} for any key - * @since 10.0 - */ - public static <K, V> ImmutableListMultimap<K, V> index( - Iterator<V> values, Function<? super V, K> keyFunction) { - checkNotNull(keyFunction); - ImmutableListMultimap.Builder<K, V> builder = ImmutableListMultimap.builder(); - while (values.hasNext()) { - V value = values.next(); - checkNotNull(value, values); - builder.put(keyFunction.apply(value), value); - } - return builder.build(); - } - - static class Keys<K, V> extends AbstractMultiset<K> { - @Weak final Multimap<K, V> multimap; - - Keys(Multimap<K, V> multimap) { - this.multimap = multimap; - } - - @Override - Iterator<Multiset.Entry<K>> entryIterator() { - return new TransformedIterator<Map.Entry<K, Collection<V>>, Multiset.Entry<K>>( - multimap.asMap().entrySet().iterator()) { - @Override - Multiset.Entry<K> transform(final Map.Entry<K, Collection<V>> backingEntry) { - return new Multisets.AbstractEntry<K>() { - @Override - public K getElement() { - return backingEntry.getKey(); - } - - @Override - public int getCount() { - return backingEntry.getValue().size(); - } - }; - } - }; - } - - @Override - int distinctElements() { - return multimap.asMap().size(); - } - - @Override - public int size() { - return multimap.size(); - } - - @Override - public boolean contains(@NullableDecl Object element) { - return multimap.containsKey(element); - } - - @Override - public Iterator<K> iterator() { - return Maps.keyIterator(multimap.entries().iterator()); - } - - @Override - public int count(@NullableDecl Object element) { - Collection<V> values = Maps.safeGet(multimap.asMap(), element); - return (values == null) ? 0 : values.size(); - } - - @Override - public int remove(@NullableDecl Object element, int occurrences) { - checkNonnegative(occurrences, "occurrences"); - if (occurrences == 0) { - return count(element); - } - - Collection<V> values = Maps.safeGet(multimap.asMap(), element); - - if (values == null) { - return 0; - } - - int oldCount = values.size(); - if (occurrences >= oldCount) { - values.clear(); - } else { - Iterator<V> iterator = values.iterator(); - for (int i = 0; i < occurrences; i++) { - iterator.next(); - iterator.remove(); - } - } - return oldCount; - } - - @Override - public void clear() { - multimap.clear(); - } - - @Override - public Set<K> elementSet() { - return multimap.keySet(); - } - - @Override - Iterator<K> elementIterator() { - throw new AssertionError("should never be called"); - } - } - - /** A skeleton implementation of {@link Multimap#entries()}. */ - abstract static class Entries<K, V> extends AbstractCollection<Map.Entry<K, V>> { - abstract Multimap<K, V> multimap(); - - @Override - public int size() { - return multimap().size(); - } - - @Override - public boolean contains(@NullableDecl Object o) { - if (o instanceof Map.Entry) { - Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o; - return multimap().containsEntry(entry.getKey(), entry.getValue()); - } - return false; - } - - @Override - public boolean remove(@NullableDecl Object o) { - if (o instanceof Map.Entry) { - Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o; - return multimap().remove(entry.getKey(), entry.getValue()); - } - return false; - } - - @Override - public void clear() { - multimap().clear(); - } - } - - /** A skeleton implementation of {@link Multimap#asMap()}. */ - static final class AsMap<K, V> extends Maps.ViewCachingAbstractMap<K, Collection<V>> { - @Weak private final Multimap<K, V> multimap; - - AsMap(Multimap<K, V> multimap) { - this.multimap = checkNotNull(multimap); - } - - @Override - public int size() { - return multimap.keySet().size(); - } - - @Override - protected Set<Entry<K, Collection<V>>> createEntrySet() { - return new EntrySet(); - } - - void removeValuesForKey(Object key) { - multimap.keySet().remove(key); - } - - @WeakOuter - class EntrySet extends Maps.EntrySet<K, Collection<V>> { - @Override - Map<K, Collection<V>> map() { - return AsMap.this; - } - - @Override - public Iterator<Entry<K, Collection<V>>> iterator() { - return Maps.asMapEntryIterator( - multimap.keySet(), - new Function<K, Collection<V>>() { - @Override - public Collection<V> apply(K key) { - return multimap.get(key); - } - }); - } - - @Override - public boolean remove(Object o) { - if (!contains(o)) { - return false; - } - Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o; - removeValuesForKey(entry.getKey()); - return true; - } - } - - @SuppressWarnings("unchecked") - @Override - public Collection<V> get(Object key) { - return containsKey(key) ? multimap.get((K) key) : null; - } - - @Override - public Collection<V> remove(Object key) { - return containsKey(key) ? multimap.removeAll(key) : null; - } - - @Override - public Set<K> keySet() { - return multimap.keySet(); - } - - @Override - public boolean isEmpty() { - return multimap.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return multimap.containsKey(key); - } - - @Override - public void clear() { - multimap.clear(); - } - } - - /** - * Returns a multimap containing the mappings in {@code unfiltered} whose keys satisfy a - * predicate. The returned multimap is a live view of {@code unfiltered}; changes to one affect - * the other. - * - * <p>The resulting multimap's views have iterators that don't support {@code remove()}, but all - * other methods are supported by the multimap and its views. When adding a key that doesn't - * satisfy the predicate, the multimap's {@code put()}, {@code putAll()}, and {@code - * replaceValues()} methods throw an {@link IllegalArgumentException}. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * multimap or its views, only mappings whose keys satisfy the filter will be removed from the - * underlying multimap. - * - * <p>The returned multimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate across every - * key/value mapping in the underlying multimap and determine which satisfy the filter. When a - * live view is <i>not</i> needed, it may be faster to copy the filtered multimap and use the - * copy. - * - * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with equals</i>, as documented at - * {@link Predicate#apply}. Do not provide a predicate such as {@code - * Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. - * - * @since 11.0 - */ - public static <K, V> Multimap<K, V> filterKeys( - Multimap<K, V> unfiltered, final Predicate<? super K> keyPredicate) { - if (unfiltered instanceof SetMultimap) { - return filterKeys((SetMultimap<K, V>) unfiltered, keyPredicate); - } else if (unfiltered instanceof ListMultimap) { - return filterKeys((ListMultimap<K, V>) unfiltered, keyPredicate); - } else if (unfiltered instanceof FilteredKeyMultimap) { - FilteredKeyMultimap<K, V> prev = (FilteredKeyMultimap<K, V>) unfiltered; - return new FilteredKeyMultimap<>( - prev.unfiltered, Predicates.<K>and(prev.keyPredicate, keyPredicate)); - } else if (unfiltered instanceof FilteredMultimap) { - FilteredMultimap<K, V> prev = (FilteredMultimap<K, V>) unfiltered; - return filterFiltered(prev, Maps.<K>keyPredicateOnEntries(keyPredicate)); - } else { - return new FilteredKeyMultimap<>(unfiltered, keyPredicate); - } - } - - /** - * Returns a multimap containing the mappings in {@code unfiltered} whose keys satisfy a - * predicate. The returned multimap is a live view of {@code unfiltered}; changes to one affect - * the other. - * - * <p>The resulting multimap's views have iterators that don't support {@code remove()}, but all - * other methods are supported by the multimap and its views. When adding a key that doesn't - * satisfy the predicate, the multimap's {@code put()}, {@code putAll()}, and {@code - * replaceValues()} methods throw an {@link IllegalArgumentException}. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * multimap or its views, only mappings whose keys satisfy the filter will be removed from the - * underlying multimap. - * - * <p>The returned multimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate across every - * key/value mapping in the underlying multimap and determine which satisfy the filter. When a - * live view is <i>not</i> needed, it may be faster to copy the filtered multimap and use the - * copy. - * - * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with equals</i>, as documented at - * {@link Predicate#apply}. Do not provide a predicate such as {@code - * Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. - * - * @since 14.0 - */ - public static <K, V> SetMultimap<K, V> filterKeys( - SetMultimap<K, V> unfiltered, final Predicate<? super K> keyPredicate) { - if (unfiltered instanceof FilteredKeySetMultimap) { - FilteredKeySetMultimap<K, V> prev = (FilteredKeySetMultimap<K, V>) unfiltered; - return new FilteredKeySetMultimap<>( - prev.unfiltered(), Predicates.<K>and(prev.keyPredicate, keyPredicate)); - } else if (unfiltered instanceof FilteredSetMultimap) { - FilteredSetMultimap<K, V> prev = (FilteredSetMultimap<K, V>) unfiltered; - return filterFiltered(prev, Maps.<K>keyPredicateOnEntries(keyPredicate)); - } else { - return new FilteredKeySetMultimap<>(unfiltered, keyPredicate); - } - } - - /** - * Returns a multimap containing the mappings in {@code unfiltered} whose keys satisfy a - * predicate. The returned multimap is a live view of {@code unfiltered}; changes to one affect - * the other. - * - * <p>The resulting multimap's views have iterators that don't support {@code remove()}, but all - * other methods are supported by the multimap and its views. When adding a key that doesn't - * satisfy the predicate, the multimap's {@code put()}, {@code putAll()}, and {@code - * replaceValues()} methods throw an {@link IllegalArgumentException}. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * multimap or its views, only mappings whose keys satisfy the filter will be removed from the - * underlying multimap. - * - * <p>The returned multimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate across every - * key/value mapping in the underlying multimap and determine which satisfy the filter. When a - * live view is <i>not</i> needed, it may be faster to copy the filtered multimap and use the - * copy. - * - * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with equals</i>, as documented at - * {@link Predicate#apply}. Do not provide a predicate such as {@code - * Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. - * - * @since 14.0 - */ - public static <K, V> ListMultimap<K, V> filterKeys( - ListMultimap<K, V> unfiltered, final Predicate<? super K> keyPredicate) { - if (unfiltered instanceof FilteredKeyListMultimap) { - FilteredKeyListMultimap<K, V> prev = (FilteredKeyListMultimap<K, V>) unfiltered; - return new FilteredKeyListMultimap<>( - prev.unfiltered(), Predicates.<K>and(prev.keyPredicate, keyPredicate)); - } else { - return new FilteredKeyListMultimap<>(unfiltered, keyPredicate); - } - } - - /** - * Returns a multimap containing the mappings in {@code unfiltered} whose values satisfy a - * predicate. The returned multimap is a live view of {@code unfiltered}; changes to one affect - * the other. - * - * <p>The resulting multimap's views have iterators that don't support {@code remove()}, but all - * other methods are supported by the multimap and its views. When adding a value that doesn't - * satisfy the predicate, the multimap's {@code put()}, {@code putAll()}, and {@code - * replaceValues()} methods throw an {@link IllegalArgumentException}. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * multimap or its views, only mappings whose value satisfy the filter will be removed from the - * underlying multimap. - * - * <p>The returned multimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate across every - * key/value mapping in the underlying multimap and determine which satisfy the filter. When a - * live view is <i>not</i> needed, it may be faster to copy the filtered multimap and use the - * copy. - * - * <p><b>Warning:</b> {@code valuePredicate} must be <i>consistent with equals</i>, as documented - * at {@link Predicate#apply}. Do not provide a predicate such as {@code - * Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. - * - * @since 11.0 - */ - public static <K, V> Multimap<K, V> filterValues( - Multimap<K, V> unfiltered, final Predicate<? super V> valuePredicate) { - return filterEntries(unfiltered, Maps.<V>valuePredicateOnEntries(valuePredicate)); - } - - /** - * Returns a multimap containing the mappings in {@code unfiltered} whose values satisfy a - * predicate. The returned multimap is a live view of {@code unfiltered}; changes to one affect - * the other. - * - * <p>The resulting multimap's views have iterators that don't support {@code remove()}, but all - * other methods are supported by the multimap and its views. When adding a value that doesn't - * satisfy the predicate, the multimap's {@code put()}, {@code putAll()}, and {@code - * replaceValues()} methods throw an {@link IllegalArgumentException}. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * multimap or its views, only mappings whose value satisfy the filter will be removed from the - * underlying multimap. - * - * <p>The returned multimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate across every - * key/value mapping in the underlying multimap and determine which satisfy the filter. When a - * live view is <i>not</i> needed, it may be faster to copy the filtered multimap and use the - * copy. - * - * <p><b>Warning:</b> {@code valuePredicate} must be <i>consistent with equals</i>, as documented - * at {@link Predicate#apply}. Do not provide a predicate such as {@code - * Predicates.instanceOf(ArrayList.class)}, which is inconsistent with equals. - * - * @since 14.0 - */ - public static <K, V> SetMultimap<K, V> filterValues( - SetMultimap<K, V> unfiltered, final Predicate<? super V> valuePredicate) { - return filterEntries(unfiltered, Maps.<V>valuePredicateOnEntries(valuePredicate)); - } - - /** - * Returns a multimap containing the mappings in {@code unfiltered} that satisfy a predicate. The - * returned multimap is a live view of {@code unfiltered}; changes to one affect the other. - * - * <p>The resulting multimap's views have iterators that don't support {@code remove()}, but all - * other methods are supported by the multimap and its views. When adding a key/value pair that - * doesn't satisfy the predicate, multimap's {@code put()}, {@code putAll()}, and {@code - * replaceValues()} methods throw an {@link IllegalArgumentException}. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * multimap or its views, only mappings whose keys satisfy the filter will be removed from the - * underlying multimap. - * - * <p>The returned multimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate across every - * key/value mapping in the underlying multimap and determine which satisfy the filter. When a - * live view is <i>not</i> needed, it may be faster to copy the filtered multimap and use the - * copy. - * - * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals</i>, as documented - * at {@link Predicate#apply}. - * - * @since 11.0 - */ - public static <K, V> Multimap<K, V> filterEntries( - Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) { - checkNotNull(entryPredicate); - if (unfiltered instanceof SetMultimap) { - return filterEntries((SetMultimap<K, V>) unfiltered, entryPredicate); - } - return (unfiltered instanceof FilteredMultimap) - ? filterFiltered((FilteredMultimap<K, V>) unfiltered, entryPredicate) - : new FilteredEntryMultimap<K, V>(checkNotNull(unfiltered), entryPredicate); - } - - /** - * Returns a multimap containing the mappings in {@code unfiltered} that satisfy a predicate. The - * returned multimap is a live view of {@code unfiltered}; changes to one affect the other. - * - * <p>The resulting multimap's views have iterators that don't support {@code remove()}, but all - * other methods are supported by the multimap and its views. When adding a key/value pair that - * doesn't satisfy the predicate, multimap's {@code put()}, {@code putAll()}, and {@code - * replaceValues()} methods throw an {@link IllegalArgumentException}. - * - * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered - * multimap or its views, only mappings whose keys satisfy the filter will be removed from the - * underlying multimap. - * - * <p>The returned multimap isn't threadsafe or serializable, even if {@code unfiltered} is. - * - * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate across every - * key/value mapping in the underlying multimap and determine which satisfy the filter. When a - * live view is <i>not</i> needed, it may be faster to copy the filtered multimap and use the - * copy. - * - * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals</i>, as documented - * at {@link Predicate#apply}. - * - * @since 14.0 - */ - public static <K, V> SetMultimap<K, V> filterEntries( - SetMultimap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) { - checkNotNull(entryPredicate); - return (unfiltered instanceof FilteredSetMultimap) - ? filterFiltered((FilteredSetMultimap<K, V>) unfiltered, entryPredicate) - : new FilteredEntrySetMultimap<K, V>(checkNotNull(unfiltered), entryPredicate); - } - - /** - * Support removal operations when filtering a filtered multimap. Since a filtered multimap has - * iterators that don't support remove, passing one to the FilteredEntryMultimap constructor would - * lead to a multimap whose removal operations would fail. This method combines the predicates to - * avoid that problem. - */ - private static <K, V> Multimap<K, V> filterFiltered( - FilteredMultimap<K, V> multimap, Predicate<? super Entry<K, V>> entryPredicate) { - Predicate<Entry<K, V>> predicate = - Predicates.<Entry<K, V>>and(multimap.entryPredicate(), entryPredicate); - return new FilteredEntryMultimap<>(multimap.unfiltered(), predicate); - } - - /** - * Support removal operations when filtering a filtered multimap. Since a filtered multimap has - * iterators that don't support remove, passing one to the FilteredEntryMultimap constructor would - * lead to a multimap whose removal operations would fail. This method combines the predicates to - * avoid that problem. - */ - private static <K, V> SetMultimap<K, V> filterFiltered( - FilteredSetMultimap<K, V> multimap, Predicate<? super Entry<K, V>> entryPredicate) { - Predicate<Entry<K, V>> predicate = - Predicates.<Entry<K, V>>and(multimap.entryPredicate(), entryPredicate); - return new FilteredEntrySetMultimap<>(multimap.unfiltered(), predicate); - } - - static boolean equalsImpl(Multimap<?, ?> multimap, @NullableDecl Object object) { - if (object == multimap) { - return true; - } - if (object instanceof Multimap) { - Multimap<?, ?> that = (Multimap<?, ?>) object; - return multimap.asMap().equals(that.asMap()); - } - return false; - } - - // TODO(jlevy): Create methods that filter a SortedSetMultimap. -} |