|
|
@@ -0,0 +1,211 @@
|
|
|
+/*
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
+ * @license WTFPL
|
|
|
+ * @url http://ranides.net/projects/assira
|
|
|
+ */
|
|
|
+package net.ranides.assira.collections.map;
|
|
|
+
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.ConcurrentModificationException;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Map.Entry;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.function.BiConsumer;
|
|
|
+import java.util.function.BiFunction;
|
|
|
+import java.util.function.Function;
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ * @author msieron
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+public interface GenericMap<K> {
|
|
|
+
|
|
|
+ int size();
|
|
|
+
|
|
|
+ boolean isEmpty();
|
|
|
+
|
|
|
+ boolean containsKey(GenericKey<K,?> key);
|
|
|
+
|
|
|
+ boolean containsValue(Object value);
|
|
|
+
|
|
|
+ <V> V get(GenericKey<K,V> key);
|
|
|
+
|
|
|
+ <V> V put(GenericKey<K,V> key, V value);
|
|
|
+
|
|
|
+ <V> V remove(GenericKey<K,V> key);
|
|
|
+
|
|
|
+
|
|
|
+ void putAll(GenericMap<? extends K> m);
|
|
|
+
|
|
|
+ void clear();
|
|
|
+
|
|
|
+ Set<GenericKey<K,?>> keySet();
|
|
|
+
|
|
|
+ Collection<?> values();
|
|
|
+
|
|
|
+ Set<Map.Entry<GenericKey<K,?>, ?>> entrySet();
|
|
|
+
|
|
|
+ boolean equals(Object o);
|
|
|
+
|
|
|
+ int hashCode();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ default <V> V getOrDefault(GenericKey<K,V> key, V defaultValue) {
|
|
|
+ V v;
|
|
|
+ return (((v = get(key)) != null) || containsKey(key)) ? v : defaultValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ default void forEach(BiConsumer<? super GenericKey<K,?>, Object> action) {
|
|
|
+ Objects.requireNonNull(action);
|
|
|
+ for (Map.Entry<GenericKey<K,?>, ?> entry : entrySet()) {
|
|
|
+ GenericKey<K,?> k;
|
|
|
+ Object v;
|
|
|
+ try {
|
|
|
+ k = entry.getKey();
|
|
|
+ v = entry.getValue();
|
|
|
+ } catch(IllegalStateException ise) {
|
|
|
+ // this usually means the entry is no longer in the map.
|
|
|
+ throw new ConcurrentModificationException(ise);
|
|
|
+ }
|
|
|
+ action.accept(k, v);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ default void replaceAll(BiFunction<? super GenericKey<K,?>, Object, Object> function) {
|
|
|
+ Objects.requireNonNull(function);
|
|
|
+ for (Map.Entry<GenericKey<K,?>, ?> entry : entrySet()) {
|
|
|
+ GenericKey<K,?> k;
|
|
|
+ Object v;
|
|
|
+ try {
|
|
|
+ k = entry.getKey();
|
|
|
+ v = entry.getValue();
|
|
|
+ } catch(IllegalStateException ise) {
|
|
|
+ // this usually means the entry is no longer in the map.
|
|
|
+ throw new ConcurrentModificationException(ise);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ise thrown from function is not a cme.
|
|
|
+ v = function.apply(k, v);
|
|
|
+
|
|
|
+ try {
|
|
|
+ ((Entry)entry).setValue(v);
|
|
|
+ } catch(IllegalStateException ise) {
|
|
|
+ // this usually means the entry is no longer in the map.
|
|
|
+ throw new ConcurrentModificationException(ise);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ default <V> V putIfAbsent(GenericKey<K,V> key, V value) {
|
|
|
+ V v = get(key);
|
|
|
+ if (v == null) {
|
|
|
+ v = put(key, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ return v;
|
|
|
+ }
|
|
|
+
|
|
|
+ default <V> boolean remove(GenericKey<K,V> key, V value) {
|
|
|
+ Object curValue = get(key);
|
|
|
+ if (!Objects.equals(curValue, value) ||
|
|
|
+ (curValue == null && !containsKey(key))) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ remove(key);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ default <V> boolean replace(GenericKey<K,V> key, V oldValue, V newValue) {
|
|
|
+ Object curValue = get(key);
|
|
|
+ if (!Objects.equals(curValue, oldValue) ||
|
|
|
+ (curValue == null && !containsKey(key))) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ put(key, newValue);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ default <V> V replace(GenericKey<K,V> key, V value) {
|
|
|
+ V curValue;
|
|
|
+ if (((curValue = get(key)) != null) || containsKey(key)) {
|
|
|
+ curValue = put(key, value);
|
|
|
+ }
|
|
|
+ return curValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ default <V> V computeIfAbsent(GenericKey<K,V> key,
|
|
|
+ Function<? super GenericKey<K,V>, ? extends V> mappingFunction) {
|
|
|
+ Objects.requireNonNull(mappingFunction);
|
|
|
+ V v;
|
|
|
+ if ((v = get(key)) == null) {
|
|
|
+ V newValue;
|
|
|
+ if ((newValue = mappingFunction.apply(key)) != null) {
|
|
|
+ put(key, newValue);
|
|
|
+ return newValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return v;
|
|
|
+ }
|
|
|
+
|
|
|
+ default <V> V computeIfPresent(GenericKey<K,V> key,
|
|
|
+ BiFunction<? super GenericKey<K,?>, ? super V, ? extends V> remappingFunction) {
|
|
|
+ Objects.requireNonNull(remappingFunction);
|
|
|
+ V oldValue;
|
|
|
+ if ((oldValue = get(key)) != null) {
|
|
|
+ V newValue = remappingFunction.apply(key, oldValue);
|
|
|
+ if (newValue != null) {
|
|
|
+ put(key, newValue);
|
|
|
+ return newValue;
|
|
|
+ } else {
|
|
|
+ remove(key);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ default <V> V compute(GenericKey<K,V> key,
|
|
|
+ BiFunction<? super GenericKey<K,V>, ? super V, ? extends V> remappingFunction) {
|
|
|
+ Objects.requireNonNull(remappingFunction);
|
|
|
+ V oldValue = get(key);
|
|
|
+
|
|
|
+ V newValue = remappingFunction.apply(key, oldValue);
|
|
|
+ if (newValue == null) {
|
|
|
+ // delete mapping
|
|
|
+ if (oldValue != null || containsKey(key)) {
|
|
|
+ // something to remove
|
|
|
+ remove(key);
|
|
|
+ return null;
|
|
|
+ } else {
|
|
|
+ // nothing to do. Leave things as they were.
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // add or replace old mapping
|
|
|
+ put(key, newValue);
|
|
|
+ return newValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ default <V> V merge(GenericKey<K,V> key, V value,
|
|
|
+ BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
|
|
+ Objects.requireNonNull(remappingFunction);
|
|
|
+ Objects.requireNonNull(value);
|
|
|
+ V oldValue = get(key);
|
|
|
+ V newValue = (oldValue == null) ? value :
|
|
|
+ remappingFunction.apply(oldValue, value);
|
|
|
+ if(newValue == null) {
|
|
|
+ remove(key);
|
|
|
+ } else {
|
|
|
+ put(key, newValue);
|
|
|
+ }
|
|
|
+ return newValue;
|
|
|
+ }
|
|
|
+}
|