diff options
Diffstat (limited to 'src/main/java/bjc/esodata')
| -rw-r--r-- | src/main/java/bjc/esodata/.AbbrevTree.java.un~ | bin | 0 -> 33807 bytes | |||
| -rw-r--r-- | src/main/java/bjc/esodata/AbbrevMap2.java | 2 | ||||
| -rw-r--r-- | src/main/java/bjc/esodata/AbbrevTree.java | 276 | ||||
| -rw-r--r-- | src/main/java/bjc/esodata/Multimap.java | 44 | ||||
| -rw-r--r-- | src/main/java/bjc/esodata/NestList.java | 3 | ||||
| -rw-r--r-- | src/main/java/bjc/esodata/Stack.java | 2 | ||||
| -rw-r--r-- | src/main/java/bjc/esodata/ThresholdSet.java | 74 | ||||
| -rw-r--r-- | src/main/java/bjc/esodata/spool/Spool.java | 5 | ||||
| -rw-r--r-- | src/main/java/bjc/esodata/spool/Spooler.java | 5 |
9 files changed, 375 insertions, 36 deletions
diff --git a/src/main/java/bjc/esodata/.AbbrevTree.java.un~ b/src/main/java/bjc/esodata/.AbbrevTree.java.un~ Binary files differnew file mode 100644 index 0000000..7c8a369 --- /dev/null +++ b/src/main/java/bjc/esodata/.AbbrevTree.java.un~ diff --git a/src/main/java/bjc/esodata/AbbrevMap2.java b/src/main/java/bjc/esodata/AbbrevMap2.java index 259c963..341a28d 100644 --- a/src/main/java/bjc/esodata/AbbrevMap2.java +++ b/src/main/java/bjc/esodata/AbbrevMap2.java @@ -41,7 +41,7 @@ public class AbbrevMap2 { } // Generate all of the strings a given word could be abbreviated as - private List<String> genAbbrevs(String word) { + private static List<String> genAbbrevs(String word) { List<String> retList = new ArrayList<>(); int len = word.length(); diff --git a/src/main/java/bjc/esodata/AbbrevTree.java b/src/main/java/bjc/esodata/AbbrevTree.java new file mode 100644 index 0000000..35c44f0 --- /dev/null +++ b/src/main/java/bjc/esodata/AbbrevTree.java @@ -0,0 +1,276 @@ +package bjc.esodata; + +import java.util.*; + +import bjc.data.Pair; +import bjc.data.TransformIterator; +import bjc.funcdata.FunctionalList; +import bjc.funcdata.ListEx; + +/** + * A labeled tree, where you can reference sub-nodes by their label as long as + * the reference is unambiguous. + * + * Inspired by the way that you can reference COBOL members by their name, as + * long as it is unambiguous. If it is ambiguous, you can instead use parent + * nodes to disambiguate. + * + * Additional note: The base iterator will give you all of the child nodes, but + * in no defined order. + * + * @param <Label> The label on each node + * @param <Contained> The type of data contained in the nodes. + */ +public class AbbrevTree<Label, Contained> implements Iterable<Pair<Label, Contained>> { + private Multimap<Label, AbbrevTree<Label, Contained>> labelledNodes; + + private Map<Label, AbbrevTree<Label, Contained>> children; + private AbbrevTree<Label, Contained> parent; + + private Contained data; + private Label label; + + /** + * Create a new empty root AbbrevTree. + */ + public AbbrevTree() { + labelledNodes = new Multimap<>(); + children = new HashMap<>(); + } + + /** + * Create a new occupied root AbbrevTree + * + * @param label The label for this tree + * @param data The data for this tree + */ + public AbbrevTree(Label label, Contained data) { + this(); + + this.label = label; + this.data = data; + } + + /** + * Create a new empty child AbbrevTree. + * + * @param parent The parent of this node + */ + public AbbrevTree(AbbrevTree<Label, Contained> parent) { + labelledNodes = new Multimap<>(); + children = new HashMap<>(); + + this.parent = parent; + } + + /** + * Create a new occupied child AbbrevTree + * + * @param parent The parent of this node + * @param label The label for this tree + * @param data The data for this tree + */ + public AbbrevTree(AbbrevTree<Label, Contained> parent, Label label, Contained data) { + this(); + + this.parent = parent; + this.label = label; + this.data = data; + + addFromChild(label, this); + } + + private void addFromChild(Label lbl, AbbrevTree<Label, Contained> node) { + labelledNodes.add(lbl, node); + + if (parent != null) + parent.addFromChild(lbl, node); + } + + /** + * Get the data contained in this node. + * + * @return The contained data. + */ + public Contained getData() { + return data; + } + + /** + * Set the data contained in this node. + * + * @param data The new data. + */ + public void setData(Contained data) { + this.data = data; + } + + /** + * Get the label for this node. + * + * @return The label for this node. + */ + public Label getLabel() { + return label; + } + + /* + * Unsupported for now. This requires some additional scaffolding. + * + * Set the label for this node. + * + * @param label The new label for this node. + */ + // public void setLabel(Label label) { + // this.label = label; + // } + + /** + * Add a child to this node + * + * @param key The label for the new node + * @param dat The data for the new node. + * + * @return The new node + */ + public AbbrevTree<Label, Contained> add(Label key, Contained dat) { + AbbrevTree<Label, Contained> node = new AbbrevTree<>(this, key, dat); + + children.put(key, node); + + return node; + } + + /** + * Remove a direct child from this node. + * + * @param key The label for this child. + * + * @return The removed child. + */ + public Optional<AbbrevTree<Label, Contained>> removeChild(Label key) { + Optional<AbbrevTree<Label, Contained>> res = Optional.ofNullable(children.remove(key)); + + res.ifPresent((node) -> { + node.parent = null; + node.labelledNodes.iterator().forEachRemaining((par) -> { + labelledNodes.remove(par.getLeft(), par.getRight()); + + parent.labelledNodes.remove(par.getLeft(), par.getRight()); + }); + }); + + return res; + } + + /** + * Retrieve a number of subnodes from this tree which correspond to the given + * keys. + * + * Note that the keys are passed in reverse order. Essentially, the first + * argument is the actual key, the remainder are just disambiguators + * + * @param keys The keys to look up. + * + * @return All of the nodes which match the given key pattern. + */ + public Set<AbbrevTree<Label, Contained>> nodes(@SuppressWarnings("unchecked") Label... keys) { + // Need this; Java can't deduce the proper type for reduceAux otherwise + Set<AbbrevTree<Label, Contained>> nodes = new HashSet<>(); + + ListEx<Label> keyList = new FunctionalList<>(keys); + + // COBOL keylists are in reverse order + keyList.reverse(); + + Label last = keyList.popLast(); + + List<AbbrevTree<Label, Contained>> focusList = List.of(this); + for (Label key : keyList) { + List<AbbrevTree<Label, Contained>> nextFocus = new ArrayList<>(); + + for (AbbrevTree<Label, Contained> focus : focusList) { + Set<AbbrevTree<Label, Contained>> focusSet = focus.labelledNodes.get(key); + nextFocus.addAll(focusSet); + } + + focusList = nextFocus; + } + + focusList.forEach((focus) -> { + nodes.addAll(focus.labelledNodes.get(last)); + }); + + if (label.equals(last)) + nodes.add(this); + + return nodes; + } + + /** + * Retrieve all of the values which correspond to a given key. + * + * + * Note that the keys are passed in reverse order. Essentially, the first + * argument is the actual key, the remainder are just disambiguators + * + * @param keys The keys to look up + * + * @return All of the values which correspond to the key + */ + public Set<Contained> values(@SuppressWarnings("unchecked") Label... keys) { + Set<Contained> res = new HashSet<>(); + + nodes(keys).forEach((node) -> res.add(node.data)); + + return res; + } + + /** + * Returns the singular value identified by the given keypath. + * + * Note that unlike {@link AbbrevTree#nodes(Object...)} and + * {@link AbbrevTree#values(Object...)}, the keys to this method are passed in + * the proper order, not reverse. + * + * @param keys The keypath to look up. + * + * @return An optional containing the identified element if there is one; + * otherwise, empty. + */ + public Optional<AbbrevTree<Label, Contained>> path(@SuppressWarnings("unchecked") Label... keys) { + Optional<AbbrevTree<Label, Contained>> focus = Optional.of(this); + + for (Label key : keys) { + focus.map((node) -> { + return node.children.get(key); + }); + } + + return focus; + } + + @Override + public Iterator<Pair<Label, Contained>> iterator() { + return new TransformIterator<>(labelledNodes.iterator(), + (node) -> node.mapRight(AbbrevTree<Label, Contained>::getData)); + } + + @Override + public int hashCode() { + return Objects.hash(children, data, label, parent); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AbbrevTree<?, ?> other = (AbbrevTree<?, ?>) obj; + return Objects.equals(children, other.children) && Objects.equals(data, other.data) + && Objects.equals(label, other.label); + } +} diff --git a/src/main/java/bjc/esodata/Multimap.java b/src/main/java/bjc/esodata/Multimap.java index fae872e..e18ed49 100644 --- a/src/main/java/bjc/esodata/Multimap.java +++ b/src/main/java/bjc/esodata/Multimap.java @@ -1,6 +1,9 @@ package bjc.esodata; import java.util.*; +import java.util.Map.Entry; + +import bjc.data.Pair; /** * A map that has support for multiple values for a given key. @@ -14,7 +17,7 @@ import java.util.*; * @param <KeyType> The type of keys in the map. * @param <ValueType> The type of values in the map. */ -public class Multimap<KeyType, ValueType> { +public class Multimap<KeyType, ValueType> implements Iterable<Pair<KeyType, ValueType>> { private Map<KeyType, ThresholdSet<ValueType>> backing; /** @@ -80,6 +83,17 @@ public class Multimap<KeyType, ValueType> { } /** + * Get the single value in the map, if there is one. + * @param key The key to look up + * @return An optional containing the key if it is there once, or empty if it is there either no or more than one times + */ + public Optional<ValueType> getSingle(KeyType key) { + Set<ValueType> set = get(key); + + if (set.size() == 1) return Optional.of(set.iterator().next()); + return Optional.empty(); + } + /** * Check if there is at least one value mapped to the given key. * * @param key @@ -108,4 +122,32 @@ public class Multimap<KeyType, ValueType> { return backing.get(key).contains(value) > 0; } + + @Override + public Iterator<Pair<KeyType, ValueType>> iterator() { + return new Iterator<>() { + private Iterator<Entry<KeyType, ThresholdSet<ValueType>>> mapIter = backing.entrySet().iterator(); + private KeyType currKey; + private Iterator<ValueType> setIter; + + @Override + public boolean hasNext() { + while (setIter == null || !setIter.hasNext()) { + if (!mapIter.hasNext()) return false; + Entry<KeyType,ThresholdSet<ValueType>> entry = mapIter.next(); + + currKey = entry.getKey(); + setIter = entry.getValue().setView().iterator(); + } + + return setIter.hasNext(); + } + + @Override + public Pair<KeyType, ValueType> next() { + if (setIter == null || !setIter.hasNext()) throw new NoSuchElementException(); + return Pair.pair(currKey, setIter.next()) ; + } + }; + } } diff --git a/src/main/java/bjc/esodata/NestList.java b/src/main/java/bjc/esodata/NestList.java index eccaf9d..9d9149c 100644 --- a/src/main/java/bjc/esodata/NestList.java +++ b/src/main/java/bjc/esodata/NestList.java @@ -351,8 +351,7 @@ public class NestList<Element> extends AbstractList<Either<Element, NestList<Ele return backing.get(index); } - @SuppressWarnings("unlikely-arg-type") - @Override + @Override public boolean remove(Object o) { return backing.remove(o); } diff --git a/src/main/java/bjc/esodata/Stack.java b/src/main/java/bjc/esodata/Stack.java index 360e57d..9dfee17 100644 --- a/src/main/java/bjc/esodata/Stack.java +++ b/src/main/java/bjc/esodata/Stack.java @@ -337,7 +337,7 @@ public abstract class Stack<T> { } /* - * Dataflow Combinators + * Data-flow Combinators */ /** diff --git a/src/main/java/bjc/esodata/ThresholdSet.java b/src/main/java/bjc/esodata/ThresholdSet.java index 9b8560b..c13bad3 100644 --- a/src/main/java/bjc/esodata/ThresholdSet.java +++ b/src/main/java/bjc/esodata/ThresholdSet.java @@ -2,6 +2,10 @@ package bjc.esodata; import java.util.*; +import bjc.data.Pair; +import bjc.data.SimplePair; +import bjc.data.TransformIterator; + /** * Represents a counted set, that overflows to a map. * @@ -17,12 +21,11 @@ import java.util.*; * The iterator that this type gives by default is an iterator over all of the * values in the set, not including any of those in the map. * - * @param <KeyType> - * The value being counted. + * @param <KeyType> The value being counted. * * @author Ben Culkin */ -public class ThresholdSet<KeyType> { +public class ThresholdSet<KeyType> implements Iterable<Pair<KeyType, Integer>> { // View of this class as a java.util.Set private class SetView extends AbstractSet<KeyType> { /* @@ -37,7 +40,8 @@ public class ThresholdSet<KeyType> { int ret = ThresholdSet.this.add(key); // No change to set contents - if (ret > 2) return false; + if (ret > 2) + return false; return true; } @@ -51,7 +55,8 @@ public class ThresholdSet<KeyType> { int ret = ThresholdSet.this.remove(k); // We removed the element. - if (ret == 0) return true; + if (ret == 0) + return true; return false; } @@ -65,7 +70,8 @@ public class ThresholdSet<KeyType> { int ret = ThresholdSet.this.contains(k); // The object is set-visible - if (ret == 1) return true; + if (ret == 1) + return true; return false; } @@ -101,15 +107,15 @@ public class ThresholdSet<KeyType> { /** * Add multiple keys at once to the map. * - * @param keys - * The keys to add. + * @param keys The keys to add. * * @return An array containing the results of adding the keys. */ public int[] addKeys(@SuppressWarnings("unchecked") KeyType... keys) { int[] ret = new int[keys.length]; - for (int i = 0; i < keys.length; i++) ret[i] = add(keys[i]); + for (int i = 0; i < keys.length; i++) + ret[i] = add(keys[i]); return ret; } @@ -117,11 +123,10 @@ public class ThresholdSet<KeyType> { /** * Add a key to the collection. * - * @param key - * The key to add to the collection. + * @param key The key to add to the collection. * * @return The number of times that key now exists in the collection. Should - * always be < 0. + * always be > 0. */ public int add(KeyType key) { if (keySet.contains(key)) { @@ -149,15 +154,15 @@ public class ThresholdSet<KeyType> { /** * Remove a bunch of keys from the collection. * - * @param keys - * The keys to remove from the collection. + * @param keys The keys to remove from the collection. * * @return The results from removing the keys. */ public int[] removeKeys(@SuppressWarnings("unchecked") KeyType... keys) { int[] ret = new int[keys.length]; - for (int i = 0; i < keys.length; i++) ret[i] = remove(keys[i]); + for (int i = 0; i < keys.length; i++) + ret[i] = remove(keys[i]); return ret; } @@ -165,8 +170,7 @@ public class ThresholdSet<KeyType> { /** * Remove a key from the collection. * - * @param key - * The key to remove from the collection. + * @param key The key to remove from the collection. * * @return The number of times that key now exists in the collection. Returns -1 * if that key wasn't in the collection beforehand. @@ -188,11 +192,11 @@ public class ThresholdSet<KeyType> { keySet.add(key); return 1; - } else { - keyMap.put(key, cnt); - - return cnt; } + + keyMap.put(key, cnt); + + return cnt; } else { // We don't know about that key return -1; @@ -202,15 +206,15 @@ public class ThresholdSet<KeyType> { /** * Get the number of times the set contains a set of given keys. * - * @param keys - * The keys to look for. + * @param keys The keys to look for. * * @return The containment counts for each key. */ public int[] containsKeys(@SuppressWarnings("unchecked") KeyType... keys) { int[] ret = new int[keys.length]; - for (int i = 0; i < keys.length; i++) ret[i] = contains(keys[i]); + for (int i = 0; i < keys.length; i++) + ret[i] = contains(keys[i]); return ret; } @@ -218,15 +222,17 @@ public class ThresholdSet<KeyType> { /** * Get the number of times the set contains a given key. * - * @param key - * The key to look for. + * @param key The key to look for. * * @return The number of times the key occurs; -1 if it doesn't occur. */ public int contains(KeyType key) { - if (keySet.contains(key)) return 1; - if (!keyMap.containsKey(key)) return -1; - else return keyMap.get(key); + if (keySet.contains(key)) + return 1; + if (!keyMap.containsKey(key)) + return -1; + + return keyMap.get(key); } /** @@ -252,12 +258,18 @@ public class ThresholdSet<KeyType> { return new SetView(); } + @Override + public Iterator<Pair<KeyType, Integer>> iterator() { + return new TransformIterator<>(keyMap.entrySet().iterator(), + (entry) -> new SimplePair<>(entry.getKey(), entry.getValue())); + } + /** * Static threshold set constructor. + * * @param <KType> The type of keys for the threshold set. * - * @param keys - * The initial keys to add to the threshold set. + * @param keys The initial keys to add to the threshold set. * @return A threshold set with the given keys. */ @SafeVarargs diff --git a/src/main/java/bjc/esodata/spool/Spool.java b/src/main/java/bjc/esodata/spool/Spool.java new file mode 100644 index 0000000..dbd2ce8 --- /dev/null +++ b/src/main/java/bjc/esodata/spool/Spool.java @@ -0,0 +1,5 @@ +package bjc.esodata.spool; + +public interface Spool<Contained> { + +} diff --git a/src/main/java/bjc/esodata/spool/Spooler.java b/src/main/java/bjc/esodata/spool/Spooler.java new file mode 100644 index 0000000..a222a25 --- /dev/null +++ b/src/main/java/bjc/esodata/spool/Spooler.java @@ -0,0 +1,5 @@ +package bjc.esodata.spool; + +public interface Spooler { + public <E> Spool<E> getSpool(); +} |
