|
|
@@ -9,10 +9,8 @@ package net.ranides.assira.collection.maps;
|
|
|
import java.io.Serializable;
|
|
|
import java.util.*;
|
|
|
import java.util.AbstractMap.SimpleEntry;
|
|
|
-import java.util.function.BiFunction;
|
|
|
-import java.util.function.Function;
|
|
|
-import java.util.function.Predicate;
|
|
|
-import java.util.function.Supplier;
|
|
|
+import java.util.function.*;
|
|
|
+import java.util.stream.Stream;
|
|
|
|
|
|
import net.ranides.assira.collection.ACollection;
|
|
|
import net.ranides.assira.collection.CollectionUtils;
|
|
|
@@ -74,6 +72,10 @@ public final class MapUtils {
|
|
|
return new ViewAdapter<>(map, keyMapper, valueMapper);
|
|
|
}
|
|
|
|
|
|
+ public static <K, V> MultiMap<K, V> synchronizedMultiMap(MultiMap<K, V> map) {
|
|
|
+ return new SynchronizedMultiMap<K, V>(map);
|
|
|
+ }
|
|
|
+
|
|
|
private static class ViewAdapter<TK, RK, TV, RV> extends AMap<RK, RV> {
|
|
|
|
|
|
private final Map<TK,? extends TV> content;
|
|
|
@@ -681,5 +683,386 @@ public final class MapUtils {
|
|
|
}
|
|
|
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ private static class SynchronizedMultiMap<K, V> implements MultiMap<K, V> {
|
|
|
+
|
|
|
+ private final Object mutex = new Object();
|
|
|
+
|
|
|
+ private final MultiMap<K, V> data;
|
|
|
+
|
|
|
+ private Set<K> keySet;
|
|
|
+ private Set<Map.Entry<K,V>> entrySet;
|
|
|
+ private Collection<V> values;
|
|
|
+
|
|
|
+ public SynchronizedMultiMap(MultiMap<K, V> data) {
|
|
|
+ this.data = data;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Collection<V> getAll(Object key) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return new SynchronizedCollection<>(mutex, data.getAll(key));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int size() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.size();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean isEmpty() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.isEmpty();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean containsKey(Object key) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.containsKey(key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean containsValue(Object value) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.containsValue(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V get(Object key) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.get(key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V put(K key, V value) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.put(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V remove(Object key) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.remove(key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void putAll(Map<? extends K, ? extends V> m) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ data.putAll(m);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void clear() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ data.clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<K> keySet() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ if(keySet == null) {
|
|
|
+ keySet = new SynchronizedSet<>(mutex, data.keySet());
|
|
|
+ }
|
|
|
+ return keySet;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Collection<V> values() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ if(values == null) {
|
|
|
+ values = new SynchronizedCollection<>(mutex, data.values());
|
|
|
+ }
|
|
|
+ return values;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<Entry<K, V>> entrySet() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ if(entrySet == null) {
|
|
|
+ entrySet = new SynchronizedSet<>(mutex, data.entrySet());
|
|
|
+ }
|
|
|
+ return entrySet;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V get(Object key, BinaryOperator<V> fold) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.get(key, fold);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean containsEntry(Object key, Object value) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.containsEntry(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void putAll(K key, Iterable<? extends V> values) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ data.putAll(key, values);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V replace(K key, V value) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.replace(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Collection<V> replaceAll(K key, Collection<V> values) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.replaceAll(key, values);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean remove(Object key, Object value) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.remove(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Collection<V> removeAll(Object key) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.removeAll(key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<K> uniqueKeySet() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.uniqueKeySet();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V getOrDefault(Object key, V defaultValue) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.getOrDefault(key, defaultValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void forEach(BiConsumer<? super K, ? super V> action) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ data.forEach(action);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ data.replaceAll(function);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V putIfAbsent(K key, V value) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.putIfAbsent(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean replace(K key, V oldValue, V newValue) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.replace(key, oldValue, newValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.computeIfAbsent(key, mappingFunction);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.computeIfPresent(key, remappingFunction);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.compute(key, remappingFunction);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return data.merge(key, value, remappingFunction);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ static class SynchronizedCollection<E> implements Collection<E> {
|
|
|
+
|
|
|
+ final Collection<E> c;
|
|
|
+
|
|
|
+ final Object mutex;
|
|
|
+
|
|
|
+ SynchronizedCollection(Object mutex, Collection<E> c) {
|
|
|
+ this.c = Objects.requireNonNull(c);
|
|
|
+ this.mutex = Objects.requireNonNull(mutex);
|
|
|
+ }
|
|
|
+
|
|
|
+ public int size() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.size();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean isEmpty() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.isEmpty();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean contains(Object o) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.contains(o);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Object[] toArray() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.toArray();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public <T> T[] toArray(T[] a) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.toArray(a);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public Iterator<E> iterator() {
|
|
|
+ return c.iterator(); // Must be manually synched by user!
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean add(E e) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.add(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean remove(Object o) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.remove(o);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean containsAll(Collection<?> coll) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.containsAll(coll);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean addAll(Collection<? extends E> coll) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.addAll(coll);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean removeAll(Collection<?> coll) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.removeAll(coll);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean retainAll(Collection<?> coll) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.retainAll(coll);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void clear() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ c.clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public String toString() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.toString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void forEach(Consumer<? super E> consumer) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ c.forEach(consumer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean removeIf(Predicate<? super E> filter) {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.removeIf(filter);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Spliterator<E> spliterator() {
|
|
|
+ return c.spliterator(); // Must be manually synched by user!
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Stream<E> stream() {
|
|
|
+ return c.stream(); // Must be manually synched by user!
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Stream<E> parallelStream() {
|
|
|
+ return c.parallelStream(); // Must be manually synched by user!
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ static class SynchronizedSet<E> extends SynchronizedCollection<E> implements Set<E> {
|
|
|
+
|
|
|
+ SynchronizedSet(Object mutex, Set<E> s) {
|
|
|
+ super(mutex, s);
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean equals(Object o) {
|
|
|
+ if (this == o) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.equals(o);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public int hashCode() {
|
|
|
+ synchronized (mutex) {
|
|
|
+ return c.hashCode();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|