summaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/bjc/data/Contexts.java96
-rw-r--r--src/main/java/bjc/data/GeneratingIterator.java2
-rw-r--r--src/main/java/bjc/data/MarkListIterator.java175
-rw-r--r--src/main/java/bjc/data/Multimap.java16
-rw-r--r--src/main/java/bjc/data/Pair.java14
-rw-r--r--src/main/java/bjc/data/ResettableIterator.java14
-rw-r--r--src/main/java/bjc/esodata/.AbbrevTree.java.un~bin0 -> 33807 bytes
-rw-r--r--src/main/java/bjc/esodata/AbbrevMap2.java2
-rw-r--r--src/main/java/bjc/esodata/AbbrevTree.java276
-rw-r--r--src/main/java/bjc/esodata/Multimap.java44
-rw-r--r--src/main/java/bjc/esodata/NestList.java3
-rw-r--r--src/main/java/bjc/esodata/Stack.java2
-rw-r--r--src/main/java/bjc/esodata/ThresholdSet.java74
-rw-r--r--src/main/java/bjc/esodata/spool/Spool.java5
-rw-r--r--src/main/java/bjc/esodata/spool/Spooler.java5
-rw-r--r--src/main/java/bjc/funcdata/FunctionalList.java18
-rw-r--r--src/main/java/bjc/functypes/optics/Lens.java13
-rw-r--r--src/main/java/bjc/functypes/optics/LensX.java67
-rw-r--r--src/main/java/bjc/functypes/optics/Lenses.java147
-rw-r--r--src/main/java/bjc/functypes/optics/MutableLens.java29
-rw-r--r--src/main/java/bjc/functypes/optics/Optic.java15
-rw-r--r--src/main/java/bjc/functypes/optics/PrismX.java5
-rw-r--r--src/main/java/bjc/functypes/optics/impl/package-info.java1
-rw-r--r--src/main/java/bjc/functypes/optics/package-info.java4
-rw-r--r--src/main/java/module-info.java14
25 files changed, 932 insertions, 109 deletions
diff --git a/src/main/java/bjc/data/Contexts.java b/src/main/java/bjc/data/Contexts.java
index b028ad1..f587fe6 100644
--- a/src/main/java/bjc/data/Contexts.java
+++ b/src/main/java/bjc/data/Contexts.java
@@ -37,67 +37,67 @@ public class Contexts {
public static Context create(Context parent) {
return new ContextImpl(parent);
}
+}
- private static class NullContextImpl implements Context {
- @Override
- public Context getParent() {
- return this;
- }
+class NullContextImpl implements Context {
+ @Override
+ public Context getParent() {
+ return this;
+ }
- @Override
- public void register(String name, Object o) {
- throw new UnsupportedOperationException();
- }
+ @Override
+ public void register(String name, Object o) {
+ throw new UnsupportedOperationException();
+ }
- @Override
- public Object get(String name) {
- throw new NoSuchElementException();
- }
-
- @Override
- public <T> T get(Class<T> contract) {
- throw new NoSuchElementException();
- }
+ @Override
+ public Object get(String name) {
+ throw new NoSuchElementException();
}
+
+ @Override
+ public <T> T get(Class<T> contract) {
+ throw new NoSuchElementException();
+ }
+}
- private static class ContextImpl implements Context {
+class ContextImpl implements Context {
- private final Context parent;
+ private final Context parent;
- private final Map<String, Object> objects;
+ private final Map<String, Object> objects;
- public ContextImpl(Context parent) {
- this.parent = parent;
- this.objects = new HashMap<>();
- }
+ public ContextImpl(Context parent) {
+ this.parent = parent;
+ this.objects = new HashMap<>();
+ }
- @Override
- public void register(String name, Object o) {
- objects.put(name, o);
- }
+ @Override
+ public void register(String name, Object o) {
+ objects.put(name, o);
+ }
- @Override
- public Object get(String name) {
- if (objects.containsKey(name)) {
- return objects.get(name);
- }
- return parent.get(name);
+ @Override
+ public Object get(String name) {
+ if (objects.containsKey(name)) {
+ return objects.get(name);
}
+ return parent.get(name);
+ }
- @SuppressWarnings("unchecked")
- @Override
- public <T> T get(Class<T> contract) {
- for (Object o : objects.values()) {
- if (contract.isInstance(o)) {
- return (T) o;
- }
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T get(Class<T> contract) {
+ for (Object o : objects.values()) {
+ if (contract.isInstance(o)) {
+ return (T) o;
}
- return parent.get(contract);
}
+ return parent.get(contract);
+ }
- @Override
- public Context getParent() {
- return parent;
- }
+ @Override
+ public Context getParent() {
+ return parent;
}
-}
+} \ No newline at end of file
diff --git a/src/main/java/bjc/data/GeneratingIterator.java b/src/main/java/bjc/data/GeneratingIterator.java
index f926833..8900b94 100644
--- a/src/main/java/bjc/data/GeneratingIterator.java
+++ b/src/main/java/bjc/data/GeneratingIterator.java
@@ -42,7 +42,7 @@ public class GeneratingIterator<E> implements Iterator<E> {
@Override
public boolean hasNext() {
- return stpper.test(state);
+ return !stpper.test(state);
}
/*
diff --git a/src/main/java/bjc/data/MarkListIterator.java b/src/main/java/bjc/data/MarkListIterator.java
new file mode 100644
index 0000000..35baa28
--- /dev/null
+++ b/src/main/java/bjc/data/MarkListIterator.java
@@ -0,0 +1,175 @@
+package bjc.data;
+
+import java.util.*;
+
+/**
+ * ListIterator which allows navigation/marking of an iterator.
+ *
+ * @author bjcul
+ *
+ * @param <E> The element type
+ */
+public class MarkListIterator<E> implements ListIterator<E> {
+ private Iterator<E> backing;
+
+ private List<E> cache;
+ private Deque<Integer> marks;
+
+ private int currIdx;
+ private int maxIdx;
+
+ /**
+ * Create a new marking list iterator.
+ *
+ * @param backing The iterator which backs us.
+ */
+ public MarkListIterator(Iterator<E> backing) {
+ this.backing = backing;
+
+ this.currIdx = 0;
+ this.maxIdx = 0;
+
+ this.cache = new ArrayList<>();
+ this.marks = new ArrayDeque<>();
+ }
+
+ /**
+ * Get the current element of the iterator.
+ *
+ * @return The current iterator of the element
+ */
+ public E current() {
+ return cache.get(currIdx);
+ }
+
+ /**
+ * Create a new marking list iterator.
+ *
+ * @param backing The iterable to get the backing iterator from.
+ */
+ public MarkListIterator(Iterable<E> backing) {
+ this(backing.iterator());
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (currIdx < maxIdx)
+ return true;
+ return backing.hasNext();
+ }
+
+ @Override
+ public E next() {
+ if (currIdx < maxIdx) {
+ return cache.get(currIdx++);
+ }
+ currIdx++;
+ maxIdx++;
+ E next = backing.next();
+ cache.add(next);
+ return next;
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return maxIdx > 0 && currIdx > 0;
+ }
+
+ @Override
+ public E previous() {
+ currIdx--;
+ return cache.get(currIdx);
+ }
+
+ @Override
+ public int nextIndex() {
+ return currIdx + 1;
+ }
+
+ @Override
+ public int previousIndex() {
+ return currIdx - 1;
+ }
+
+ /**
+ * Mark the current position in the iterator.
+ */
+ public void mark() {
+ marks.push(currIdx);
+ }
+
+ /**
+ * Reset the iterator to the last position that was marked, leaving the mark in
+ * place.
+ *
+ * @return Whether or not a rollback actually happened
+ */
+ public boolean rollback() {
+ return rollback(false);
+ }
+
+ /**
+ * Reset the iterator to the last position that was marked.
+ *
+ * @param clearMark Whether to clear the mark being rolled back to.
+ *
+ * @return Whether or not a rollback actually happened
+ */
+ public boolean rollback(boolean clearMark) {
+ if (marks.isEmpty()) return false;
+
+ if (clearMark) {
+ currIdx = marks.pop();
+ } else {
+ currIdx = marks.peek();
+ }
+ return true;
+ }
+
+ /**
+ * Remove the last position that was marked.
+ *
+ * @return The marked position
+ */
+ public int commit() {
+ return marks.pop();
+ }
+
+ /**
+ * Resets the cache state of this iterator.
+ *
+ * Once this has been called, all of the previous elements and marks are
+ * discarded.
+ */
+ public void reset() {
+ this.cache = new ArrayList<>();
+ this.marks = new ArrayDeque<>();
+
+ this.currIdx = 0;
+ this.maxIdx = 0;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Can't remove items");
+ }
+
+ @Override
+ public void set(E e) {
+ throw new UnsupportedOperationException("Can't set items");
+ }
+
+ @Override
+ public void add(E e) {
+ throw new UnsupportedOperationException("Can't add items");
+ }
+
+ /**
+ * Check if this iterator has at least one active mark.
+ *
+ * @return Whether this iterator has any active marks.
+ */
+ public boolean hasMark() {
+ return !marks.isEmpty();
+ }
+}
diff --git a/src/main/java/bjc/data/Multimap.java b/src/main/java/bjc/data/Multimap.java
deleted file mode 100644
index 0e858b7..0000000
--- a/src/main/java/bjc/data/Multimap.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package bjc.data;
-
-/**
- * A map with support for multiple values per key.
- *
- * @param <KeyType>
- * The type of the keys for the map.
- * @param <ValueType>
- * The type of the values for the map.
- *
- * @author Ben Culkin
- */
-public class Multimap<KeyType, ValueType> {
- // TODO either implement this, or find if there is an implementation I've
- // written elsewhere
-}
diff --git a/src/main/java/bjc/data/Pair.java b/src/main/java/bjc/data/Pair.java
index baf1894..1d4be5e 100644
--- a/src/main/java/bjc/data/Pair.java
+++ b/src/main/java/bjc/data/Pair.java
@@ -1,5 +1,8 @@
package bjc.data;
+import java.util.Formattable;
+import java.util.FormattableFlags;
+import java.util.Formatter;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -18,7 +21,7 @@ import bjc.funcdata.theory.Bifunctor;
* The type of the right side of the pair.
*
*/
-public interface Pair<LeftType, RightType> extends Bifunctor<LeftType, RightType> {
+public interface Pair<LeftType, RightType> extends Bifunctor<LeftType, RightType>, Formattable {
/**
* Bind a function across the values in this pair.
*
@@ -247,4 +250,13 @@ public interface Pair<LeftType, RightType> extends Bifunctor<LeftType, RightType
public static <Left, Right> Pair<Left, Right> pair(Left left, Right right) {
return new SimplePair<>(left, right);
}
+
+ @Override
+ default void formatTo(Formatter formatter, int flags, int width, int precision) {
+ if ((flags & FormattableFlags.ALTERNATE) != 0) {
+ formatter.format("(%s, %s)", getLeft(), getRight());
+ } else {
+ formatter.format("Pair [l=%s, r=%s", getLeft(), getRight());
+ }
+ }
}
diff --git a/src/main/java/bjc/data/ResettableIterator.java b/src/main/java/bjc/data/ResettableIterator.java
index 8b7f07a..8c1c4aa 100644
--- a/src/main/java/bjc/data/ResettableIterator.java
+++ b/src/main/java/bjc/data/ResettableIterator.java
@@ -5,12 +5,12 @@ import java.util.*;
/*
* @TODO Oct 6, 2020 - Ben Culkin - :CleverCache
*
- * In the future, there are certain efficencies we could take with our cached
+ * In the future, there are certain efficiencies we could take with our cached
* elements; namely, the case where we repeat the same element multiple times,
* or the case where we have a mixture of identical (and probably sizable) elements
*
- * The general downside to these of course, is that these efficencies would cost
- * us something in terms of complexity, as well as not benefitting iterators which
+ * The general downside to these of course, is that these efficiencies would cost
+ * us something in terms of complexity, as well as not benefiting iterators which
* aren't large enough.
*
* Still an interesting thought as to the best way to implement such a thing though.
@@ -57,7 +57,7 @@ public class ResettableIterator<T> implements Iterator<T> {
@Override
public boolean hasNext() {
if (isRepeating) return cacheIterator.hasNext() ? true : backing.hasNext();
- else return backing.hasNext();
+ return backing.hasNext();
}
@Override
@@ -65,10 +65,10 @@ public class ResettableIterator<T> implements Iterator<T> {
if (isRepeating) {
if (cacheIterator.hasNext()) {
return cacheIterator.next();
- } else {
- cacheIterator = null;
- isRepeating = false;
}
+
+ cacheIterator = null;
+ isRepeating = false;
}
T itm = backing.next();
diff --git a/src/main/java/bjc/esodata/.AbbrevTree.java.un~ b/src/main/java/bjc/esodata/.AbbrevTree.java.un~
new file mode 100644
index 0000000..7c8a369
--- /dev/null
+++ b/src/main/java/bjc/esodata/.AbbrevTree.java.un~
Binary files differ
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 &lt; 0.
+ * always be &gt; 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();
+}
diff --git a/src/main/java/bjc/funcdata/FunctionalList.java b/src/main/java/bjc/funcdata/FunctionalList.java
index 88f49c4..c9c3a9f 100644
--- a/src/main/java/bjc/funcdata/FunctionalList.java
+++ b/src/main/java/bjc/funcdata/FunctionalList.java
@@ -6,6 +6,7 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -487,4 +488,21 @@ public class FunctionalList<E> implements Cloneable, ListEx<E> {
return sb.toString();
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(wrapped);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FunctionalList<?> other = (FunctionalList<?>) obj;
+ return Objects.equals(wrapped, other.wrapped);
+ }
}
diff --git a/src/main/java/bjc/functypes/optics/Lens.java b/src/main/java/bjc/functypes/optics/Lens.java
new file mode 100644
index 0000000..0a7d4cd
--- /dev/null
+++ b/src/main/java/bjc/functypes/optics/Lens.java
@@ -0,0 +1,13 @@
+package bjc.functypes.optics;
+
+/**
+ * A type-invariant var Laarhoven lens.
+ *
+ * @author bjcul
+ *
+ * @param <Whole> The item this lens can focus on
+ * @param <Part> The field this lens focuses on
+ */
+public interface Lens<Whole, Part> extends LensX<Whole, Whole, Part, Part> {
+ // Alias type
+}
diff --git a/src/main/java/bjc/functypes/optics/LensX.java b/src/main/java/bjc/functypes/optics/LensX.java
new file mode 100644
index 0000000..d2e9c30
--- /dev/null
+++ b/src/main/java/bjc/functypes/optics/LensX.java
@@ -0,0 +1,67 @@
+package bjc.functypes.optics;
+
+import static bjc.functypes.optics.Lenses.immutable;
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * A type-variant lens
+ *
+ * @author Ben Culkin
+ *
+ * @param <W1> The first type the lens is used on
+ * @param <W2> The second 'whole' type
+ * @param <P1> The first 'part' type
+ * @param <P2> The second 'part' type
+ */
+public interface LensX<W1, W2, P1, P2> extends Optic<W1, W2, P1, P2> {
+ /**
+ * Retrieve the focused value of this lens.
+ *
+ * @param source The item to use the lens on.
+ *
+ * @return The value from the given whole this lens focuses on.
+ */
+ P1 get(W1 source);
+
+ /**
+ * Create an updated version of the item this lens focuses on.
+ *
+ * @param source The item to use the lens on.
+ * @param val The new value.
+ *
+ * @return The updated item the lens was used on.
+ */
+ W2 set(W1 source, P2 val);
+
+ /**
+ * Update the focused value.
+ *
+ * NOTE: It will often be more efficient to implement this directly. The
+ * implementation here is provided for convenience.
+ *
+ * @param source The item to use the lens on.
+ * @param action The action to applied to the focused item.
+ *
+ * @return The updated item the lens was used on.
+ */
+ default W2 update(W1 source, Function<P1, P2> action) {
+ return set(source, action.apply(get(source)));
+ }
+
+ /**
+ * Compose two type-variant lenses together.
+ *
+ * @param <V1> The first type the second lens focuses on
+ * @param <V2> The second type the second lens focuses on.
+ *
+ * @param other The second lens to use.
+ *
+ * @return A lens composed from this one and the given one.
+ */
+ default <V1, V2> LensX<W1, W2, V1, V2> compose(LensX<P1, P2, V1, V2> other) {
+ return immutable((whole) -> other.get(get(whole)),
+ (whole, val) -> update(whole, (P1 val2) -> other.set(val2, val)));
+ }
+} \ No newline at end of file
diff --git a/src/main/java/bjc/functypes/optics/Lenses.java b/src/main/java/bjc/functypes/optics/Lenses.java
new file mode 100644
index 0000000..05a64e7
--- /dev/null
+++ b/src/main/java/bjc/functypes/optics/Lenses.java
@@ -0,0 +1,147 @@
+package bjc.functypes.optics;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import bjc.data.Holder;
+import bjc.data.Pair;
+
+/**
+ * Utility and constructor functions for lenses
+ *
+ * @author bjcul
+ *
+ */
+public class Lenses {
+ /**
+ * Create an immutable lens from a pair of functions.
+ *
+ * @param <W1> The first type the lens is used on
+ * @param <W2> The second type the lens is used on
+ * @param <P1> The first type the lens focuses on
+ * @param <P2> The second type the lens focuses on.
+ *
+ * @param getter The getter for the lens
+ * @param setter The setter for the lens
+ *
+ * @return The lens composed from the two given functions
+ */
+ public static <W1, W2, P1, P2> LensX<W1, W2, P1, P2> immutable(Function<W1, P1> getter,
+ BiFunction<W1, P2, W2> setter) {
+ return new FunctionalLensX<>(getter, setter);
+ }
+
+ /**
+ * Create a mutable lens from a pair of functions.
+ *
+ * @param <Whole> The type the lens is used on
+ * @param <Part> The type the lens is focused on
+ *
+ * @param getter The getter for the lens
+ * @param mutator The mutator for the lens
+ *
+ * @return The mutable lens composed from the two given functions
+ */
+ public static <Whole, Part> MutableLens<Whole, Part> mutable(Function<Whole, Part> getter,
+ BiConsumer<Whole, Part> mutator) {
+ return new FunctionalMutableLens<>(getter, mutator);
+ }
+
+ /**
+ * Create a lens that reflects over the value in a holder
+ *
+ * @param <Part1> The first type contained in the holder
+ * @param <Part2> The second type contained in the holder
+ *
+ * @return A lens that focuses on the value of a holder
+ */
+ public static <Part1, Part2> LensX<Holder<Part1>, Holder<Part2>, Part1, Part2> holder() {
+ return immutable((hld) -> hld.getValue(), (hld, val) -> hld.map((vl) -> val));
+ }
+
+ /**
+ * Create a lens for updating tagged pairs.
+ *
+ * TODO: Should this be on a Tagged<T, A> class that is isomorphic to pair
+ * instead?
+ *
+ * @param <A> The first data type
+ * @param <B> The second data type
+ * @param <T> The tag type
+ *
+ * @return A lens that operates on the value of a tagged pair.
+ */
+ public static <A, B, T> LensX<Pair<T, A>, Pair<T, B>, A, B> tagged() {
+ return immutable((par) -> par.getRight(), (par, val) -> par.mapRight((vl) -> val));
+ }
+
+ /**
+ * Creates a lens which focuses on a piece of internal state.
+ *
+ * @param <A> The first state type
+ * @param <B> The second state type
+ *
+ * @param val The initial state value
+ *
+ * @return A lens that focuses on the given internal state.
+ */
+ public static <A, B> LensX<?, ?, A, B> state(A val) {
+ Holder<A> hold = Holder.of(val);
+ return immutable((whole) -> hold.getValue(), (whole, vl) -> hold.map((arg) -> vl));
+ }
+
+ /**
+ * Creates a lens which focuses on a piece of mutable internal state.
+ *
+ * @param <A> The state type
+ *
+ * @param val The initial state value
+ *
+ * @return A lens that focuses on the given internal state.
+ */
+ public static <A> MutableLens<?, A> stateM(A val) {
+ Holder<A> hold = Holder.of(val);
+ return mutable((whole) -> hold.getValue(), (whole, vl) -> hold.replace(vl));
+ }
+}
+
+final class FunctionalLensX<W1, W2, P1, P2> implements LensX<W1, W2, P1, P2> {
+ private final BiFunction<W1, P2, W2> setter;
+ private final Function<W1, P1> getter;
+
+ FunctionalLensX(Function<W1, P1> getter, BiFunction<W1, P2, W2> setter) {
+ this.setter = setter;
+ this.getter = getter;
+ }
+
+ @Override
+ public P1 get(W1 source) {
+ return getter.apply(source);
+ }
+
+ @Override
+ public W2 set(W1 source, P2 val) {
+ return setter.apply(source, val);
+ }
+}
+
+final class FunctionalMutableLens<Whole, Part> implements MutableLens<Whole, Part> {
+ private final BiConsumer<Whole, Part> mutator;
+ private final Function<Whole, Part> getter;
+
+ FunctionalMutableLens(Function<Whole, Part> getter, BiConsumer<Whole, Part> mutator) {
+ this.mutator = mutator;
+ this.getter = getter;
+ }
+
+ @Override
+ public Part get(Whole source) {
+ return getter.apply(source);
+ }
+
+ @Override
+ public void mutate(Whole source, Part val) {
+ mutator.accept(source, val);
+ }
+}
diff --git a/src/main/java/bjc/functypes/optics/MutableLens.java b/src/main/java/bjc/functypes/optics/MutableLens.java
new file mode 100644
index 0000000..b6fca5d
--- /dev/null
+++ b/src/main/java/bjc/functypes/optics/MutableLens.java
@@ -0,0 +1,29 @@
+package bjc.functypes.optics;
+
+/**
+ * A type-invariant lens for mutating objects.
+ *
+ * Note that there is no type-variant version, because that wouldn't make much sense.
+ *
+ * Also, mixing mutable and immutable lenses may lead to confusion.
+ *
+ * @author bjcul
+ *
+ * @param <Whole> The type the lens is used on
+ * @param <Part> The type the lens is focused on
+ */
+public interface MutableLens<Whole, Part> extends Lens<Whole, Part> {
+ /**
+ * Apply a mutation to an item.
+ *
+ * @param source The item to use the lens on.
+ * @param val The new value for the focused field.
+ */
+ void mutate(Whole source, Part val);
+
+ @Override
+ default Whole set(Whole source, Part val) {
+ mutate(source, val);
+ return source;
+ }
+}
diff --git a/src/main/java/bjc/functypes/optics/Optic.java b/src/main/java/bjc/functypes/optics/Optic.java
new file mode 100644
index 0000000..949eeca
--- /dev/null
+++ b/src/main/java/bjc/functypes/optics/Optic.java
@@ -0,0 +1,15 @@
+package bjc.functypes.optics;
+
+/**
+ * General interface for optics of varying sorts
+ *
+ * @author bjcul
+ *
+ * @param <W1> The first item the optic is used on
+ * @param <W2> The second item the optic is used on
+ * @param <P1> The first item the optic focuses on
+ * @param <P2> The second item the optic focuses on
+ */
+public interface Optic<W1, W2, P1, P2> {
+ // Marker interface
+}
diff --git a/src/main/java/bjc/functypes/optics/PrismX.java b/src/main/java/bjc/functypes/optics/PrismX.java
new file mode 100644
index 0000000..a9c0dd2
--- /dev/null
+++ b/src/main/java/bjc/functypes/optics/PrismX.java
@@ -0,0 +1,5 @@
+package bjc.functypes.optics;
+
+public interface PrismX<W1, W2, P1, P2> extends Optic<W1, W2, P1, P2> {
+
+}
diff --git a/src/main/java/bjc/functypes/optics/impl/package-info.java b/src/main/java/bjc/functypes/optics/impl/package-info.java
new file mode 100644
index 0000000..f309401
--- /dev/null
+++ b/src/main/java/bjc/functypes/optics/impl/package-info.java
@@ -0,0 +1 @@
+package bjc.functypes.optics.impl; \ No newline at end of file
diff --git a/src/main/java/bjc/functypes/optics/package-info.java b/src/main/java/bjc/functypes/optics/package-info.java
new file mode 100644
index 0000000..c187df9
--- /dev/null
+++ b/src/main/java/bjc/functypes/optics/package-info.java
@@ -0,0 +1,4 @@
+/**
+ *
+ */
+package bjc.functypes.optics; \ No newline at end of file
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
new file mode 100644
index 0000000..fdbf1b6
--- /dev/null
+++ b/src/main/java/module-info.java
@@ -0,0 +1,14 @@
+/**
+ * Contains various more esoteric data structures.
+ *
+ * @author bjculkin
+ *
+ */
+module esodata {
+ exports bjc.data;
+ exports bjc.esodata;
+ exports bjc.functypes;
+ exports bjc.funcdata.bst;
+ exports bjc.funcdata.theory;
+ exports bjc.funcdata;
+} \ No newline at end of file