package io.shockah.skylark.util;
import io.shockah.skylark.func.Action1;
import io.shockah.skylark.func.Action2;
import io.shockah.skylark.func.Action3;
import io.shockah.skylark.func.Func1;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteMap<K, V> implements Map<K, V> {
protected final Map<K, V> map;
protected final ReentrantReadWriteLock lock;
public ReadWriteMap(Map<K, V> underlyingMap) {
this(underlyingMap, true);
}
public ReadWriteMap(Map<K, V> underlyingMap, boolean fair) {
map = underlyingMap;
lock = new ReentrantReadWriteLock(fair);
}
public void readOperation(Action1<Map<K, V>> f) {
lock.readLock().lock();
try {
f.call(Collections.unmodifiableMap(map));
} finally {
lock.readLock().unlock();
}
}
public <R> R readOperation(Func1<Map<K, V>, R> f) {
lock.readLock().lock();
try {
return f.call(Collections.unmodifiableMap(map));
} finally {
lock.readLock().unlock();
}
}
public boolean tryReadOperation(long timeout, TimeUnit unit, Action1<Map<K, V>> f) throws InterruptedException {
if (lock.readLock().tryLock(timeout, unit)) {
try {
f.call(Collections.unmodifiableMap(map));
} finally {
lock.readLock().unlock();
}
return true;
}
return false;
}
public void writeOperation(Action1<Map<K, V>> f) {
lock.writeLock().lock();
try {
f.call(map);
} finally {
lock.writeLock().unlock();
}
}
public <R> R writeOperation(Func1<Map<K, V>, R> f) {
lock.writeLock().lock();
try {
return f.call(map);
} finally {
lock.writeLock().unlock();
}
}
public boolean tryWriteOperation(long timeout, TimeUnit unit, Action1<Map<K, V>> f) throws InterruptedException {
if (lock.writeLock().tryLock(timeout, unit)) {
try {
f.call(map);
} finally {
lock.writeLock().unlock();
}
return true;
}
return false;
}
public void iterate(Action2<K, V> f) {
lock.readLock().lock();
try {
for (Map.Entry<K, V> entry : map.entrySet()) {
f.call(entry.getKey(), entry.getValue());
}
} finally {
lock.readLock().unlock();
}
}
public void iterateKeys(Action1<K> f) {
lock.readLock().lock();
try {
for (Map.Entry<K, V> entry : map.entrySet()) {
f.call(entry.getKey());
}
} finally {
lock.readLock().unlock();
}
}
public void iterateValues(Action1<V> f) {
lock.readLock().lock();
try {
for (Map.Entry<K, V> entry : map.entrySet()) {
f.call(entry.getValue());
}
} finally {
lock.readLock().unlock();
}
}
public void iterate(Action3<K, V, ReadIterator<K, V>> f) {
lock.readLock().lock();
try {
new ReadIterator<K, V>(map.entrySet()).iterate(f);
} finally {
lock.readLock().unlock();
}
}
public V findOne(Func1<V, Boolean> f) {
lock.readLock().lock();
try {
for (V value : map.values()) {
if (f.call(value))
return value;
}
} finally {
lock.readLock().unlock();
}
return null;
}
public void iterateAndWrite(Action3<K, V, WriteIterator<K, V>> f) {
lock.writeLock().lock();
try {
new WriteIterator<K, V>(map.entrySet()).iterate(f);
} finally {
lock.writeLock().unlock();
}
}
@Override
public int size() {
lock.readLock().lock();
int ret = map.size();
lock.readLock().unlock();
return ret;
}
@Override
public boolean isEmpty() {
lock.readLock().lock();
boolean ret = map.isEmpty();
lock.readLock().unlock();
return ret;
}
@Override
public boolean containsKey(Object key) {
lock.readLock().lock();
boolean ret = map.containsKey(key);
lock.readLock().unlock();
return ret;
}
@Override
public boolean containsValue(Object value) {
lock.readLock().lock();
boolean ret = map.containsValue(value);
lock.readLock().unlock();
return ret;
}
@Override
public V get(Object key) {
lock.readLock().lock();
V ret = map.get(key);
lock.readLock().unlock();
return ret;
}
@Override
public V put(K key, V value) {
lock.writeLock().lock();
V ret = map.put(key, value);
lock.writeLock().unlock();
return ret;
}
@Override
public V remove(Object key) {
lock.writeLock().lock();
V ret = map.remove(key);
lock.writeLock().unlock();
return ret;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
lock.writeLock().lock();
map.putAll(m);
lock.writeLock().unlock();
}
@Override
public void clear() {
lock.writeLock().lock();
map.clear();
lock.writeLock().unlock();
}
@Override
public Set<K> keySet() {
throw new UnsupportedOperationException();
}
@Override
public Collection<V> values() {
throw new UnsupportedOperationException();
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
throw new UnsupportedOperationException();
}
public static class ReadIterator<K, V> {
protected final Set<Map.Entry<K, V>> set;
protected boolean shouldStop = false;
protected Map.Entry<K, V> currentEntry;
private ReadIterator(Set<Map.Entry<K, V>> set) {
this.set = set;
}
private void iterate(Action3<K, V, ReadIterator<K, V>> f) {
for (Map.Entry<K, V> entry : set) {
currentEntry = entry;
f.call(entry.getKey(), entry.getValue(), this);
if (shouldStop)
break;
}
}
public void stop() {
shouldStop = true;
}
}
public static class WriteIterator<K, V> extends ReadIterator<K, V> {
private WriteIterator(Set<Map.Entry<K, V>> set) {
super(set);
}
private void iterate(Action3<K, V, WriteIterator<K, V>> f) {
for (Map.Entry<K, V> entry : set) {
currentEntry = entry;
f.call(entry.getKey(), entry.getValue(), this);
if (shouldStop)
break;
}
}
public void set(V value) {
currentEntry.setValue(value);
}
}
}