summaryrefslogtreecommitdiff
path: root/src/main/java/bjc/esodata
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/bjc/esodata')
-rw-r--r--src/main/java/bjc/esodata/AbbrevMap2.java15
-rw-r--r--src/main/java/bjc/esodata/DefaultList.java6
-rw-r--r--src/main/java/bjc/esodata/Directory.java3
-rw-r--r--src/main/java/bjc/esodata/DoubleTape.java29
-rw-r--r--src/main/java/bjc/esodata/FlatNestIterator.java103
-rw-r--r--src/main/java/bjc/esodata/MapSet.java9
-rw-r--r--src/main/java/bjc/esodata/MinMaxList.java238
-rw-r--r--src/main/java/bjc/esodata/Multimap.java14
-rw-r--r--src/main/java/bjc/esodata/NestList.java389
-rw-r--r--src/main/java/bjc/esodata/PushdownMap.java135
-rw-r--r--src/main/java/bjc/esodata/QueueStack.java21
-rw-r--r--src/main/java/bjc/esodata/SimpleDirectory.java31
-rw-r--r--src/main/java/bjc/esodata/SimpleStack.java21
-rw-r--r--src/main/java/bjc/esodata/SingleTape.java63
-rw-r--r--src/main/java/bjc/esodata/SpaghettiStack.java27
-rw-r--r--src/main/java/bjc/esodata/Stack.java36
-rw-r--r--src/main/java/bjc/esodata/TapeLibrary.java163
-rw-r--r--src/main/java/bjc/esodata/TapeView.java102
-rw-r--r--src/main/java/bjc/esodata/ThresholdSet.java30
-rw-r--r--src/main/java/bjc/esodata/UnifiedDirectory.java31
20 files changed, 1193 insertions, 273 deletions
diff --git a/src/main/java/bjc/esodata/AbbrevMap2.java b/src/main/java/bjc/esodata/AbbrevMap2.java
index f131aec..259c963 100644
--- a/src/main/java/bjc/esodata/AbbrevMap2.java
+++ b/src/main/java/bjc/esodata/AbbrevMap2.java
@@ -36,9 +36,7 @@ public class AbbrevMap2 {
*/
public void add(String... words) {
for (String word : words) {
- for (String substr : genAbbrevs(word)) {
- backing.add(substr, word);
- }
+ for (String substr : genAbbrevs(word)) backing.add(substr, word);
}
}
@@ -65,9 +63,7 @@ public class AbbrevMap2 {
*/
public void removeWords(String... words) {
for (String word : words) {
- for (String substr : genAbbrevs(word)) {
- backing.remove(substr, word);
- }
+ for (String substr : genAbbrevs(word)) backing.remove(substr, word);
}
}
@@ -95,10 +91,7 @@ public class AbbrevMap2 {
public String deabbrev(String word) {
Set<String> st = backing.get(word);
- if (st.size() == 1) {
- return st.iterator().next();
- } else {
- return null;
- }
+ if (st.size() == 1) return st.iterator().next();
+ else return null;
}
}
diff --git a/src/main/java/bjc/esodata/DefaultList.java b/src/main/java/bjc/esodata/DefaultList.java
index c4535bd..e622301 100644
--- a/src/main/java/bjc/esodata/DefaultList.java
+++ b/src/main/java/bjc/esodata/DefaultList.java
@@ -90,10 +90,8 @@ public class DefaultList<ValueType> extends AbstractList<ValueType> {
@Override
public ValueType get(int idx) {
- if (idx < 0 || idx >= backing.size())
- return defVal;
-
- return backing.get(idx);
+ if (idx < 0 || idx >= backing.size()) return defVal;
+ else return backing.get(idx);
}
@Override
diff --git a/src/main/java/bjc/esodata/Directory.java b/src/main/java/bjc/esodata/Directory.java
index e083cd8..fa47b6f 100644
--- a/src/main/java/bjc/esodata/Directory.java
+++ b/src/main/java/bjc/esodata/Directory.java
@@ -59,8 +59,7 @@ public interface Directory<K, V> {
* @return The new sub-directory, or null if one by that name already exists.
*/
default Directory<K, V> newSubdirectory(final K key) {
- if (hasSubdirectory(key))
- return null;
+ if (hasSubdirectory(key)) return null;
final Directory<K, V> dir = new SimpleDirectory<>();
diff --git a/src/main/java/bjc/esodata/DoubleTape.java b/src/main/java/bjc/esodata/DoubleTape.java
index cc7cdb9..30d94a1 100644
--- a/src/main/java/bjc/esodata/DoubleTape.java
+++ b/src/main/java/bjc/esodata/DoubleTape.java
@@ -112,9 +112,7 @@ public class DoubleTape<T> implements Tape<T>, DoubleSided {
public boolean left(final int amt) {
final boolean succ = front.left(amt);
- if (succ) {
- back.right(amt);
- }
+ if (succ) back.right(amt);
return succ;
}
@@ -128,9 +126,7 @@ public class DoubleTape<T> implements Tape<T>, DoubleSided {
public boolean right(final int amt) {
final boolean succ = front.right(amt);
- if (succ) {
- back.left(amt);
- }
+ if (succ) back.left(amt);
return succ;
}
@@ -167,26 +163,23 @@ public class DoubleTape<T> implements Tape<T>, DoubleSided {
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof DoubleTape<?>))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof DoubleTape<?>)) return false;
final DoubleTape<?> other = (DoubleTape<?>) obj;
if (back == null) {
- if (other.back != null)
- return false;
- } else if (!back.equals(other.back))
+ if (other.back != null) return false;
+ } else if (!back.equals(other.back)) {
return false;
+ }
if (front == null) {
- if (other.front != null)
- return false;
- } else if (!front.equals(other.front))
+ if (other.front != null) return false;
+ } else if (!front.equals(other.front)) {
return false;
+ }
return true;
}
diff --git a/src/main/java/bjc/esodata/FlatNestIterator.java b/src/main/java/bjc/esodata/FlatNestIterator.java
new file mode 100644
index 0000000..42981f5
--- /dev/null
+++ b/src/main/java/bjc/esodata/FlatNestIterator.java
@@ -0,0 +1,103 @@
+package bjc.esodata;
+
+import java.util.*;
+
+import bjc.data.*;
+
+final class FlatNestIterator<Element> implements ListIterator<Element>
+{
+ private Deque<ListIterator<Either<Element, NestList<Element>>>> iterators;
+
+ public FlatNestIterator(ListIterator<Either<Element, NestList<Element>>> iterator)
+ {
+ this.iterators = new ArrayDeque<>();
+ this.iterators.add(iterator);
+ }
+
+ @Override
+ public boolean hasNext() {
+ boolean result = false;
+ do {
+ result = iterators.peek().hasNext();
+
+ if (result == false) iterators.pop();
+ } while (result == false && iterators.isEmpty() == false);
+
+ return result;
+ }
+
+ @Override
+ public Element next() {
+ Holder<Element> element = Holder.of(null);
+ do {
+ element = iterators.peek().next().extract((ele) -> {
+ return Holder.of(ele);
+ }, (lst) -> {
+ // Ignore empty sublists.
+ if (lst.size() != 0) iterators.push(lst.listIterator());
+
+ return null;
+ });
+ } while (element == null && hasNext());
+
+ if (element == null) throw new NoSuchElementException();
+
+ return element.getValue();
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ boolean result = false;
+ do {
+ result = iterators.peek().hasPrevious();
+
+ if (result == false) iterators.pop();
+ } while (result == false && iterators.isEmpty() == false);
+
+ return result;
+ }
+
+ @Override
+ public Element previous() {
+ Holder<Element> element = Holder.of(null);
+ do {
+ element = iterators.peek().previous().extract((ele) -> {
+ return Holder.of(ele);
+ }, (lst) -> {
+ // Ignore empty sublists.
+ if (lst.size() != 0) iterators.push(lst.listIterator());
+
+ return null;
+ });
+ } while (element == null && hasPrevious());
+
+ if (element == null) throw new NoSuchElementException();
+
+ return element.getValue();
+ }
+
+ @Override
+ public int nextIndex() {
+ return iterators.peek().nextIndex();
+ }
+
+ @Override
+ public int previousIndex() {
+ return iterators.peek().previousIndex();
+ }
+
+ @Override
+ public void remove() {
+ iterators.peek().remove();
+ }
+
+ @Override
+ public void set(Element e) {
+ iterators.peek().set(Either.left(e));
+ }
+
+ @Override
+ public void add(Element e) {
+ iterators.peek().add(Either.left(e));
+ }
+} \ No newline at end of file
diff --git a/src/main/java/bjc/esodata/MapSet.java b/src/main/java/bjc/esodata/MapSet.java
index a80c482..7d77ad6 100644
--- a/src/main/java/bjc/esodata/MapSet.java
+++ b/src/main/java/bjc/esodata/MapSet.java
@@ -116,8 +116,7 @@ public class MapSet<KeyType, ValueType> extends AbstractMap<KeyType, ValueType>
* @return False if there is no map attached to the key, true otherwise.
*/
public boolean setMap(String key) {
- if (!backing.containsKey(key))
- return false;
+ if (!backing.containsKey(key)) return false;
currentMap = backing.get(key);
@@ -165,16 +164,14 @@ public class MapSet<KeyType, ValueType> extends AbstractMap<KeyType, ValueType>
@Override
public Set<Map.Entry<KeyType, ValueType>> entrySet() {
- if (currentMap == null)
- throw new NullPointerException("Current map is not set");
+ if (currentMap == null) throw new NullPointerException("Current map is not set");
return currentMap.entrySet();
}
@Override
public ValueType put(KeyType key, ValueType value) {
- if (currentMap == null)
- throw new NullPointerException("Current map is not set");
+ if (currentMap == null) throw new NullPointerException("Current map is not set");
return currentMap.put(key, value);
}
diff --git a/src/main/java/bjc/esodata/MinMaxList.java b/src/main/java/bjc/esodata/MinMaxList.java
new file mode 100644
index 0000000..6747831
--- /dev/null
+++ b/src/main/java/bjc/esodata/MinMaxList.java
@@ -0,0 +1,238 @@
+package bjc.esodata;
+
+import java.util.*;
+
+// @FIXME Nov 15th, 2020 Ben Culkin :RecalcMinMax
+// Is there some sort of way to avoid having to recalculate these elements when
+// that element is removed?
+/**
+ * A list that automatically tracks the minimum & maximum element of a list.
+ *
+ * @author Ben Culkin
+ *
+ * @param <ValueType> The type of element stored in the list.
+ *
+ */
+public class MinMaxList<ValueType> extends AbstractList<ValueType> {
+ private final List<ValueType> backing;
+ private final Comparator<ValueType> picker;
+
+ private ValueType minElement;
+ private boolean recalcMin = false;
+
+ private ValueType maxElement;
+ private boolean recalcMax = false;
+
+ // Create constructors
+
+ /**
+ * Create a new min/max list using the given comparator.
+ *
+ * @param picker The comparator to use to determine min/max elements.
+ */
+ public MinMaxList(Comparator<ValueType> picker) {
+ this(picker, new ArrayList<>());
+ }
+
+ /**
+ * Create a new min/max list using the given comparator.
+ *
+ * @param picker The comparator to use to determine min/max elements.
+ * @param values The values to fill the list from.
+ */
+ @SafeVarargs
+ public MinMaxList(Comparator<ValueType> picker, ValueType... values) {
+ this(picker);
+
+ for (ValueType value : values) {
+ add(value);
+ }
+ }
+ /**
+ * Create a new min/max list using the given comparator.
+ *
+ * @param picker The comparator to use to determine min/max elements.
+ * @param backing The collection to use values from.
+ */
+ public MinMaxList(Comparator<ValueType> picker, Collection<ValueType> backing) {
+ this(picker, new ArrayList<>(backing));
+ }
+
+ /**
+ * Create a new min/max list using the given comparator.
+ *
+ * @param picker The comparator to use to determine min/max elements.
+ * @param backing The list to use as a backing list.
+ */
+ public MinMaxList(Comparator<ValueType> picker, List<ValueType> backing) {
+ this.backing = backing;
+ this.picker = picker;
+
+ calculateBoth();
+ }
+
+ @Override
+ public ValueType get(int index) {
+ return backing.get(index);
+ }
+
+ @Override
+ public ValueType set(int index, ValueType element) {
+ ValueType oldElement = backing.set(index, element);
+
+ if (minElement == null) {
+ minElement = element;
+ } else if (picker.compare(element, minElement) < 0) {
+ minElement = element;
+ recalcMin = false;
+ } else if (oldElement.equals(minElement)) {
+ minElement = null;
+ recalcMin = true;
+ }
+
+ if (maxElement == null) {
+ maxElement = element;
+ } else if (picker.compare(element, maxElement) > 0) {
+ maxElement = element;
+ recalcMax = false;
+ } else if (oldElement.equals(maxElement)) {
+ maxElement = null;
+ recalcMax = true;
+ }
+
+ return oldElement;
+ }
+
+ @Override
+ public void add(int index, ValueType element) {
+ backing.add(index, element);
+
+ if (minElement == null) {
+ minElement = element;
+ } else if (picker.compare(element, minElement) < 0) {
+ minElement = element;
+ recalcMin = false;
+ }
+
+ if (maxElement == null) {
+ maxElement = element;
+ } else if (picker.compare(element, maxElement) > 0) {
+ maxElement = element;
+ recalcMax = false;
+ }
+ }
+
+ @Override
+ public ValueType remove(int index) {
+ ValueType oldElement = backing.remove(index);
+
+ if (oldElement.equals(minElement)) {
+ minElement = null;
+ recalcMin = true;
+ }
+
+ if (oldElement.equals(maxElement)) {
+ maxElement = null;
+ recalcMax = true;
+ }
+
+ return oldElement;
+ }
+
+ @Override
+ public int size() {
+ return backing.size();
+ }
+
+ /**
+ * Get the minimum element currently stored in this list.
+ *
+ * @return The minimum element stored in the list.
+ */
+ public ValueType minimum() {
+ if (recalcMin) calculateMinimum();
+
+ return minElement;
+ }
+
+ /**
+ * Get the maximum element currently stored in this list.
+ *
+ * @return The maximum element stored in the list.
+ */
+ public ValueType maximum() {
+ if (recalcMax) calculateMaximum();
+
+ return maxElement;
+ }
+
+ private void calculateMinimum() {
+ for (ValueType element : backing) {
+ if (minElement == null) {
+ minElement = element;
+ } else if (picker.compare(element, minElement) < 0) {
+ minElement = element;
+ }
+ }
+
+ recalcMin = false;
+ }
+
+ private void calculateMaximum() {
+ for (ValueType element : backing) {
+ if (maxElement == null) {
+ maxElement = element;
+ } else if (picker.compare(element, maxElement) > 0) {
+ maxElement = element;
+ }
+ }
+
+ recalcMax = false;
+ }
+
+ private void calculateBoth() {
+ for (ValueType element : backing) {
+ if (minElement == null) {
+ minElement = element;
+ } else if (picker.compare(element, minElement) < 0) {
+ minElement = element;
+ }
+
+ if (maxElement == null) {
+ maxElement = element;
+ } else if (picker.compare(element, maxElement) > 0) {
+ maxElement = element;
+ }
+ }
+
+ recalcMin = false;
+ recalcMax = false;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s (min: %s) (max: %s)", backing,
+ recalcMin ? "(unknown)" : minElement,
+ recalcMax ? "(unknown)" : maxElement);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(backing, picker);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+
+ MinMaxList<?> other = (MinMaxList<?>) obj;
+
+ return Objects.equals(backing, other.backing)
+ && Objects.equals(picker, other.picker);
+ }
+}
diff --git a/src/main/java/bjc/esodata/Multimap.java b/src/main/java/bjc/esodata/Multimap.java
index a79f1b0..fae872e 100644
--- a/src/main/java/bjc/esodata/Multimap.java
+++ b/src/main/java/bjc/esodata/Multimap.java
@@ -51,9 +51,8 @@ public class Multimap<KeyType, ValueType> {
*/
public void remove(KeyType key, ValueType value) {
// We have no values for that key; bail.
- if (!backing.containsKey(key))
- return;
-
+ if (!backing.containsKey(key)) return;
+
backing.get(key).remove(value);
}
@@ -76,10 +75,8 @@ public class Multimap<KeyType, ValueType> {
* @return A set containing all of the values that have been mapped to that key.
*/
public Set<ValueType> get(KeyType key) {
- if (!backing.containsKey(key))
- return new HashSet<>();
-
- return backing.get(key).values();
+ if (!backing.containsKey(key)) return new HashSet<>();
+ else return backing.get(key).values();
}
/**
@@ -107,8 +104,7 @@ public class Multimap<KeyType, ValueType> {
* mapping.
*/
public boolean contains(KeyType key, ValueType value) {
- if (!backing.containsKey(key))
- return false;
+ if (!backing.containsKey(key)) return false;
return backing.get(key).contains(value) > 0;
}
diff --git a/src/main/java/bjc/esodata/NestList.java b/src/main/java/bjc/esodata/NestList.java
new file mode 100644
index 0000000..eccaf9d
--- /dev/null
+++ b/src/main/java/bjc/esodata/NestList.java
@@ -0,0 +1,389 @@
+package bjc.esodata;
+
+import static bjc.functypes.Combinators.*;
+
+import java.util.*;
+import java.util.function.*;
+
+import bjc.data.*;
+
+/**
+ * A list which can contain sublists of itself.
+ *
+ * N.B: Be careful if you form a recursive list, as there is no form of detection
+ * in place for that. Some operations may work, but those that do a deep traversal
+ * of the list will not.
+ *
+ * @author Ben Culkin
+ *
+ * @param <Element> The type contained in the list.
+ */
+public class NestList<Element> extends AbstractList<Either<Element, NestList<Element>>>
+{
+ private final List<Either<Element, NestList<Element>>> backing;
+
+ /**
+ * Create a new empty nesting list.
+ */
+ public NestList() {
+ backing = new ArrayList<>();
+ }
+
+ /**
+ * Create a new empty nesting list with the given capacity.
+ *
+ * @param cap The capacity for the nesting list.
+ */
+ public NestList(int cap) {
+ backing = new ArrayList<>(cap);
+ }
+
+ /**
+ * Add an element to this list.
+ *
+ * @param element The element to add to the list.
+ *
+ * @return Whether we could add the element.
+ */
+ public boolean addItem(Element element) {
+ return backing.add(Either.left(element));
+ }
+
+ /**
+ * Add a sublist to this list.
+ *
+ * @param element The sublist to add to this list.
+ *
+ * @return Whether we could add the sublist.
+ */
+ public boolean addItem(NestList<Element> element) {
+ return backing.add(Either.right(element));
+ }
+ /**
+ * Add elements to this list.
+ *
+ * @param elements The elements to add to the list.
+ *
+ * @return Whether we could add each element.
+ */
+ public boolean[] addItems(@SuppressWarnings("unchecked") Element... elements) {
+ boolean[] vals = new boolean[elements.length];
+
+ for (int i = 0; i < vals.length; i++)
+ {
+ vals[i] = addItem(elements[i]);
+ }
+
+ return vals;
+ }
+
+ /**
+ * Add sublists to this list.
+ *
+ * @param elements The sublists to add to this list.
+ *
+ * @return Whether we could add each sublist.
+ */
+ public boolean[] addItems(@SuppressWarnings("unchecked") NestList<Element>... elements) {
+ boolean[] vals = new boolean[elements.length];
+
+ for (int i = 0; i < vals.length; i++)
+ {
+ vals[i] = addItem(elements[i]);
+ }
+
+ return vals;
+ }
+
+ /**
+ * Add a sublist with the given elements to this list.
+ *
+ * @param elements The elements of the sublist.
+ *
+ * @return Whether or not we could add the sublist.
+ */
+ public boolean addSublist(@SuppressWarnings("unchecked") Element... elements) {
+ NestList<Element> container = new NestList<>(elements.length);
+
+ for (Element ele : elements) {
+ container.addItem(ele);
+ }
+
+ return addItem(container);
+ }
+
+ /**
+ * Return an iterator over a flattened version of this list.
+ *
+ * N.B: In certain cases involving empty sublists, the hasNext() operation\
+ * may not be 100% accurate. Be warned.
+ *
+ * @return An iterator over a flattened variant of this list.
+ */
+ public ListIterator<Element> flatIterator() {
+ return new FlatNestIterator<>(listIterator());
+ }
+
+ /**
+ * Flatten one level of nesting from this list.
+ *
+ * @return The list with one level of nesting flattened.
+ */
+ public NestList<Element> flatten() {
+ NestList<Element> flatterList = new NestList<>(size());
+
+ backing.forEach((element) ->
+ element.pick(flatterList::addItem, flatterList::addAll)
+ );
+
+ return flatterList;
+ }
+
+ /**
+ * Flatten this list recursively.
+ *
+ * @return A flattened form of this list.
+ */
+ public List<Element> deepFlatten() {
+ List<Element> flatList = new ArrayList<>();
+
+ flatIterator().forEachRemaining(flatList::add);
+
+ return flatList;
+ }
+
+ /**
+ * Get the total number of elements contained in this list and all sublists.
+ *
+ * @return The total number of elements contained in this list.
+ */
+ public int deepSize() {
+ int size = 0;
+
+ for (Either<Element, NestList<Element>> element : backing)
+ {
+ size += element.extract((ele) -> 1, (lst) -> lst.deepSize());
+ }
+
+ return size;
+ }
+
+ /**
+ * Replace all of the elements in this list in-place with transformed versions.
+ *
+ * @param elementOperator The operator to apply to elements.
+ * @param listOperator The operator to apply to sublists.
+ */
+ public void replace(
+ UnaryOperator<Element> elementOperator,
+ UnaryOperator<NestList<Element>> listOperator) {
+ backing.replaceAll((ele) -> ele.map(elementOperator, listOperator));
+ }
+
+ /**
+ * Perform a shallow mapping over this list.
+ *
+ * @param <NewElement> The new element type.
+ *
+ * @param elementMapper The function to map elements.
+ * @param listMapper The function to map lists.
+ *
+ * @return A new list containing the mapped elements.
+ */
+ public <NewElement> NestList<NewElement> map(
+ Function<Element, NewElement> elementMapper,
+ Function<NestList<Element>, NestList<NewElement>> listMapper)
+ {
+ NestList<NewElement> nest = new NestList<>(backing.size());
+
+ for (Either<Element, NestList<Element>> element : backing)
+ {
+ nest.add(element.map(elementMapper, listMapper));
+ }
+
+ return nest;
+ }
+
+ /**
+ * Perform a recursive mapping over this list.
+ *
+ * @param <NewElement> The new element type.
+ *
+ * @param mapper The element mapper.
+ *
+ * @return A new list with the same structure, but transformed elements.
+ */
+ public <NewElement> NestList<NewElement> deepMap(
+ Function<Element, NewElement> mapper)
+ {
+ return map(mapper, (lst) -> lst.deepMap(mapper));
+ }
+
+ /**
+ * Perform a mapping on the list with controllable recursion.
+ *
+ * Inspired by the function of the same name from Raku.
+ *
+ * @param <NewElement> The new element type.
+ *
+ * @param recurPredicate Determines whether to recur into a list or not.
+ * @param elementMapper The mapper on elements.
+ * @param listMapper The mapper on lists we aren't recursing into.
+ *
+ * @return A new list with its elements mapped.
+ */
+ public <NewElement> NestList<NewElement> duckMap(
+ Predicate<NestList<Element>> recurPredicate,
+ Function<Element, NewElement> elementMapper,
+ Function<NestList<Element>, NestList<NewElement>> listMapper)
+ {
+ return map(
+ elementMapper,
+ iftt(recurPredicate,
+ (list) -> list.duckMap(
+ recurPredicate, elementMapper, listMapper),
+ listMapper
+ )
+ );
+ }
+
+ /**
+ * Perform a reduction over this list.
+ *
+ * @param <Output> The type of the output value.
+ *
+ * @param initial The initial state of the output value.
+ * @param elementFolder The function to fold elements with.
+ * @param listFolder The function to fold lists with.
+ *
+ * @return The result of reducing the list.
+ */
+ public <Output> Output reduce(
+ Output initial,
+ BiFunction<Output, Element, Output> elementFolder,
+ BiFunction<Output, NestList<Element>, Output> listFolder)
+ {
+ Holder<Output> out = Holder.of(initial);
+ for (Either<Element, NestList<Element>> item : backing)
+ {
+ out.transform((state) -> item.extract(
+ (ele) -> elementFolder.apply(state, ele),
+ (lst) -> listFolder.apply(state, lst))
+ );
+ }
+
+ return out.getValue();
+ }
+
+ /**
+ * Perform a recursive reduction over this list.
+ *
+ * @param <Output> The type of the output value.
+ *
+ * @param initial The initial state of the output value.
+ * @param elementFolder The function to fold elements with.
+ *
+ * @return The result of recursively reducing the list.
+ */
+ public <Output> Output deepReduce(
+ Output initial,
+ BiFunction<Output, Element, Output> elementFolder)
+ {
+ return reduce(
+ initial,
+ elementFolder,
+ (state, lst) -> lst.deepReduce(state, elementFolder));
+ }
+
+ /**
+ * Conditionally expand elements of this list into the provided list.
+ *
+ * @param nest The list to expand elements into.
+ * @param expandPicker Picks whether or not to expand a list.
+ * @param recur Whether or not to recursively expand lists.
+ *
+ * @return The provided list.
+ */
+ public NestList<Element> expandInto(
+ NestList<Element> nest,
+ Predicate<NestList<Element>> expandPicker,
+ boolean recur)
+ {
+ return reduce(nest,
+ (state, item) -> with(state, (stat) -> stat.addItem(item)),
+ (state, list) -> {
+ if (expandPicker.test(list)) {
+ return list.reduce(nest,
+ (substate, subitem)
+ -> with(substate,
+ (subst) -> subst.addItem(subitem)),
+ (substate, sublist)
+ -> with(substate, (subst) -> {
+ if (recur) {
+ sublist.expandInto(
+ subst,
+ expandPicker,
+ recur);
+ } else {
+ subst.addItem(sublist);
+ }
+ }));
+ } else {
+ state.addItem(list);
+ return state;
+ }
+ });
+ }
+ // List methods and other things.
+
+ @Override
+ public boolean add(Either<Element, NestList<Element>> e) {
+ return backing.add(e);
+ }
+
+ @Override
+ public void add(int index, Either<Element, NestList<Element>> element) {
+ backing.add(index, element);
+ }
+
+ @Override
+ public Either<Element, NestList<Element>> get(int index) {
+ return backing.get(index);
+ }
+
+ @SuppressWarnings("unlikely-arg-type")
+ @Override
+ public boolean remove(Object o) {
+ return backing.remove(o);
+ }
+
+
+ @Override
+ public Either<Element, NestList<Element>> remove(int index) {
+ return backing.remove(index);
+ }
+
+ @Override
+ public int size() {
+ return backing.size();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Objects.hash(backing);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+
+ NestList<?> other = (NestList<?>) obj;
+
+ return Objects.equals(backing, other.backing);
+ }
+}
diff --git a/src/main/java/bjc/esodata/PushdownMap.java b/src/main/java/bjc/esodata/PushdownMap.java
index 54ae939..76dd2db 100644
--- a/src/main/java/bjc/esodata/PushdownMap.java
+++ b/src/main/java/bjc/esodata/PushdownMap.java
@@ -1,12 +1,10 @@
package bjc.esodata;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.*;
+import java.util.function.*;
-import bjc.funcdata.FunctionalMap;
-import bjc.funcdata.IList;
-import bjc.funcdata.IMap;
+import bjc.data.*;
+import bjc.funcdata.*;
/**
* A variant of a map where inserting a duplicate key shadows the existing value
@@ -22,22 +20,22 @@ import bjc.funcdata.IMap;
* @param <ValueType>
* The values in the map.
*/
-public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType> {
+public class PushdownMap<KeyType, ValueType> implements MapEx<KeyType, ValueType> {
/* Our backing storage. */
- private final IMap<KeyType, Stack<ValueType>> backing;
+ private final MapEx<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,30 +43,15 @@ 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()));
}
@Override
- public void forEachKey(final Consumer<KeyType> action) {
- backing.forEachKey(action);
- }
-
- @Override
- public void forEachValue(final Consumer<ValueType> action) {
- backing.forEachValue(stk -> action.accept(stk.top()));
- }
-
- @Override
- public ValueType get(final KeyType key) {
- return backing.get(key).top();
+ public Optional<ValueType> get(final KeyType key) {
+ return backing.get(key).map((stack) -> stack.top());
}
@Override
@@ -77,23 +60,16 @@ public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType>
}
@Override
- public IList<KeyType> keyList() {
+ public ListEx<KeyType> keyList() {
return backing.keyList();
}
@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);
+ final Stack<ValueType> stk = backing.get(key).get();
final ValueType vl = stk.top();
@@ -111,18 +87,19 @@ public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType>
@Override
public ValueType remove(final KeyType key) {
- final Stack<ValueType> stk = backing.get(key);
+ if (isFrozen) throw new ObjectFrozen("Can't remove key " + key + " from frozen map");
- if (stk.size() > 1) {
- return stk.pop();
- }
+ Holder<ValueType> result = Holder.of(null);
+
+ backing.get(key).ifPresent((stk) -> {
+ if (stk.size() > 1) {
+ result.replace(stk.pop());
+ } else {
+ result.replace(backing.remove(key).top());
+ }
+ });
- return backing.remove(key).top();
- }
-
- @Override
- public IList<ValueType> valueList() {
- return backing.valueList().map(Stack::top);
+ return result.getValue();
}
@Override
@@ -137,20 +114,17 @@ public class PushdownMap<KeyType, ValueType> implements IMap<KeyType, ValueType>
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof PushdownMap<?, ?>))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof PushdownMap<?, ?>)) return false;
final PushdownMap<?, ?> other = (PushdownMap<?, ?>) obj;
if (backing == null) {
- if (other.backing != null)
- return false;
- } else if (!backing.equals(other.backing))
+ if (other.backing != null) return false;
+ } else if (!backing.equals(other.backing)) {
return false;
+ }
return true;
}
@@ -159,4 +133,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/esodata/QueueStack.java b/src/main/java/bjc/esodata/QueueStack.java
index c40721a..e310f16 100644
--- a/src/main/java/bjc/esodata/QueueStack.java
+++ b/src/main/java/bjc/esodata/QueueStack.java
@@ -29,16 +29,14 @@ public class QueueStack<T> extends Stack<T> {
@Override
public T pop() {
- if (backing.isEmpty())
- throw new StackUnderflow();
+ if (backing.isEmpty()) throw new StackUnderflow();
return backing.remove();
}
@Override
public T top() {
- if (backing.isEmpty())
- throw new StackUnderflow();
+ if (backing.isEmpty()) throw new StackUnderflow();
return backing.peek();
}
@@ -76,20 +74,17 @@ public class QueueStack<T> extends Stack<T> {
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof QueueStack<?>))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof QueueStack<?>)) return false;
final QueueStack<?> other = (QueueStack<?>) obj;
if (backing == null) {
- if (other.backing != null)
- return false;
- } else if (!backing.equals(other.backing))
+ if (other.backing != null) return false;
+ } else if (!backing.equals(other.backing)) {
return false;
+ }
return true;
}
diff --git a/src/main/java/bjc/esodata/SimpleDirectory.java b/src/main/java/bjc/esodata/SimpleDirectory.java
index 672d92f..13a9f3e 100644
--- a/src/main/java/bjc/esodata/SimpleDirectory.java
+++ b/src/main/java/bjc/esodata/SimpleDirectory.java
@@ -1,7 +1,7 @@
package bjc.esodata;
import bjc.funcdata.FunctionalMap;
-import bjc.funcdata.IMap;
+import bjc.funcdata.MapEx;
/**
* Simple implementation of {@link Directory}.
@@ -18,9 +18,9 @@ import bjc.funcdata.IMap;
*/
public class SimpleDirectory<K, V> implements Directory<K, V> {
/* Our sub-directories. */
- private final IMap<K, Directory<K, V>> children;
+ private final MapEx<K, Directory<K, V>> children;
/* Our data. */
- private final IMap<K, V> data;
+ private final MapEx<K, V> data;
/** Create a new directory. */
public SimpleDirectory() {
@@ -30,7 +30,7 @@ public class SimpleDirectory<K, V> implements Directory<K, V> {
@Override
public Directory<K, V> getSubdirectory(final K key) {
- return children.get(key);
+ return children.get(key).orElse(null);
}
@Override
@@ -50,7 +50,7 @@ public class SimpleDirectory<K, V> implements Directory<K, V> {
@Override
public V getKey(final K key) {
- return data.get(key);
+ return data.get(key).orElse(null);
}
@Override
@@ -71,26 +71,23 @@ public class SimpleDirectory<K, V> implements Directory<K, V> {
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof SimpleDirectory<?, ?>))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof SimpleDirectory<?, ?>)) return false;
final SimpleDirectory<?, ?> other = (SimpleDirectory<?, ?>) obj;
if (children == null) {
- if (other.children != null)
- return false;
- } else if (!children.equals(other.children))
+ if (other.children != null) return false;
+ } else if (!children.equals(other.children)) {
return false;
+ }
if (data == null) {
- if (other.data != null)
- return false;
- } else if (!data.equals(other.data))
+ if (other.data != null) return false;
+ } else if (!data.equals(other.data)) {
return false;
+ }
return true;
}
diff --git a/src/main/java/bjc/esodata/SimpleStack.java b/src/main/java/bjc/esodata/SimpleStack.java
index b50521e..9c016c3 100644
--- a/src/main/java/bjc/esodata/SimpleStack.java
+++ b/src/main/java/bjc/esodata/SimpleStack.java
@@ -27,16 +27,14 @@ public class SimpleStack<T> extends Stack<T> {
@Override
public T pop() {
- if (backing.isEmpty())
- throw new StackUnderflow();
+ if (backing.isEmpty()) throw new StackUnderflow();
return backing.pop();
}
@Override
public T top() {
- if (backing.isEmpty())
- throw new StackUnderflow();
+ if (backing.isEmpty()) throw new StackUnderflow();
return backing.peek();
}
@@ -69,20 +67,17 @@ public class SimpleStack<T> extends Stack<T> {
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof SimpleStack<?>))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof SimpleStack<?>)) return false;
final SimpleStack<?> other = (SimpleStack<?>) obj;
if (backing == null) {
- if (other.backing != null)
- return false;
- } else if (!backing.equals(other.backing))
+ if (other.backing != null) return false;
+ } else if (!backing.equals(other.backing)) {
return false;
+ }
return true;
}
diff --git a/src/main/java/bjc/esodata/SingleTape.java b/src/main/java/bjc/esodata/SingleTape.java
index ec56e2b..7c3a34f 100644
--- a/src/main/java/bjc/esodata/SingleTape.java
+++ b/src/main/java/bjc/esodata/SingleTape.java
@@ -45,9 +45,7 @@ public class SingleTape<T> implements Tape<T> {
backing = new ArrayList<>(vals.length);
- for (T val : vals) {
- backing.add(val);
- }
+ for (T val : vals) backing.add(val);
}
/**
@@ -66,9 +64,7 @@ public class SingleTape<T> implements Tape<T> {
public SingleTape(Iterable<T> itr) {
this(false);
- for (T itm : itr) {
- backing.add(itm);
- }
+ for (T itm : itr) backing.add(itm);
}
/**
@@ -86,8 +82,7 @@ public class SingleTape<T> implements Tape<T> {
@Override
public T item() {
- if (pos < 0 || pos >= backing.size())
- return null;
+ if (pos < 0 || pos >= backing.size()) return null;
return backing.get(pos);
}
@@ -114,19 +109,16 @@ public class SingleTape<T> implements Tape<T> {
@Override
public void insertAfter(final T itm) {
- if (pos == backing.size() - 1) {
- backing.add(itm);
- } else {
- backing.add(pos + 1, itm);
- }
+ if (pos == backing.size() - 1) backing.add(itm);
+ else backing.add(pos + 1, itm);
}
@Override
public T remove() {
final T res = backing.remove(pos);
- if (pos != 0) {
- pos -= 1;
- }
+
+ if (pos != 0) pos -= 1;
+
return res;
}
@@ -147,8 +139,7 @@ public class SingleTape<T> implements Tape<T> {
@Override
public boolean left(final int amt) {
- if (pos - amt < 0)
- return false;
+ if (pos - amt < 0) return false;
pos -= amt;
return true;
@@ -163,11 +154,10 @@ public class SingleTape<T> implements Tape<T> {
public boolean right(final int amt) {
if (pos + amt > backing.size()) {
if (autoExtend) {
- while (pos + amt >= backing.size() - 1) {
- backing.add(null);
- }
- } else
+ while (pos + amt >= backing.size() - 1) backing.add(null);
+ } else {
return false;
+ }
}
pos += amt;
@@ -176,15 +166,15 @@ public class SingleTape<T> implements Tape<T> {
@Override
public boolean seekTo(int tgtPos) {
- if (tgtPos < 0)
- return false;
+ if (tgtPos < 0) return false;
- if (tgtPos >= backing.size() - 1)
- if (autoExtend)
- while (tgtPos >= backing.size() - 1)
- backing.add(null);
- else
+ if (tgtPos >= backing.size() - 1) {
+ if (autoExtend) {
+ while (tgtPos >= backing.size() - 1) backing.add(null);
+ } else {
return false;
+ }
+ }
pos = tgtPos;
@@ -208,20 +198,17 @@ public class SingleTape<T> implements Tape<T> {
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof SingleTape<?>))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof SingleTape<?>)) return false;
final SingleTape<?> other = (SingleTape<?>) obj;
if (backing == null) {
- if (other.backing != null)
- return false;
- } else if (!backing.equals(other.backing))
+ if (other.backing != null) return false;
+ } else if (!backing.equals(other.backing)) {
return false;
+ }
return true;
}
diff --git a/src/main/java/bjc/esodata/SpaghettiStack.java b/src/main/java/bjc/esodata/SpaghettiStack.java
index fc3e154..4bd77d3 100644
--- a/src/main/java/bjc/esodata/SpaghettiStack.java
+++ b/src/main/java/bjc/esodata/SpaghettiStack.java
@@ -37,16 +37,14 @@ class SpaghettiStack<T> extends Stack<T> {
@Override
public T pop() {
- if (backing.isEmpty())
- return parent.pop();
+ if (backing.isEmpty()) return parent.pop();
return backing.pop();
}
@Override
public T top() {
- if (backing.isEmpty())
- return parent.top();
+ if (backing.isEmpty()) return parent.top();
return backing.top();
}
@@ -82,26 +80,23 @@ class SpaghettiStack<T> extends Stack<T> {
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof SpaghettiStack<?>))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof SpaghettiStack<?>)) return false;
final SpaghettiStack<?> other = (SpaghettiStack<?>) obj;
if (backing == null) {
- if (other.backing != null)
- return false;
- } else if (!backing.equals(other.backing))
+ if (other.backing != null) return false;
+ } else if (!backing.equals(other.backing)) {
return false;
+ }
if (parent == null) {
- if (other.parent != null)
- return false;
- } else if (!parent.equals(other.parent))
+ if (other.parent != null) return false;
+ } else if (!parent.equals(other.parent)) {
return false;
+ }
return true;
}
diff --git a/src/main/java/bjc/esodata/Stack.java b/src/main/java/bjc/esodata/Stack.java
index 5ee5ef2..360e57d 100644
--- a/src/main/java/bjc/esodata/Stack.java
+++ b/src/main/java/bjc/esodata/Stack.java
@@ -96,9 +96,7 @@ public abstract class Stack<T> {
* The elements to insert.
*/
public void pushAll(@SuppressWarnings("unchecked") T... elms) {
- for (T elm : elms) {
- push(elm);
- }
+ for (T elm : elms) push(elm);
}
/**
@@ -108,9 +106,7 @@ public abstract class Stack<T> {
* The elements to insert.
*/
public void pushAll(List<T> elms) {
- for (T elm : elms) {
- push(elm);
- }
+ for (T elm : elms) push(elm);
}
/**
@@ -124,9 +120,7 @@ public abstract class Stack<T> {
public List<T> multipop(int n) {
List<T> lst = new LinkedList<>();
- for (int i = 0; i < n; i++) {
- lst.add(pop());
- }
+ for (int i = 0; i < n; i++) lst.add(pop());
return lst;
}
@@ -142,9 +136,7 @@ public abstract class Stack<T> {
public List<T> multipoprev(int n) {
LinkedList<T> lst = new LinkedList<>();
- for (int i = 0; i < n; i++) {
- lst.addFirst(pop());
- }
+ for (int i = 0; i < n; i++) lst.addFirst(pop());
return lst;
}
@@ -160,9 +152,7 @@ public abstract class Stack<T> {
* The number of items to drop.
*/
public void drop(final int n) {
- for (int i = 0; i < n; i++) {
- pop();
- }
+ for (int i = 0; i < n; i++) pop();
}
/** Drop one item from the stack. */
@@ -201,9 +191,7 @@ public abstract class Stack<T> {
public void multidup(final int n, final int m) {
List<T> lst = multipoprev(n);
- for (int i = 0; i <= m; i++) {
- pushAll(lst);
- }
+ for (int i = 0; i <= m; i++) pushAll(lst);
}
/**
@@ -235,15 +223,11 @@ public abstract class Stack<T> {
List<T> lst = multipoprev(n);
- for (final T nelm : lst) {
- push(nelm);
- }
+ for (final T nelm : lst) push(nelm);
push(elm);
- for (int i = 0; i < m; i++) {
- pushAll(lst);
- }
+ for (int i = 0; i < m; i++) pushAll(lst);
}
/**
@@ -555,9 +539,7 @@ public abstract class Stack<T> {
public void multiapply(final int n, final int m, final Consumer<Stack<T>> action) {
final List<Consumer<Stack<T>>> actions = new ArrayList<>(m);
- for (int i = 0; i < m; i++) {
- actions.add(action);
- }
+ for (int i = 0; i < m; i++) actions.add(action);
multispread(n, actions);
}
diff --git a/src/main/java/bjc/esodata/TapeLibrary.java b/src/main/java/bjc/esodata/TapeLibrary.java
new file mode 100644
index 0000000..922833f
--- /dev/null
+++ b/src/main/java/bjc/esodata/TapeLibrary.java
@@ -0,0 +1,163 @@
+package bjc.esodata;
+
+import java.util.*;
+
+/**
+ * Represents a library of possible tapes, with a single tape 'mounted' or active
+ * at a time.
+ *
+ * @author Ben Culkin
+ *
+ * @param <ElementType> The type stored on each tape.
+ */
+public class TapeLibrary<ElementType> implements TapeView<ElementType>
+{
+ private final Map<String, Tape<ElementType>> library;
+
+ private String currentLabel;
+ private Tape<ElementType> currentTape;
+
+ private boolean allowAutoCreation;
+
+ /**
+ * Get a view of this tape library as a map.
+ *
+ * Modifications to this map will apply to the library, but will not
+ * affect whether a given tape is mounted or not. Be forewarned.
+ *
+ * @return A view onto this tape library as a map.
+ */
+ public Map<String, Tape<ElementType>> asMap()
+ {
+ return library;
+ }
+
+ /**
+ * Create a new empty tape library, with no tape mounted.
+ */
+ public TapeLibrary()
+ {
+ library = new HashMap<>();
+ }
+
+ /**
+ * Create a new tape, with a given tape mounted by default.
+ *
+ * @param label The label of the tape.
+ * @param tape The tape to mount.
+ */
+ public TapeLibrary(String label, Tape<ElementType> tape)
+ {
+ this();
+ library.put(label, tape);
+
+ this.currentLabel = label;
+ this.currentTape = tape;
+ }
+
+ @Override
+ public Tape<ElementType> tapeView()
+ {
+ return currentTape;
+ }
+
+ /**
+ * Insert a tape into this library.
+ *
+ * @param label The label to use for the tape.
+ * @param tape The tape to add.
+ *
+ * @return The tape which previously had that label, or null if there was not one.
+ */
+ public Tape<ElementType> insertTape(String label, Tape<ElementType> tape)
+ {
+ return library.put(label, tape);
+ }
+
+ /**
+ * Remove a tape from this library.
+ *
+ * @param label The label of the tape to remove.
+ *
+ * @return The tape which had that label, or null if there was not one.
+ */
+ public Tape<ElementType> removeTape(String label)
+ {
+ return library.remove(label);
+ }
+
+ /**
+ * Check if this library has a tape with a given label.
+ *
+ * @param label The label of the tape to check for.
+ *
+ * @return Whether or not the library contains a tape with that label.
+ */
+ public boolean hasTape(String label)
+ {
+ return allowAutoCreation ? true : library.containsKey(label);
+ }
+
+ /**
+ * Mount a different tape in the library.
+ *
+ * @param label The label of the tape to mount.
+ *
+ * @return True if the tape was successfully mounted, false otherwise.
+ */
+ public boolean mountTape(String label)
+ {
+ if (library.containsKey(label) || allowAutoCreation)
+ {
+ currentLabel = label;
+ currentTape = library.computeIfAbsent(
+ label,
+ (ignored) -> new SingleTape<>());
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the label of the current tape.
+ *
+ * @return The label of the current tape, or null if no tape is
+ * currently 'mounted'.
+ */
+ public String currentLabel()
+ {
+ return currentLabel;
+ }
+
+ /**
+ * Unmount the currently mounted tape.
+ */
+ public void ejectTape()
+ {
+ currentTape = null;
+ currentLabel = null;
+ }
+
+ /**
+ * Check if this tape library currently allows auto-creation of
+ * non-existing tapes.
+ *
+ * @return Whether or not auto-creation of tapes is currently allowed.
+ */
+ public boolean isAllowAutoCreation() {
+ return allowAutoCreation;
+ }
+
+ /**
+ * Set whether or not this library allows auto-creation of non-existing
+ * tapes.
+ *
+ * @param allowAutoCreation Whether tape auto-creation is allowed.
+ */
+ public void setAllowAutoCreation(boolean allowAutoCreation)
+ {
+ this.allowAutoCreation = allowAutoCreation;
+ }
+}
diff --git a/src/main/java/bjc/esodata/TapeView.java b/src/main/java/bjc/esodata/TapeView.java
new file mode 100644
index 0000000..bfc33a9
--- /dev/null
+++ b/src/main/java/bjc/esodata/TapeView.java
@@ -0,0 +1,102 @@
+package bjc.esodata;
+
+/**
+ * An interface which allows you to view a given type as a tape.
+ *
+ * @author Ben Culkin
+ *
+ * @param <ElementType> The type of element contained in the tape.
+ */
+public interface TapeView<ElementType> extends Tape<ElementType>
+{
+ /**
+ * Return a view of this object as a tape.
+ *
+ * @return A view of this object as a tape.
+ */
+ public Tape<ElementType> tapeView();
+
+ @Override
+ public default ElementType item()
+ {
+ return tapeView().item();
+ }
+
+ @Override
+ public default void item(ElementType itm)
+ {
+ tapeView().item(itm);
+ }
+
+ @Override
+ public default int size()
+ {
+ return tapeView().size();
+ }
+
+ @Override
+ public default int position()
+ {
+ return tapeView().position();
+ }
+
+ @Override
+ public default void insertBefore(ElementType itm)
+ {
+ tapeView().insertBefore(itm);
+ }
+
+ @Override
+ public default void insertAfter(ElementType itm)
+ {
+ tapeView().insertAfter(itm);
+ }
+
+ @Override
+ public default ElementType remove()
+ {
+ return tapeView().remove();
+ }
+
+ @Override
+ public default void first()
+ {
+ tapeView().first();
+ }
+
+ @Override
+ public default void last()
+ {
+ tapeView().last();
+ }
+
+ @Override
+ public default boolean left()
+ {
+ return tapeView().left();
+ }
+
+ @Override
+ public default boolean left(int amt)
+ {
+ return tapeView().left(amt);
+ }
+
+ @Override
+ public default boolean right()
+ {
+ return tapeView().right();
+ }
+
+ @Override
+ public default boolean right(int amt)
+ {
+ return tapeView().right(amt);
+ }
+
+ @Override
+ public default boolean seekTo(int pos)
+ {
+ return tapeView().seekTo(pos);
+ }
+}
diff --git a/src/main/java/bjc/esodata/ThresholdSet.java b/src/main/java/bjc/esodata/ThresholdSet.java
index ae277e1..9b8560b 100644
--- a/src/main/java/bjc/esodata/ThresholdSet.java
+++ b/src/main/java/bjc/esodata/ThresholdSet.java
@@ -37,8 +37,7 @@ 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;
}
@@ -52,8 +51,7 @@ 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;
}
@@ -67,8 +65,7 @@ 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;
}
@@ -112,9 +109,7 @@ public class ThresholdSet<KeyType> {
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;
}
@@ -162,9 +157,7 @@ public class ThresholdSet<KeyType> {
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;
}
@@ -217,9 +210,7 @@ public class ThresholdSet<KeyType> {
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;
}
@@ -233,12 +224,9 @@ public class ThresholdSet<KeyType> {
* @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;
-
- return keyMap.get(key);
+ if (keySet.contains(key)) return 1;
+ if (!keyMap.containsKey(key)) return -1;
+ else return keyMap.get(key);
}
/**
diff --git a/src/main/java/bjc/esodata/UnifiedDirectory.java b/src/main/java/bjc/esodata/UnifiedDirectory.java
index 2221615..1b630eb 100644
--- a/src/main/java/bjc/esodata/UnifiedDirectory.java
+++ b/src/main/java/bjc/esodata/UnifiedDirectory.java
@@ -1,7 +1,7 @@
package bjc.esodata;
import bjc.funcdata.FunctionalMap;
-import bjc.funcdata.IMap;
+import bjc.funcdata.MapEx;
/**
* Simple implementation of {@link Directory}.
@@ -18,9 +18,9 @@ import bjc.funcdata.IMap;
*/
public class UnifiedDirectory<K, V> implements Directory<K, V> {
/* Our directory children. */
- private final IMap<K, Directory<K, V>> children;
+ private final MapEx<K, Directory<K, V>> children;
/* Our data children. */
- private final IMap<K, V> data;
+ private final MapEx<K, V> data;
/** Create a new directory. */
public UnifiedDirectory() {
@@ -30,7 +30,7 @@ public class UnifiedDirectory<K, V> implements Directory<K, V> {
@Override
public Directory<K, V> getSubdirectory(final K key) {
- return children.get(key);
+ return children.get(key).orElse(null);
}
@Override
@@ -56,7 +56,7 @@ public class UnifiedDirectory<K, V> implements Directory<K, V> {
@Override
public V getKey(final K key) {
- return data.get(key);
+ return data.get(key).orElse(null);
}
@Override
@@ -82,26 +82,23 @@ public class UnifiedDirectory<K, V> implements Directory<K, V> {
@Override
public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof UnifiedDirectory<?, ?>))
- return false;
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof UnifiedDirectory<?, ?>)) return false;
final UnifiedDirectory<?, ?> other = (UnifiedDirectory<?, ?>) obj;
if (children == null) {
- if (other.children != null)
- return false;
- } else if (!children.equals(other.children))
+ if (other.children != null) return false;
+ } else if (!children.equals(other.children)) {
return false;
+ }
if (data == null) {
- if (other.data != null)
- return false;
- } else if (!data.equals(other.data))
+ if (other.data != null) return false;
+ } else if (!data.equals(other.data)) {
return false;
+ }
return true;
}