summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Culkin <scorpress@gmail.com>2020-11-17 17:44:05 -0500
committerBen Culkin <scorpress@gmail.com>2020-11-17 17:44:05 -0500
commit213171f95845ebc5efcfa73d1cab4b723ff2abf2 (patch)
treee0c167842d8923e5a0235a9e64fc0d7fe7201cf8
parent38e97f991ee69afd53f36fd7296b4afd5a621311 (diff)
Implement IFreezable for IMap
-rw-r--r--src/main/java/bjc/esodata/PushdownMap.java77
-rw-r--r--src/main/java/bjc/funcdata/ExtendedMap.java125
-rw-r--r--src/main/java/bjc/funcdata/FunctionalMap.java108
-rw-r--r--src/main/java/bjc/funcdata/IMap.java24
-rw-r--r--src/main/java/bjc/funcdata/TransformedValueMap.java63
5 files changed, 253 insertions, 144 deletions
diff --git a/src/main/java/bjc/esodata/PushdownMap.java b/src/main/java/bjc/esodata/PushdownMap.java
index a10c149..456d33b 100644
--- a/src/main/java/bjc/esodata/PushdownMap.java
+++ b/src/main/java/bjc/esodata/PushdownMap.java
@@ -1,12 +1,8 @@
package bjc.esodata;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.function.*;
-import bjc.funcdata.FunctionalMap;
-import bjc.funcdata.IList;
-import bjc.funcdata.IMap;
+import bjc.funcdata.*;
/**
* A variant of a map where inserting a duplicate key shadows the existing value
@@ -26,18 +22,18 @@ public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType>
/* Our backing storage. */
private final IMap<KeyType, Stack<ValueType>> backing;
+ private boolean isFrozen = false;
+ private boolean thawEnabled = true;
+
/** Create a new empty stack-based map. */
public PushdownMap() {
backing = new FunctionalMap<>();
}
- /** Create a new empty stack-based map using the specified backing. */
- private PushdownMap(final IMap<KeyType, Stack<ValueType>> back) {
- backing = back;
- }
-
@Override
public void clear() {
+ if (isFrozen) throw new ObjectFrozen("Can't clear frozen map");
+
backing.clear();
}
@@ -45,12 +41,7 @@ public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType>
public boolean containsKey(final KeyType key) {
return backing.containsKey(key);
}
-
- @Override
- public IMap<KeyType, ValueType> extend() {
- return new PushdownMap<>(backing.extend());
- }
-
+
@Override
public void forEach(final BiConsumer<KeyType, ValueType> action) {
backing.forEach((key, stk) -> action.accept(key, stk.top()));
@@ -82,16 +73,9 @@ public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType>
}
@Override
- public <V2> IMap<KeyType, V2> transform(final Function<ValueType, V2> transformer) {
- /*
- * @NOTE Can and should we support this? More to the point, maybe this should be
- * a map sub-type that does what it needs to?
- */
- throw new UnsupportedOperationException("Cannot transform pushdown maps.");
- }
-
- @Override
public ValueType put(final KeyType key, final ValueType val) {
+ if (isFrozen) throw new ObjectFrozen("Can't insert key " + key + " into frozen map");
+
if (backing.containsKey(key)) {
final Stack<ValueType> stk = backing.get(key);
@@ -111,6 +95,8 @@ public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType>
@Override
public ValueType remove(final KeyType key) {
+ if (isFrozen) throw new ObjectFrozen("Can't remove key " + key + " from frozen map");
+
final Stack<ValueType> stk = backing.get(key);
if (stk.size() > 1) return stk.pop();
@@ -154,4 +140,43 @@ public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType>
public String toString() {
return String.format("PushdownMap [backing=%s]", backing);
}
+
+ @Override
+ public boolean freeze() {
+ isFrozen = true;
+
+ return true;
+ }
+
+ @Override
+ public boolean thaw() {
+ if (thawEnabled) {
+ isFrozen = false;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean deepFreeze() {
+ thawEnabled = true;
+
+ return freeze();
+ }
+
+ @Override
+ public boolean canFreeze() {
+ return true;
+ }
+
+ @Override
+ public boolean canThaw() {
+ return thawEnabled;
+ }
+
+ @Override
+ public boolean isFrozen() {
+ return isFrozen;
+ }
}
diff --git a/src/main/java/bjc/funcdata/ExtendedMap.java b/src/main/java/bjc/funcdata/ExtendedMap.java
index bd500f4..19e3b4e 100644
--- a/src/main/java/bjc/funcdata/ExtendedMap.java
+++ b/src/main/java/bjc/funcdata/ExtendedMap.java
@@ -1,8 +1,7 @@
package bjc.funcdata;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.*;
+import java.util.function.*;
/**
* An extended version of a map, that stores values into a map, but can look
@@ -22,6 +21,9 @@ class ExtendedMap<KeyType, ValueType> implements IMap<KeyType, ValueType> {
/* The map we store things in. */
private final IMap<KeyType, ValueType> store;
+ private boolean isFrozen = false;
+ private boolean thawEnabled = true;
+
/**
* Create a new extended map.
*
@@ -39,20 +41,15 @@ class ExtendedMap<KeyType, ValueType> implements IMap<KeyType, ValueType> {
@Override
public void clear() {
+ if (isFrozen) return;
+
store.clear();
}
@Override
public boolean containsKey(final KeyType key) {
- if (store.containsKey(key))
- return true;
-
- return delegate.containsKey(key);
- }
-
- @Override
- public IMap<KeyType, ValueType> extend() {
- return new ExtendedMap<>(this, new FunctionalMap<>());
+ if (store.containsKey(key)) return true;
+ else return delegate.containsKey(key);
}
@Override
@@ -78,10 +75,8 @@ class ExtendedMap<KeyType, ValueType> implements IMap<KeyType, ValueType> {
@Override
public ValueType get(final KeyType key) {
- if (store.containsKey(key))
- return store.get(key);
-
- return delegate.get(key);
+ if (store.containsKey(key)) return store.get(key);
+ else return delegate.get(key);
}
@Override
@@ -100,22 +95,20 @@ class ExtendedMap<KeyType, ValueType> implements IMap<KeyType, ValueType> {
}
@Override
- public <MappedValue> IMap<KeyType, MappedValue>
- transform(final Function<ValueType, MappedValue> transformer) {
- return new TransformedValueMap<>(this, transformer);
- }
-
- @Override
public ValueType put(final KeyType key, final ValueType val) {
+ if (isFrozen)
+ throw new ObjectFrozen("Can't insert key " + key + " into frozen map");
+
return store.put(key, val);
}
@Override
public ValueType remove(final KeyType key) {
- if (!store.containsKey(key))
- return delegate.remove(key);
-
- return store.remove(key);
+ if (isFrozen)
+ throw new ObjectFrozen("Can't remove key " + key + " from frozen map");
+
+ if (!store.containsKey(key)) return delegate.remove(key);
+ else return store.remove(key);
}
@Override
@@ -127,43 +120,69 @@ class ExtendedMap<KeyType, ValueType> implements IMap<KeyType, ValueType> {
return ilst;
}
-
+
@Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + (delegate == null ? 0 : delegate.hashCode());
- result = prime * result + (store == null ? 0 : store.hashCode());
- return result;
+ public int hashCode() {
+ // isFrozen isn't counted
+ return Objects.hash(delegate, store);
+ }
+
+ /* Misc. object support. */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+
+ ExtendedMap<?, ?> other = (ExtendedMap<?, ?>) obj;
+
+ // isFrozen isn't counted
+ return Objects.equals(delegate, other.delegate) && Objects.equals(store, other.store);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ExtendedMap [delegate=%s, store=%s]", delegate, store);
}
+ /* IFreezable support */
+
@Override
- public boolean equals(final Object obj) {
- if (this == obj)
+ public boolean freeze() {
+ isFrozen = true;
+
return true;
- if (obj == null)
- return false;
- if (!(obj instanceof ExtendedMap))
- return false;
+ }
- final ExtendedMap<?, ?> other = (ExtendedMap<?, ?>) obj;
+ @Override
+ public boolean deepFreeze() {
+ thawEnabled = false;
- if (delegate == null) {
- if (other.delegate != null)
- return false;
- } else if (!delegate.equals(other.delegate))
- return false;
- if (store == null) {
- if (other.store != null)
- return false;
- } else if (!store.equals(other.store))
+ return freeze();
+ }
+
+ @Override
+ public boolean thaw() {
+ if (thawEnabled) {
+ isFrozen = false;
+ return true;
+ } else {
return false;
+ }
+ }
+ @Override
+ public boolean isFrozen() {
+ return isFrozen;
+ }
+
+ @Override
+ public boolean canFreeze() {
return true;
}
-
+
@Override
- public String toString() {
- return String.format("ExtendedMap [delegate=%s, store=%s]", delegate, store);
+ public boolean canThaw() {
+ return thawEnabled;
}
-}
+} \ No newline at end of file
diff --git a/src/main/java/bjc/funcdata/FunctionalMap.java b/src/main/java/bjc/funcdata/FunctionalMap.java
index aba3dd1..c088ff3 100644
--- a/src/main/java/bjc/funcdata/FunctionalMap.java
+++ b/src/main/java/bjc/funcdata/FunctionalMap.java
@@ -1,12 +1,9 @@
package bjc.funcdata;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.*;
+import java.util.function.*;
-import bjc.data.IPair;
+import bjc.data.*;
/**
* Basic implementation of {@link IMap}
@@ -23,6 +20,9 @@ public class FunctionalMap<KeyType, ValueType> implements IMap<KeyType, ValueTyp
/* Our backing store. */
private Map<KeyType, ValueType> wrappedMap;
+ private boolean isFrozen = false;
+ private boolean thawEnabled = true;
+
/** Create a new blank functional map */
public FunctionalMap() {
wrappedMap = new HashMap<>();
@@ -39,9 +39,7 @@ public class FunctionalMap<KeyType, ValueType> implements IMap<KeyType, ValueTyp
this();
for (final IPair<KeyType, ValueType> entry : entries) {
- entry.doWith((key, val) -> {
- wrappedMap.put(key, val);
- });
+ entry.doWith(wrappedMap::put);
}
}
@@ -52,14 +50,15 @@ public class FunctionalMap<KeyType, ValueType> implements IMap<KeyType, ValueTyp
* The map to wrap.
*/
public FunctionalMap(final Map<KeyType, ValueType> wrap) {
- if (wrap == null)
- throw new NullPointerException("Map to wrap must not be null");
+ if (wrap == null) throw new NullPointerException("Map to wrap must not be null");
wrappedMap = wrap;
}
@Override
public void clear() {
+ if (isFrozen) throw new ObjectFrozen("Can't clear frozen map");
+
wrappedMap.clear();
}
@@ -69,11 +68,6 @@ public class FunctionalMap<KeyType, ValueType> implements IMap<KeyType, ValueTyp
}
@Override
- public IMap<KeyType, ValueType> extend() {
- return new ExtendedMap<>(this, new FunctionalMap<>());
- }
-
- @Override
public void forEach(final BiConsumer<KeyType, ValueType> action) {
wrappedMap.forEach(action);
}
@@ -90,8 +84,7 @@ public class FunctionalMap<KeyType, ValueType> implements IMap<KeyType, ValueTyp
@Override
public ValueType get(final KeyType key) {
- if (key == null)
- throw new NullPointerException("Key must not be null");
+ if (key == null) throw new NullPointerException("Key must not be null");
if (!wrappedMap.containsKey(key)) {
final String msg = String.format("Key %s is not present in the map", key);
@@ -111,32 +104,23 @@ public class FunctionalMap<KeyType, ValueType> implements IMap<KeyType, ValueTyp
public IList<KeyType> keyList() {
final FunctionalList<KeyType> keys = new FunctionalList<>();
- wrappedMap.keySet().forEach(key -> {
- keys.add(key);
- });
+ wrappedMap.keySet().forEach(keys::add);
return keys;
}
@Override
- public <MappedValue> IMap<KeyType, MappedValue>
- transform(final Function<ValueType, MappedValue> transformer) {
- if (transformer == null)
- throw new NullPointerException("Transformer must not be null");
-
- return new TransformedValueMap<>(this, transformer);
- }
-
- @Override
public ValueType put(final KeyType key, final ValueType val) {
- if (key == null)
- throw new NullPointerException("Key must not be null");
+ if (isFrozen) throw new ObjectFrozen("Can't put key " + key + " into frozen map");
+ if (key == null) throw new NullPointerException("Key must not be null");
return wrappedMap.put(key, val);
}
@Override
public ValueType remove(final KeyType key) {
+ if (isFrozen) throw new ObjectFrozen("Can't remove key " + key + " from frozen map");
+
return wrappedMap.remove(key);
}
@@ -149,9 +133,7 @@ public class FunctionalMap<KeyType, ValueType> implements IMap<KeyType, ValueTyp
public IList<ValueType> valueList() {
final FunctionalList<ValueType> values = new FunctionalList<>();
- wrappedMap.values().forEach(value -> {
- values.add(value);
- });
+ wrappedMap.values().forEach(values::add);
return values;
}
@@ -166,20 +148,58 @@ public class FunctionalMap<KeyType, ValueType> implements IMap<KeyType, ValueTyp
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof FunctionalMap))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof FunctionalMap)) return false;
final FunctionalMap<?, ?> other = (FunctionalMap<?, ?>) obj;
if (wrappedMap == null) {
- if (other.wrappedMap != null)
- return false;
- } else if (!wrappedMap.equals(other.wrappedMap))
+ if (other.wrappedMap != null) return false;
+ } else if (!wrappedMap.equals(other.wrappedMap)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // IFreezable support
+ @Override
+ public boolean freeze() {
+ isFrozen = true;
+
+ return true;
+ }
+
+ @Override
+ public boolean thaw() {
+ if (thawEnabled) {
+ isFrozen = false;
+ return true;
+ } else {
return false;
+ }
+ }
+
+ @Override
+ public boolean deepFreeze() {
+ thawEnabled = false;
+
+ return freeze();
+ }
+
+ @Override
+ public boolean canFreeze() {
return true;
}
+
+ @Override
+ public boolean canThaw() {
+ return thawEnabled;
+ }
+
+ @Override
+ public boolean isFrozen() {
+ return isFrozen;
+ }
}
diff --git a/src/main/java/bjc/funcdata/IMap.java b/src/main/java/bjc/funcdata/IMap.java
index dc5ee00..e723507 100644
--- a/src/main/java/bjc/funcdata/IMap.java
+++ b/src/main/java/bjc/funcdata/IMap.java
@@ -1,8 +1,6 @@
package bjc.funcdata;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.function.*;
/**
* Functional wrapper over map providing some useful things.
@@ -15,7 +13,7 @@ import java.util.function.Function;
* @param <ValueType>
* The type of this map's values.
*/
-public interface IMap<KeyType, ValueType> {
+public interface IMap<KeyType, ValueType> extends IFreezable {
/**
* Execute an action for each entry in the map.
*
@@ -109,7 +107,7 @@ public interface IMap<KeyType, ValueType> {
/** Delete all the values in the map. */
default void clear() {
- keyList().forEach(key -> remove(key));
+ keyList().forEach(IMap.this::remove);
}
/**
@@ -151,7 +149,21 @@ public interface IMap<KeyType, ValueType> {
*
* @return An extended map.
*/
- IMap<KeyType, ValueType> extend();
+ default IMap<KeyType, ValueType> extend() {
+ return extend(new FunctionalMap<>());
+ };
+
+ /**
+ * Extends this map, creating a new map that will delegate queries to this map,
+ * but store any added values in the provided map.
+ *
+ * @param backer The map to store added values in.
+ *
+ * @return An extended map.
+ */
+ default IMap<KeyType, ValueType> extend(IMap<KeyType, ValueType> backer) {
+ return new ExtendedMap<>(this, backer);
+ };
/**
* Remove the value bound to the key.
diff --git a/src/main/java/bjc/funcdata/TransformedValueMap.java b/src/main/java/bjc/funcdata/TransformedValueMap.java
index 5de6fc3..e51c9eb 100644
--- a/src/main/java/bjc/funcdata/TransformedValueMap.java
+++ b/src/main/java/bjc/funcdata/TransformedValueMap.java
@@ -1,8 +1,6 @@
package bjc.funcdata;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.function.*;
/**
* A map that transforms values from one type to another
@@ -26,6 +24,9 @@ final class TransformedValueMap<OldKey, OldValue, NewValue>
/* Our transforming function. */
private final Function<OldValue, NewValue> transformer;
+ private boolean isFrozen = false;
+ private boolean thawEnabled = true;
+
/**
* Create a new transformed-value loop.
*
@@ -43,6 +44,8 @@ final class TransformedValueMap<OldKey, OldValue, NewValue>
@Override
public void clear() {
+ if (isFrozen) throw new ObjectFrozen("Can't clear frozen map");
+
backing.clear();
}
@@ -52,11 +55,6 @@ final class TransformedValueMap<OldKey, OldValue, NewValue>
}
@Override
- public IMap<OldKey, NewValue> extend() {
- return new ExtendedMap<>(this, new FunctionalMap<>());
- }
-
- @Override
public void forEach(final BiConsumer<OldKey, NewValue> action) {
backing.forEach((key, value) -> {
action.accept(key, transformer.apply(value));
@@ -91,18 +89,14 @@ final class TransformedValueMap<OldKey, OldValue, NewValue>
}
@Override
- public <MappedValue> IMap<OldKey, MappedValue>
- transform(final Function<NewValue, MappedValue> transform) {
- return new TransformedValueMap<>(this, transform);
- }
-
- @Override
public NewValue put(final OldKey key, final NewValue value) {
throw new UnsupportedOperationException("Can't add items to transformed map");
}
@Override
public NewValue remove(final OldKey key) {
+ if (isFrozen) throw new ObjectFrozen("Can't remove key " + key + " from frozen map");
+
return transformer.apply(backing.remove(key));
}
@@ -115,4 +109,43 @@ final class TransformedValueMap<OldKey, OldValue, NewValue>
public IList<NewValue> valueList() {
return backing.valueList().map(transformer);
}
-}
+
+ @Override
+ public boolean freeze() {
+ isFrozen = true;
+
+ return true;
+ }
+
+ @Override
+ public boolean thaw() {
+ if (thawEnabled) {
+ isFrozen = false;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean deepFreeze() {
+ thawEnabled = false;
+
+ return freeze();
+ }
+
+ @Override
+ public boolean canFreeze() {
+ return true;
+ }
+
+ @Override
+ public boolean canThaw() {
+ return thawEnabled;
+ }
+
+ @Override
+ public boolean isFrozen() {
+ return isFrozen;
+ }
+} \ No newline at end of file