com.google.common.collect.Synchronized Maven / Gradle / Ivy
/*
* 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 com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.J2ktIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.j2objc.annotations.RetainedWith;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Queue;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Spliterator;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Synchronized collection views. The returned synchronized collection views are serializable if the
* backing collection and the mutex are serializable.
*
* If {@code null} is passed as the {@code mutex} parameter to any of this class's top-level
* methods or inner class constructors, the created object uses itself as the synchronization mutex.
*
*
This class should be used by other collection classes only.
*
* @author Mike Bostock
* @author Jared Levy
*/
@GwtCompatible(emulated = true)
@ElementTypesAreNonnullByDefault
/*
* I have decided not to bother adding @ParametricNullness annotations in this class. Adding them is
* a lot of busy work, and the annotation matters only when the APIs to be annotated are visible to
* Kotlin code. In this class, nothing is publicly visible (nor exposed indirectly through a
* publicly visible subclass), and I doubt any of our current or future Kotlin extensions for the
* package will refer to the class. Plus, @ParametricNullness is only a temporary workaround,
* anyway, so we just need to get by without the annotations here until Kotlin better understands
* our other nullness annotations.
*/
final class Synchronized {
private Synchronized() {}
static class SynchronizedObject implements Serializable {
final Object delegate;
final Object mutex;
SynchronizedObject(Object delegate, @CheckForNull Object mutex) {
this.delegate = checkNotNull(delegate);
this.mutex = (mutex == null) ? this : mutex;
}
Object delegate() {
return delegate;
}
// No equals and hashCode; see ForwardingObject for details.
@Override
public String toString() {
synchronized (mutex) {
return delegate.toString();
}
}
// Serialization invokes writeObject only when it's private.
// The SynchronizedObject subclasses don't need a writeObject method since
// they don't contain any non-transient member variables, while the
// following writeObject() handles the SynchronizedObject members.
@GwtIncompatible // java.io.ObjectOutputStream
@J2ktIncompatible
private void writeObject(ObjectOutputStream stream) throws IOException {
synchronized (mutex) {
stream.defaultWriteObject();
}
}
@GwtIncompatible // not needed in emulated source
@J2ktIncompatible
private static final long serialVersionUID = 0;
}
private static Collection collection(
Collection collection, @CheckForNull Object mutex) {
return new SynchronizedCollection<>(collection, mutex);
}
@VisibleForTesting
static class SynchronizedCollection extends SynchronizedObject
implements Collection {
private SynchronizedCollection(Collection delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@SuppressWarnings("unchecked")
@Override
Collection delegate() {
return (Collection) super.delegate();
}
@Override
public boolean add(E e) {
synchronized (mutex) {
return delegate().add(e);
}
}
@Override
public boolean addAll(Collection extends E> c) {
synchronized (mutex) {
return delegate().addAll(c);
}
}
@Override
public void clear() {
synchronized (mutex) {
delegate().clear();
}
}
@Override
public boolean contains(@CheckForNull Object o) {
synchronized (mutex) {
return delegate().contains(o);
}
}
@Override
public boolean containsAll(Collection> c) {
synchronized (mutex) {
return delegate().containsAll(c);
}
}
@Override
public boolean isEmpty() {
synchronized (mutex) {
return delegate().isEmpty();
}
}
@Override
public Iterator iterator() {
return delegate().iterator(); // manually synchronized
}
@Override
public Spliterator spliterator() {
synchronized (mutex) {
return delegate().spliterator();
}
}
@Override
public Stream stream() {
synchronized (mutex) {
return delegate().stream();
}
}
@Override
public Stream parallelStream() {
synchronized (mutex) {
return delegate().parallelStream();
}
}
@Override
public void forEach(Consumer super E> action) {
synchronized (mutex) {
delegate().forEach(action);
}
}
@Override
public boolean remove(@CheckForNull Object o) {
synchronized (mutex) {
return delegate().remove(o);
}
}
@Override
public boolean removeAll(Collection> c) {
synchronized (mutex) {
return delegate().removeAll(c);
}
}
@Override
public boolean retainAll(Collection> c) {
synchronized (mutex) {
return delegate().retainAll(c);
}
}
@Override
public boolean removeIf(Predicate super E> filter) {
synchronized (mutex) {
return delegate().removeIf(filter);
}
}
@Override
public int size() {
synchronized (mutex) {
return delegate().size();
}
}
@Override
public @Nullable Object[] toArray() {
synchronized (mutex) {
return delegate().toArray();
}
}
@Override
@SuppressWarnings("nullness") // b/192354773 in our checker affects toArray declarations
public T[] toArray(T[] a) {
synchronized (mutex) {
return delegate().toArray(a);
}
}
private static final long serialVersionUID = 0;
}
@VisibleForTesting
static Set set(Set set, @CheckForNull Object mutex) {
return new SynchronizedSet<>(set, mutex);
}
static class SynchronizedSet extends SynchronizedCollection
implements Set {
SynchronizedSet(Set delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
Set delegate() {
return (Set) super.delegate();
}
@Override
public boolean equals(@CheckForNull Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override
public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
private static SortedSet sortedSet(
SortedSet set, @CheckForNull Object mutex) {
return new SynchronizedSortedSet<>(set, mutex);
}
static class SynchronizedSortedSet extends SynchronizedSet
implements SortedSet {
SynchronizedSortedSet(SortedSet delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
SortedSet delegate() {
return (SortedSet) super.delegate();
}
@Override
@CheckForNull
public Comparator super E> comparator() {
synchronized (mutex) {
return delegate().comparator();
}
}
@Override
public SortedSet subSet(E fromElement, E toElement) {
synchronized (mutex) {
return sortedSet(delegate().subSet(fromElement, toElement), mutex);
}
}
@Override
public SortedSet headSet(E toElement) {
synchronized (mutex) {
return sortedSet(delegate().headSet(toElement), mutex);
}
}
@Override
public SortedSet tailSet(E fromElement) {
synchronized (mutex) {
return sortedSet(delegate().tailSet(fromElement), mutex);
}
}
@Override
public E first() {
synchronized (mutex) {
return delegate().first();
}
}
@Override
public E last() {
synchronized (mutex) {
return delegate().last();
}
}
private static final long serialVersionUID = 0;
}
private static List list(
List list, @CheckForNull Object mutex) {
return (list instanceof RandomAccess)
? new SynchronizedRandomAccessList(list, mutex)
: new SynchronizedList(list, mutex);
}
static class SynchronizedList extends SynchronizedCollection
implements List {
SynchronizedList(List delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
List delegate() {
return (List) super.delegate();
}
@Override
public void add(int index, E element) {
synchronized (mutex) {
delegate().add(index, element);
}
}
@Override
public boolean addAll(int index, Collection extends E> c) {
synchronized (mutex) {
return delegate().addAll(index, c);
}
}
@Override
public E get(int index) {
synchronized (mutex) {
return delegate().get(index);
}
}
@Override
public int indexOf(@CheckForNull Object o) {
synchronized (mutex) {
return delegate().indexOf(o);
}
}
@Override
public int lastIndexOf(@CheckForNull Object o) {
synchronized (mutex) {
return delegate().lastIndexOf(o);
}
}
@Override
public ListIterator listIterator() {
return delegate().listIterator(); // manually synchronized
}
@Override
public ListIterator listIterator(int index) {
return delegate().listIterator(index); // manually synchronized
}
@Override
public E remove(int index) {
synchronized (mutex) {
return delegate().remove(index);
}
}
@Override
public E set(int index, E element) {
synchronized (mutex) {
return delegate().set(index, element);
}
}
@Override
public void replaceAll(UnaryOperator operator) {
synchronized (mutex) {
delegate().replaceAll(operator);
}
}
@Override
public void sort(@Nullable Comparator super E> c) {
synchronized (mutex) {
delegate().sort(c);
}
}
@Override
public List subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return list(delegate().subList(fromIndex, toIndex), mutex);
}
}
@Override
public boolean equals(@CheckForNull Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override
public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
static final class SynchronizedRandomAccessList
extends SynchronizedList implements RandomAccess {
SynchronizedRandomAccessList(List list, @CheckForNull Object mutex) {
super(list, mutex);
}
private static final long serialVersionUID = 0;
}
static Multiset multiset(
Multiset multiset, @CheckForNull Object mutex) {
if (multiset instanceof SynchronizedMultiset || multiset instanceof ImmutableMultiset) {
return multiset;
}
return new SynchronizedMultiset<>(multiset, mutex);
}
static final class SynchronizedMultiset
extends SynchronizedCollection implements Multiset {
@CheckForNull transient Set elementSet;
@CheckForNull transient Set> entrySet;
SynchronizedMultiset(Multiset delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
Multiset delegate() {
return (Multiset) super.delegate();
}
@Override
public int count(@CheckForNull Object o) {
synchronized (mutex) {
return delegate().count(o);
}
}
@Override
public int add(@ParametricNullness E e, int n) {
synchronized (mutex) {
return delegate().add(e, n);
}
}
@Override
public int remove(@CheckForNull Object o, int n) {
synchronized (mutex) {
return delegate().remove(o, n);
}
}
@Override
public int setCount(@ParametricNullness E element, int count) {
synchronized (mutex) {
return delegate().setCount(element, count);
}
}
@Override
public boolean setCount(@ParametricNullness E element, int oldCount, int newCount) {
synchronized (mutex) {
return delegate().setCount(element, oldCount, newCount);
}
}
@Override
public Set elementSet() {
synchronized (mutex) {
if (elementSet == null) {
elementSet = typePreservingSet(delegate().elementSet(), mutex);
}
return elementSet;
}
}
@Override
public Set> entrySet() {
synchronized (mutex) {
if (entrySet == null) {
entrySet = typePreservingSet(delegate().entrySet(), mutex);
}
return entrySet;
}
}
@Override
public boolean equals(@CheckForNull Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override
public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
static Multimap multimap(
Multimap multimap, @CheckForNull Object mutex) {
if (multimap instanceof SynchronizedMultimap || multimap instanceof BaseImmutableMultimap) {
return multimap;
}
return new SynchronizedMultimap<>(multimap, mutex);
}
static class SynchronizedMultimap
extends SynchronizedObject implements Multimap {
@CheckForNull transient Set keySet;
@CheckForNull transient Collection valuesCollection;
@CheckForNull transient Collection> entries;
@CheckForNull transient Map> asMap;
@CheckForNull transient Multiset keys;
@SuppressWarnings("unchecked")
@Override
Multimap delegate() {
return (Multimap) super.delegate();
}
SynchronizedMultimap(Multimap delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
public int size() {
synchronized (mutex) {
return delegate().size();
}
}
@Override
public boolean isEmpty() {
synchronized (mutex) {
return delegate().isEmpty();
}
}
@Override
public boolean containsKey(@CheckForNull Object key) {
synchronized (mutex) {
return delegate().containsKey(key);
}
}
@Override
public boolean containsValue(@CheckForNull Object value) {
synchronized (mutex) {
return delegate().containsValue(value);
}
}
@Override
public boolean containsEntry(@CheckForNull Object key, @CheckForNull Object value) {
synchronized (mutex) {
return delegate().containsEntry(key, value);
}
}
@Override
public Collection get(@ParametricNullness K key) {
synchronized (mutex) {
return typePreservingCollection(delegate().get(key), mutex);
}
}
@Override
public boolean put(@ParametricNullness K key, @ParametricNullness V value) {
synchronized (mutex) {
return delegate().put(key, value);
}
}
@Override
public boolean putAll(@ParametricNullness K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().putAll(key, values);
}
}
@Override
public boolean putAll(Multimap extends K, ? extends V> multimap) {
synchronized (mutex) {
return delegate().putAll(multimap);
}
}
@Override
public Collection replaceValues(@ParametricNullness K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().replaceValues(key, values); // copy not synchronized
}
}
@Override
public boolean remove(@CheckForNull Object key, @CheckForNull Object value) {
synchronized (mutex) {
return delegate().remove(key, value);
}
}
@Override
public Collection removeAll(@CheckForNull Object key) {
synchronized (mutex) {
return delegate().removeAll(key); // copy not synchronized
}
}
@Override
public void clear() {
synchronized (mutex) {
delegate().clear();
}
}
@Override
public Set keySet() {
synchronized (mutex) {
if (keySet == null) {
keySet = typePreservingSet(delegate().keySet(), mutex);
}
return keySet;
}
}
@Override
public Collection values() {
synchronized (mutex) {
if (valuesCollection == null) {
valuesCollection = collection(delegate().values(), mutex);
}
return valuesCollection;
}
}
@Override
public Collection> entries() {
synchronized (mutex) {
if (entries == null) {
entries = typePreservingCollection(delegate().entries(), mutex);
}
return entries;
}
}
@Override
public void forEach(BiConsumer super K, ? super V> action) {
synchronized (mutex) {
delegate().forEach(action);
}
}
@Override
public Map> asMap() {
synchronized (mutex) {
if (asMap == null) {
asMap = new SynchronizedAsMap<>(delegate().asMap(), mutex);
}
return asMap;
}
}
@Override
public Multiset keys() {
synchronized (mutex) {
if (keys == null) {
keys = multiset(delegate().keys(), mutex);
}
return keys;
}
}
@Override
public boolean equals(@CheckForNull Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override
public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
static ListMultimap listMultimap(
ListMultimap multimap, @CheckForNull Object mutex) {
if (multimap instanceof SynchronizedListMultimap || multimap instanceof BaseImmutableMultimap) {
return multimap;
}
return new SynchronizedListMultimap<>(multimap, mutex);
}
static final class SynchronizedListMultimap<
K extends @Nullable Object, V extends @Nullable Object>
extends SynchronizedMultimap implements ListMultimap {
SynchronizedListMultimap(ListMultimap delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
ListMultimap delegate() {
return (ListMultimap) super.delegate();
}
@Override
public List get(K key) {
synchronized (mutex) {
return list(delegate().get(key), mutex);
}
}
@Override
public List removeAll(@CheckForNull Object key) {
synchronized (mutex) {
return delegate().removeAll(key); // copy not synchronized
}
}
@Override
public List replaceValues(K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().replaceValues(key, values); // copy not synchronized
}
}
private static final long serialVersionUID = 0;
}
static SetMultimap setMultimap(
SetMultimap multimap, @CheckForNull Object mutex) {
if (multimap instanceof SynchronizedSetMultimap || multimap instanceof BaseImmutableMultimap) {
return multimap;
}
return new SynchronizedSetMultimap<>(multimap, mutex);
}
static class SynchronizedSetMultimap
extends SynchronizedMultimap implements SetMultimap {
@CheckForNull transient Set> entrySet;
SynchronizedSetMultimap(SetMultimap delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
SetMultimap delegate() {
return (SetMultimap) super.delegate();
}
@Override
public Set get(K key) {
synchronized (mutex) {
return set(delegate().get(key), mutex);
}
}
@Override
public Set removeAll(@CheckForNull Object key) {
synchronized (mutex) {
return delegate().removeAll(key); // copy not synchronized
}
}
@Override
public Set replaceValues(K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().replaceValues(key, values); // copy not synchronized
}
}
@Override
public Set> entries() {
synchronized (mutex) {
if (entrySet == null) {
entrySet = set(delegate().entries(), mutex);
}
return entrySet;
}
}
private static final long serialVersionUID = 0;
}
static
SortedSetMultimap sortedSetMultimap(
SortedSetMultimap multimap, @CheckForNull Object mutex) {
if (multimap instanceof SynchronizedSortedSetMultimap) {
return multimap;
}
return new SynchronizedSortedSetMultimap<>(multimap, mutex);
}
static final class SynchronizedSortedSetMultimap<
K extends @Nullable Object, V extends @Nullable Object>
extends SynchronizedSetMultimap implements SortedSetMultimap {
SynchronizedSortedSetMultimap(SortedSetMultimap delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
SortedSetMultimap delegate() {
return (SortedSetMultimap) super.delegate();
}
@Override
public SortedSet get(K key) {
synchronized (mutex) {
return sortedSet(delegate().get(key), mutex);
}
}
@Override
public SortedSet removeAll(@CheckForNull Object key) {
synchronized (mutex) {
return delegate().removeAll(key); // copy not synchronized
}
}
@Override
public SortedSet replaceValues(K key, Iterable extends V> values) {
synchronized (mutex) {
return delegate().replaceValues(key, values); // copy not synchronized
}
}
@Override
@CheckForNull
public Comparator super V> valueComparator() {
synchronized (mutex) {
return delegate().valueComparator();
}
}
private static final long serialVersionUID = 0;
}
private static Collection typePreservingCollection(
Collection collection, @CheckForNull Object mutex) {
if (collection instanceof SortedSet) {
return sortedSet((SortedSet) collection, mutex);
}
if (collection instanceof Set) {
return set((Set) collection, mutex);
}
if (collection instanceof List) {
return list((List) collection, mutex);
}
return collection(collection, mutex);
}
private static Set typePreservingSet(
Set set, @CheckForNull Object mutex) {
if (set instanceof SortedSet) {
return sortedSet((SortedSet) set, mutex);
} else {
return set(set, mutex);
}
}
static final class SynchronizedAsMapEntries<
K extends @Nullable Object, V extends @Nullable Object>
extends SynchronizedSet>> {
SynchronizedAsMapEntries(
Set>> delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
public Iterator>> iterator() {
// Must be manually synchronized.
return new TransformedIterator>, Map.Entry>>(
super.iterator()) {
@Override
Map.Entry> transform(final Map.Entry> entry) {
return new ForwardingMapEntry>() {
@Override
protected Map.Entry> delegate() {
return entry;
}
@Override
public Collection getValue() {
return typePreservingCollection(entry.getValue(), mutex);
}
};
}
};
}
// See Collections.CheckedMap.CheckedEntrySet for details on attacks.
@Override
public @Nullable Object[] toArray() {
synchronized (mutex) {
/*
* toArrayImpl returns `@Nullable Object[]` rather than `Object[]` but only because it can
* be used with collections that may contain null. This collection never contains nulls, so
* we could return `Object[]`. But this class is private and J2KT cannot change return types
* in overrides, so we declare `@Nullable Object[]` as the return type.
*/
return ObjectArrays.toArrayImpl(delegate());
}
}
@Override
@SuppressWarnings("nullness") // b/192354773 in our checker affects toArray declarations
public T[] toArray(T[] array) {
synchronized (mutex) {
return ObjectArrays.toArrayImpl(delegate(), array);
}
}
@Override
public boolean contains(@CheckForNull Object o) {
synchronized (mutex) {
return Maps.containsEntryImpl(delegate(), o);
}
}
@Override
public boolean containsAll(Collection> c) {
synchronized (mutex) {
return Collections2.containsAllImpl(delegate(), c);
}
}
@Override
public boolean equals(@CheckForNull Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return Sets.equalsImpl(delegate(), o);
}
}
@Override
public boolean remove(@CheckForNull Object o) {
synchronized (mutex) {
return Maps.removeEntryImpl(delegate(), o);
}
}
@Override
public boolean removeAll(Collection> c) {
synchronized (mutex) {
return Iterators.removeAll(delegate().iterator(), c);
}
}
@Override
public boolean retainAll(Collection> c) {
synchronized (mutex) {
return Iterators.retainAll(delegate().iterator(), c);
}
}
private static final long serialVersionUID = 0;
}
@VisibleForTesting
static Map map(
Map map, @CheckForNull Object mutex) {
return new SynchronizedMap<>(map, mutex);
}
static class SynchronizedMap
extends SynchronizedObject implements Map {
@CheckForNull transient Set keySet;
@CheckForNull transient Collection values;
@CheckForNull transient Set> entrySet;
SynchronizedMap(Map delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@SuppressWarnings("unchecked")
@Override
Map delegate() {
return (Map) super.delegate();
}
@Override
public void clear() {
synchronized (mutex) {
delegate().clear();
}
}
@Override
public boolean containsKey(@CheckForNull Object key) {
synchronized (mutex) {
return delegate().containsKey(key);
}
}
@Override
public boolean containsValue(@CheckForNull Object value) {
synchronized (mutex) {
return delegate().containsValue(value);
}
}
@Override
public Set> entrySet() {
synchronized (mutex) {
if (entrySet == null) {
entrySet = set(delegate().entrySet(), mutex);
}
return entrySet;
}
}
@Override
public void forEach(BiConsumer super K, ? super V> action) {
synchronized (mutex) {
delegate().forEach(action);
}
}
@Override
@CheckForNull
public V get(@CheckForNull Object key) {
synchronized (mutex) {
return delegate().get(key);
}
}
@Override
@CheckForNull
public V getOrDefault(@CheckForNull Object key, @CheckForNull V defaultValue) {
synchronized (mutex) {
return delegate().getOrDefault(key, defaultValue);
}
}
@Override
public boolean isEmpty() {
synchronized (mutex) {
return delegate().isEmpty();
}
}
@Override
public Set keySet() {
synchronized (mutex) {
if (keySet == null) {
keySet = set(delegate().keySet(), mutex);
}
return keySet;
}
}
@Override
@CheckForNull
public V put(K key, V value) {
synchronized (mutex) {
return delegate().put(key, value);
}
}
@Override
@CheckForNull
public V putIfAbsent(K key, V value) {
synchronized (mutex) {
return delegate().putIfAbsent(key, value);
}
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
synchronized (mutex) {
return delegate().replace(key, oldValue, newValue);
}
}
@Override
@CheckForNull
public V replace(K key, V value) {
synchronized (mutex) {
return delegate().replace(key, value);
}
}
@Override
public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
synchronized (mutex) {
return delegate().computeIfAbsent(key, mappingFunction);
}
}
@Override
@CheckForNull
@SuppressWarnings("nullness") // TODO(b/262880368): Remove once we see @NonNull in JDK APIs
public V computeIfPresent(
K key, BiFunction super K, ? super @NonNull V, ? extends @Nullable V> remappingFunction) {
synchronized (mutex) {
return delegate().computeIfPresent(key, remappingFunction);
}
}
@Override
@CheckForNull
public V compute(
K key,
BiFunction super K, ? super @Nullable V, ? extends @Nullable V> remappingFunction) {
synchronized (mutex) {
return delegate().compute(key, remappingFunction);
}
}
@Override
@CheckForNull
@SuppressWarnings("nullness") // TODO(b/262880368): Remove once we see @NonNull in JDK APIs
public V merge(
K key,
@NonNull V value,
BiFunction super @NonNull V, ? super @NonNull V, ? extends @Nullable V>
remappingFunction) {
synchronized (mutex) {
return delegate().merge(key, value, remappingFunction);
}
}
@Override
public void putAll(Map extends K, ? extends V> map) {
synchronized (mutex) {
delegate().putAll(map);
}
}
@Override
public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
synchronized (mutex) {
delegate().replaceAll(function);
}
}
@Override
@CheckForNull
public V remove(@CheckForNull Object key) {
synchronized (mutex) {
return delegate().remove(key);
}
}
@Override
public boolean remove(@CheckForNull Object key, @CheckForNull Object value) {
synchronized (mutex) {
return delegate().remove(key, value);
}
}
@Override
public int size() {
synchronized (mutex) {
return delegate().size();
}
}
@Override
public Collection values() {
synchronized (mutex) {
if (values == null) {
values = collection(delegate().values(), mutex);
}
return values;
}
}
@Override
public boolean equals(@CheckForNull Object o) {
if (o == this) {
return true;
}
synchronized (mutex) {
return delegate().equals(o);
}
}
@Override
public int hashCode() {
synchronized (mutex) {
return delegate().hashCode();
}
}
private static final long serialVersionUID = 0;
}
static SortedMap sortedMap(
SortedMap sortedMap, @CheckForNull Object mutex) {
return new SynchronizedSortedMap<>(sortedMap, mutex);
}
static class SynchronizedSortedMap
extends SynchronizedMap implements SortedMap {
SynchronizedSortedMap(SortedMap delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
SortedMap delegate() {
return (SortedMap) super.delegate();
}
@Override
@CheckForNull
public Comparator super K> comparator() {
synchronized (mutex) {
return delegate().comparator();
}
}
@Override
public K firstKey() {
synchronized (mutex) {
return delegate().firstKey();
}
}
@Override
public SortedMap headMap(K toKey) {
synchronized (mutex) {
return sortedMap(delegate().headMap(toKey), mutex);
}
}
@Override
public K lastKey() {
synchronized (mutex) {
return delegate().lastKey();
}
}
@Override
public SortedMap subMap(K fromKey, K toKey) {
synchronized (mutex) {
return sortedMap(delegate().subMap(fromKey, toKey), mutex);
}
}
@Override
public SortedMap tailMap(K fromKey) {
synchronized (mutex) {
return sortedMap(delegate().tailMap(fromKey), mutex);
}
}
private static final long serialVersionUID = 0;
}
static BiMap biMap(
BiMap bimap, @CheckForNull Object mutex) {
if (bimap instanceof SynchronizedBiMap || bimap instanceof ImmutableBiMap) {
return bimap;
}
return new SynchronizedBiMap<>(bimap, mutex, null);
}
static final class SynchronizedBiMap
extends SynchronizedMap implements BiMap, Serializable {
@CheckForNull private transient Set valueSet;
@RetainedWith @CheckForNull private transient BiMap inverse;
private SynchronizedBiMap(
BiMap delegate, @CheckForNull Object mutex, @CheckForNull BiMap inverse) {
super(delegate, mutex);
this.inverse = inverse;
}
@Override
BiMap delegate() {
return (BiMap) super.delegate();
}
@Override
public Set values() {
synchronized (mutex) {
if (valueSet == null) {
valueSet = set(delegate().values(), mutex);
}
return valueSet;
}
}
@Override
@CheckForNull
public V forcePut(@ParametricNullness K key, @ParametricNullness V value) {
synchronized (mutex) {
return delegate().forcePut(key, value);
}
}
@Override
public BiMap inverse() {
synchronized (mutex) {
if (inverse == null) {
inverse = new SynchronizedBiMap<>(delegate().inverse(), mutex, this);
}
return inverse;
}
}
private static final long serialVersionUID = 0;
}
static final class SynchronizedAsMap
extends SynchronizedMap> {
@CheckForNull transient Set>> asMapEntrySet;
@CheckForNull transient Collection> asMapValues;
SynchronizedAsMap(Map> delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
@CheckForNull
public Collection get(@CheckForNull Object key) {
synchronized (mutex) {
Collection collection = super.get(key);
return (collection == null) ? null : typePreservingCollection(collection, mutex);
}
}
@Override
public Set>> entrySet() {
synchronized (mutex) {
if (asMapEntrySet == null) {
asMapEntrySet = new SynchronizedAsMapEntries<>(delegate().entrySet(), mutex);
}
return asMapEntrySet;
}
}
@Override
public Collection> values() {
synchronized (mutex) {
if (asMapValues == null) {
asMapValues = new SynchronizedAsMapValues(delegate().values(), mutex);
}
return asMapValues;
}
}
@Override
public boolean containsValue(@CheckForNull Object o) {
// values() and its contains() method are both synchronized.
return values().contains(o);
}
private static final long serialVersionUID = 0;
}
static final class SynchronizedAsMapValues
extends SynchronizedCollection> {
SynchronizedAsMapValues(Collection> delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
public Iterator> iterator() {
// Must be manually synchronized.
return new TransformedIterator, Collection>(super.iterator()) {
@Override
Collection transform(Collection from) {
return typePreservingCollection(from, mutex);
}
};
}
private static final long serialVersionUID = 0;
}
@GwtIncompatible // NavigableSet
@VisibleForTesting
static final class SynchronizedNavigableSet
extends SynchronizedSortedSet implements NavigableSet {
SynchronizedNavigableSet(NavigableSet delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
NavigableSet delegate() {
return (NavigableSet) super.delegate();
}
@Override
@CheckForNull
public E ceiling(E e) {
synchronized (mutex) {
return delegate().ceiling(e);
}
}
@Override
public Iterator descendingIterator() {
return delegate().descendingIterator(); // manually synchronized
}
@CheckForNull transient NavigableSet descendingSet;
@Override
public NavigableSet descendingSet() {
synchronized (mutex) {
if (descendingSet == null) {
NavigableSet dS = Synchronized.navigableSet(delegate().descendingSet(), mutex);
descendingSet = dS;
return dS;
}
return descendingSet;
}
}
@Override
@CheckForNull
public E floor(E e) {
synchronized (mutex) {
return delegate().floor(e);
}
}
@Override
public NavigableSet headSet(E toElement, boolean inclusive) {
synchronized (mutex) {
return Synchronized.navigableSet(delegate().headSet(toElement, inclusive), mutex);
}
}
@Override
public SortedSet headSet(E toElement) {
return headSet(toElement, false);
}
@Override
@CheckForNull
public E higher(E e) {
synchronized (mutex) {
return delegate().higher(e);
}
}
@Override
@CheckForNull
public E lower(E e) {
synchronized (mutex) {
return delegate().lower(e);
}
}
@Override
@CheckForNull
public E pollFirst() {
synchronized (mutex) {
return delegate().pollFirst();
}
}
@Override
@CheckForNull
public E pollLast() {
synchronized (mutex) {
return delegate().pollLast();
}
}
@Override
public NavigableSet subSet(
E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
synchronized (mutex) {
return Synchronized.navigableSet(
delegate().subSet(fromElement, fromInclusive, toElement, toInclusive), mutex);
}
}
@Override
public SortedSet subSet(E fromElement, E toElement) {
return subSet(fromElement, true, toElement, false);
}
@Override
public NavigableSet tailSet(E fromElement, boolean inclusive) {
synchronized (mutex) {
return Synchronized.navigableSet(delegate().tailSet(fromElement, inclusive), mutex);
}
}
@Override
public SortedSet tailSet(E fromElement) {
return tailSet(fromElement, true);
}
private static final long serialVersionUID = 0;
}
@GwtIncompatible // NavigableSet
static NavigableSet navigableSet(
NavigableSet navigableSet, @CheckForNull Object mutex) {
return new SynchronizedNavigableSet<>(navigableSet, mutex);
}
@GwtIncompatible // NavigableSet
static NavigableSet navigableSet(NavigableSet navigableSet) {
return navigableSet(navigableSet, null);
}
@GwtIncompatible // NavigableMap
static NavigableMap navigableMap(
NavigableMap navigableMap) {
return navigableMap(navigableMap, null);
}
@GwtIncompatible // NavigableMap
static NavigableMap navigableMap(
NavigableMap navigableMap, @CheckForNull Object mutex) {
return new SynchronizedNavigableMap<>(navigableMap, mutex);
}
@GwtIncompatible // NavigableMap
@VisibleForTesting
static final class SynchronizedNavigableMap<
K extends @Nullable Object, V extends @Nullable Object>
extends SynchronizedSortedMap implements NavigableMap {
SynchronizedNavigableMap(NavigableMap delegate, @CheckForNull Object mutex) {
super(delegate, mutex);
}
@Override
NavigableMap delegate() {
return (NavigableMap) super.delegate();
}
@Override
@CheckForNull
public Map.Entry ceilingEntry(K key) {
synchronized (mutex) {
return nullableSynchronizedEntry(delegate().ceilingEntry(key), mutex);
}
}
@Override
@CheckForNull
public K ceilingKey(K key) {
synchronized (mutex) {
return delegate().ceilingKey(key);
}
}
@CheckForNull transient NavigableSet descendingKeySet;
@Override
public NavigableSet descendingKeySet() {
synchronized (mutex) {
if (descendingKeySet == null) {
return descendingKeySet = Synchronized.navigableSet(delegate().descendingKeySet(), mutex);
}
return descendingKeySet;
}
}
@CheckForNull transient NavigableMap descendingMap;
@Override
public NavigableMap descendingMap() {
synchronized (mutex) {
if (descendingMap == null) {
return descendingMap = navigableMap(delegate().descendingMap(), mutex);
}
return descendingMap;
}
}
@Override
@CheckForNull
public Map.Entry firstEntry() {
synchronized (mutex) {
return nullableSynchronizedEntry(delegate().firstEntry(), mutex);
}
}
@Override
@CheckForNull
public Map.Entry floorEntry(K key) {
synchronized (mutex) {
return nullableSynchronizedEntry(delegate().floorEntry(key), mutex);
}
}
@Override
@CheckForNull
public K floorKey(K key) {
synchronized (mutex) {
return delegate().floorKey(key);
}
}
@Override
public NavigableMap headMap(K toKey, boolean inclusive) {
synchronized (mutex) {
return navigableMap(delegate().headMap(toKey, inclusive), mutex);
}
}
@Override
public SortedMap headMap(K toKey) {
return headMap(toKey, false);
}
@Override
@CheckForNull
public Map.Entry higherEntry(K key) {
synchronized (mutex) {
return nullableSynchronizedEntry(delegate().higherEntry(key), mutex);
}
}
@Override
@CheckForNull
public K higherKey(K key) {
synchronized (mutex) {
return delegate().higherKey(key);
}
}
@Override
@CheckForNull
public Map.Entry lastEntry() {
synchronized (mutex) {
return nullableSynchronizedEntry(delegate().lastEntry(), mutex);
}
}
@Override
@CheckForNull
public Map.Entry lowerEntry(K key) {
synchronized (mutex) {
return nullableSynchronizedEntry(delegate().lowerEntry(key), mutex);
}
}
@Override
@CheckForNull
public K lowerKey(K key) {
synchronized (mutex) {
return delegate().lowerKey(key);
}
}
@Override
public Set keySet() {
return navigableKeySet();
}
@CheckForNull transient NavigableSet navigableKeySet;
@Override
public NavigableSet navigableKeySet() {
synchronized (mutex) {
if (navigableKeySet == null) {
return navigableKeySet = Synchronized.navigableSet(delegate().navigableKeySet(), mutex);
}
return navigableKeySet;
}
}
@Override
@CheckForNull
public Map.Entry