public interface MapMethods<K,V,R>
default boolean containsKey(MapQueryContext<K,V,R> q)
Map.containsKey(Object)
method.
return q.entry() != null;
default void get(MapQueryContext<K,V,R> q, ReturnValue<V> returnValue)
ChronicleMap.get(java.lang.Object)
, ChronicleMap.getUsing(K, V)
and
ConcurrentMap.getOrDefault(java.lang.Object, V)
methods.
MapEntry<K, V> entry = q.entry();
if (entry != null)
returnValue.returnValue(entry.value());
default void put(MapQueryContext<K,V,R> q, Data<V> value, ReturnValue<V> returnValue)
Map.put(Object, Object)
method.
// We cannot read the previous value under read lock, because then we will need
// to release the read lock -> acquire write lock, the value might be updated in
// between, that will break ConcurrentMap.put() atomicity guarantee. So, we acquire
// update lock from the start:
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
q.replaceValue(entry, value);
} else {
q.insert(q.absentEntry(), value);
}
default void putIfAbsent(MapQueryContext<K,V,R> q, Data<V> value, ReturnValue<V> returnValue)
ConcurrentMap.putIfAbsent(Object, Object)
method.
if (q.readLock().tryLock()) {
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
return;
}
// Key is absent
q.readLock().unlock();
}
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
return;
}
// Key is absent
q.insert(q.absentEntry(), value);
default void acquireUsing(MapQueryContext<K,V,R> q, ReturnValue<V> returnValue)
ChronicleMap.acquireUsing(Object, Object)
method.
if (q.readLock().tryLock()) {
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
return;
}
// Key is absent
q.readLock().unlock();
}
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
return;
}
// Key is absent
q.insert(q.absentEntry(), q.defaultValue(q.absentEntry()));
// Meaningful to return the default as newly-inserted, not the default entry itself.
// map.acquireUsing() is most useful for value interfaces, for which it makes big
// difference -- what bytes to refer. Consider map.acquireUsing(...).incrementValue();
returnValue.returnValue(q.entry().value());
default void computeIfAbsent(MapQueryContext<K,V,R> q, Function<? super K,? extends V> mappingFunction, ReturnValue<V> returnValue)
ConcurrentMap.computeIfAbsent(Object, Function)
method.
if (q.readLock().tryLock()) {
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
return;
}
// Key is absent
q.readLock().unlock();
}
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
return;
}
// Key is absent
q.insert(q.absentEntry(), q.wrapValueAsData(mappingFunction.apply(q.queriedKey().get())));
returnValue.returnValue(q.entry().value());
default void remove(MapQueryContext<K,V,R> q, ReturnValue<V> returnValue)
Map.remove(Object)
method.
// We cannot read the previous value under read lock, because then we will need
// to release the read lock -> acquire write lock, the value might be updated in
// between, that will break ConcurrentMap.remove() atomicity guarantee. So, we acquire
// update lock from the start:
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
q.remove(entry);
}
default boolean remove(MapQueryContext<K,V,R> q, Data<V> value)
ConcurrentMap.remove(Object, Object)
method.
// remove(key, value) should find the entry & remove most of the time,
// so don't try to check key presence and value equivalence under read lock first,
// as in putIfAbsent()/acquireUsing(), start with update lock:
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null && Data.bytesEquivalent(entry.value(), value)) {
q.remove(entry);
return true;
} else {
return false;
}
default void replace(MapQueryContext<K,V,R> q, Data<V> value, ReturnValue<V> returnValue)
ConcurrentMap.replace(Object, Object)
method.
// replace(key, value) should find the key & put the value most of the time,
// so don't try to check key presence under read lock first,
// as in putIfAbsent()/acquireUsing(), start with update lock:
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null) {
returnValue.returnValue(entry.value());
q.replaceValue(entry, value);
}
default boolean replace(MapQueryContext<K,V,R> q, Data<V> oldValue, Data<V> newValue)
ConcurrentMap.replace(Object, Object, Object)
method.
// replace(key, old, new) should find the entry & put new value most of the time,
// so don't try to check key presence and value equivalence under read lock first,
// as in putIfAbsent()/acquireUsing(), start with update lock:
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null && Data.bytesEquivalent(((MapEntry<K, V>) entry).value(), oldValue)) {
q.replaceValue(entry, newValue);
return true;
} else {
return false;
}
default void compute(MapQueryContext<K,V,R> q, BiFunction<? super K,? super V,? extends V> remappingFunction, ReturnValue<V> returnValue)
ConcurrentMap.compute(Object, BiFunction)
method.
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
V oldValue = entry != null ? entry.value().get() : null;
V newValue = remappingFunction.apply(q.queriedKey().get(), oldValue);
if (newValue != null) {
Data<V, ?> newValueData = q.wrapValueAsData(newValue);
if (entry != null) {
q.replaceValue(entry, newValueData);
} else {
q.insert(q.absentEntry(), newValueData);
entry = q.entry();
}
returnValue.returnValue(entry.value());
} else if (entry != null) {
q.remove(entry);
}
default void computeIfPresent(MapQueryContext<K,V,R> q, BiFunction<? super K,? super V,? extends V> remappingFunction, ReturnValue<V> returnValue)
ConcurrentMap.computeIfPresent(Object, BiFunction)
method.
q.updateLock().lock();
MapEntry<K, V> entry = q.entry();
if (entry != null) {
V oldValue = entry.value().get();
V newValue = remappingFunction.apply(q.queriedKey().get(), oldValue);
if (newValue != null ) {
q.replaceValue(entry, q.wrapValueAsData(newValue));
returnValue.returnValue(q.entry().value());
} else {
q.remove(entry);
}
}
default void merge(MapQueryContext<K,V,R> q, Data<V> value, BiFunction<? super V,? super V,? extends V> remappingFunction, ReturnValue<V> returnValue)
ConcurrentMap.merge(Object, Object, BiFunction)
method.
q.updateLock().lock();
Data<V, ?> newValueData;
MapEntry<K, V> entry = q.entry();
if (entry != null) {
V oldValue = entry.value().get();
V newValue = remappingFunction.apply(oldValue, value.get());
if (newValue == null) {
q.remove(entry);
return;
}
newValueData = q.wrapValueAsData(newValue);
q.replaceValue(entry, newValueData);
} else {
newValueData = value;
q.insert(q.absentEntry(), newValueData);
entry = q.entry();
}
returnValue.returnValue(entry.value());
Copyright © 2022. All rights reserved.