summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/bjc/esodata/Stack.java274
-rw-r--r--src/test/java/bjc/TestUtils.java15
-rw-r--r--src/test/java/bjc/esodata/StackTest.java153
3 files changed, 331 insertions, 111 deletions
diff --git a/src/main/java/bjc/esodata/Stack.java b/src/main/java/bjc/esodata/Stack.java
index f28e882..1a15764 100644
--- a/src/main/java/bjc/esodata/Stack.java
+++ b/src/main/java/bjc/esodata/Stack.java
@@ -47,18 +47,6 @@ public abstract class Stack<T> {
public abstract void push(T elm);
/**
- * Push multiple elements onto the stack.
- *
- * @param elms
- * The elements to insert.
- */
- public void pushAll(T... elms) {
- for (T elm : elms) {
- push(elm);
- }
- }
-
- /**
* Pop an element off of the stack.
*
* @return The element on top of the stack.
@@ -99,6 +87,70 @@ public abstract class Stack<T> {
}
/*
+ * Multi-item add/remove.
+ */
+
+ /**
+ * Push multiple elements onto the stack.
+ *
+ * @param elms
+ * The elements to insert.
+ */
+ public void pushAll(T... elms) {
+ for (T elm : elms) {
+ push(elm);
+ }
+ }
+
+ /**
+ * Push multiple elements onto the stack.
+ *
+ * @param elms
+ * The elements to insert.
+ */
+ public void pushAll(List<T> elms) {
+ for (T elm : elms) {
+ push(elm);
+ }
+ }
+
+ /**
+ * Pop n items off of the stack and return them.
+ *
+ * @param n
+ * The number of items to pop off of the stack.
+ *
+ * @return A list of the popped items, in the order they were popped.
+ */
+ public List<T> multipop(int n) {
+ List<T> lst = new LinkedList<>();
+
+ for (int i = 0; i < n; n++) {
+ lst.add(pop());
+ }
+
+ return lst;
+ }
+
+ /**
+ * Pop n items off of the stack and return them.
+ *
+ * @param n
+ * The number of items to pop off of the stack.
+ *
+ * @return A list of the popped items, in the reverse order they were popped.
+ */
+ public List<T> multipoprev(int n) {
+ LinkedList<T> lst = new LinkedList<>();
+
+ for (int i = 0; i < n; i++) {
+ lst.addFirst(pop());
+ }
+
+ return lst;
+ }
+
+ /*
* Basic combinators
*/
@@ -148,16 +200,10 @@ public abstract class Stack<T> {
* The number of times to duplicate items.
*/
public void multidup(final int n, final int m) {
- final List<T> lst = new ArrayList<>(n);
-
- for(int i = n; i > 0; i--) {
- lst.add(0, pop());
- }
+ List<T> lst = multipoprev(n);
for(int i = 0; i <= m; i++) {
- for(final T elm : lst) {
- push(elm);
- }
+ pushAll(lst);
}
}
@@ -186,23 +232,18 @@ public abstract class Stack<T> {
* The number of times to duplicate items.
*/
public void multiover(final int n, final int m) {
- final List<T> lst = new ArrayList<>(n);
+ T elm = pop();
- final T elm = pop();
-
- for(int i = n; i > 0; i--) {
- lst.set(i - 1, pop());
- }
+ List<T> lst = multipoprev(n);
for(final T nelm : lst) {
push(nelm);
}
+
push(elm);
- for(int i = 1; i < m; i++) {
- for(final T nelm : lst) {
- push(nelm);
- }
+ for(int i = 0; i < m; i++) {
+ pushAll(lst);
}
}
@@ -213,7 +254,7 @@ public abstract class Stack<T> {
* The number of items to duplicate.
*/
public void over(final int n) {
- multiover(n, 2);
+ multiover(n, 1);
}
/** Duplicate the second item in the stack. */
@@ -233,13 +274,44 @@ public abstract class Stack<T> {
push(x);
}
+ /**
+ * Rotate the n items m deep on the stack i positions.
+ *
+ * @param n
+ * The number of items to rotate.
+ * @param m
+ * The number of positions the item is down in the stack.
+ * @param i
+ * The number of steps to rotate. Pass a negative number to rotate things in the opposite
+ * direction.
+ */
+ public void deepmultirot(int n, int m, int i) {
+ List<T> kep = multipoprev(m);
+
+ List<T> lst = multipoprev(n);
+
+ Collections.rotate(lst, i);
+
+ pushAll(lst);
+ pushAll(kep);
+ }
+
+ /**
+ * Rotate the n items on top of the stack i positions.
+ *
+ * @param n
+ * The number of items to rotate.
+ * @param i
+ * The number of steps to rotate. Pass a negative number to rotate things in the opposite
+ * direction.
+ */
+ public void multirot(int n, int i) {
+ deepmultirot(n, 0, i);
+ }
+
/** Swap the top two items on the stack. */
public void swap() {
- final T y = pop();
- final T x = pop();
-
- push(y);
- push(x);
+ multirot(2, 1);
}
/** Duplicate the second item below the first item. */
@@ -254,16 +326,12 @@ public abstract class Stack<T> {
/** Swap the second and third items in the stack. */
public void deepswap() {
- final T z = pop();
- final T y = pop();
- final T x = pop();
-
- push(y);
- push(x);
- push(z);
+ deepmultirot(2, 1, 1);
}
- /** Rotate the top three items on the stack */
+ /**
+ * Rotate the top three items on the stack
+ */
public void rot() {
final T z = pop();
final T y = pop();
@@ -286,10 +354,6 @@ public abstract class Stack<T> {
}
/*
- * :StackCombinators Add a general rotate/roll operator.
- */
-
- /*
* Dataflow Combinators
*/
@@ -303,17 +367,11 @@ public abstract class Stack<T> {
* The action to hide the elements from
*/
public void dip(final int n, final Consumer<Stack<T>> action) {
- final List<T> elms = new ArrayList<>(n);
-
- for(int i = n; i > 0; i--) {
- elms.set(i - 1, pop());
- }
+ List<T> elms = multipoprev(n);
action.accept(this);
- for(final T elm : elms) {
- push(elm);
- }
+ pushAll(elms);
}
/**
@@ -337,14 +395,23 @@ public abstract class Stack<T> {
* The action to execute.
*/
public void keep(final int n, final Consumer<Stack<T>> action) {
- /*
- * @NOTE Is this correct?
- */
dup(n);
+
dip(n, action);
}
/**
+ * Copy the first element on the stack, replacing them once an action
+ * is done.
+ *
+ * @param action
+ * The action to execute.
+ */
+ public void keep(final Consumer<Stack<T>> action) {
+ keep(1, action);
+ }
+
+ /**
* Apply all the actions in a list to the top n elements of the stack.
*
* @param n
@@ -354,16 +421,29 @@ public abstract class Stack<T> {
* The actions to execute.
*/
public void multicleave(final int n, final List<Consumer<Stack<T>>> actions) {
- final List<T> elms = new ArrayList<>(n);
+ List<T> elms = multipoprev(n);
- for(int i = n; i > 0; i--) {
- elms.set(i - 1, pop());
+ for(final Consumer<Stack<T>> action : actions) {
+ pushAll(elms);
+
+ action.accept(this);
}
+ }
+
+ /**
+ * Apply all the actions in a list to the top n elements of the stack.
+ *
+ * @param n
+ * The number of elements to give to cons.
+ *
+ * @param actions
+ * The actions to execute.
+ */
+ public void multicleave(final int n, final Consumer<Stack<T>>... actions) {
+ List<T> elms = multipoprev(n);
for(final Consumer<Stack<T>> action : actions) {
- for(final T elm : elms) {
- push(elm);
- }
+ pushAll(elms);
action.accept(this);
}
@@ -380,6 +460,16 @@ public abstract class Stack<T> {
}
/**
+ * Apply all the actions in a list to the top element of the stack.
+ *
+ * @param actions
+ * The actions to execute.
+ */
+ public void cleave(final Consumer<Stack<T>>... actions) {
+ multicleave(1, actions);
+ }
+
+ /**
* Apply every action in a list of actions to n arguments.
*
* @param n
@@ -389,26 +479,45 @@ public abstract class Stack<T> {
* The actions to execute.
*/
public void multispread(final int n, final List<Consumer<Stack<T>>> actions) {
- final List<List<T>> nelms = new ArrayList<>(actions.size());
+ List<List<T>> nelms = new LinkedList<>();
+
+ for (int i = 0; i < actions.size(); i++) {
+ List<T> elms = multipoprev(n);
+
+ nelms.add(elms);
+ }
+
+ Iterator<Consumer<Stack<T>>> itr = actions.iterator();
+ for(final List<T> elms : nelms) {
+ pushAll(elms);
+
+ itr.next().accept(this);
+ }
+ }
- for(int i = actions.size(); i > 0; i--) {
- final List<T> elms = new ArrayList<>(n);
+ /**
+ * Apply every action in a list of actions to n arguments.
+ *
+ * @param n
+ * The number of parameters each action takes.
+ *
+ * @param actions
+ * The actions to execute.
+ */
+ public void multispread(final int n, final Consumer<Stack<T>>... actions) {
+ List<List<T>> nelms = new LinkedList<>();
- for(int j = n; j > 0; j--) {
- elms.set(j, pop());
- }
+ for (int i = 0; i < actions.length; i++) {
+ List<T> elms = multipoprev(n);
- nelms.set(i, elms);
+ nelms.add(elms);
}
int i = 0;
for(final List<T> elms : nelms) {
- for(final T elm : elms) {
- push(elm);
- }
+ pushAll(elms);
- actions.get(i).accept(this);
- i += 1;
+ actions[i++].accept(this);
}
}
@@ -424,6 +533,17 @@ public abstract class Stack<T> {
}
/**
+ * Apply the actions in a list of actions to corresponding elements from
+ * the stack.
+ *
+ * @param conses
+ * The actions to execute.
+ */
+ public void spread(final Consumer<Stack<T>>... conses) {
+ multispread(1, conses);
+ }
+
+ /**
* Apply an action to the first m groups of n arguments.
*
* @param n
diff --git a/src/test/java/bjc/TestUtils.java b/src/test/java/bjc/TestUtils.java
index a8cbf43..c325877 100644
--- a/src/test/java/bjc/TestUtils.java
+++ b/src/test/java/bjc/TestUtils.java
@@ -130,4 +130,19 @@ public class TestUtils {
assertEquals(exp, act);
}
}
+
+ /**
+ * Assert a stack has the given contents.
+ *
+ * @param <T>
+ * The type of items in the stack.
+ *
+ * @param src
+ * The stack to inspect.
+ * @param exps
+ * The values that are expected.
+ */
+ public static <T> void assertStackEquals(bjc.esodata.Stack<T> src, T... exps) {
+ assertArrayEquals(exps, src.toArray());
+ }
}
diff --git a/src/test/java/bjc/esodata/StackTest.java b/src/test/java/bjc/esodata/StackTest.java
index 568e6ea..8603a8f 100644
--- a/src/test/java/bjc/esodata/StackTest.java
+++ b/src/test/java/bjc/esodata/StackTest.java
@@ -92,61 +92,146 @@ public class StackTest {
st.drop();
- // stack should be [a, b, c]
-
- assertEquals("c", st.top());
- assertEquals(3, st.size());
+ // assertStackEquals goes from [top] -> [bottom]
+ assertStackEquals(st, "c", "b", "a");
st.drop(2);
- // stack should be [a]
-
- assertEquals("a", st.top());
- assertEquals(1, st.size());
+ assertStackEquals(st, "a");
st.pushAll("b", "c", "d");
st.nip();
st.nip();
- // stack should be [a, d]
- assertEquals("d", st.top());
- assertEquals(2, st.size());
-
- st.pop();
+ assertStackEquals(st, "d", "a");
- assertEquals("a", st.top());
- assertEquals(1, st.size());
+ st.drop();
- st.multidup(1, 1);
+ st.dup();
- // stack should be [a, a]
- assertEquals("a", st.top());
- assertEquals(2, st.size());
+ assertStackEquals(st, "a", "a");
st.pushAll("b", "c");
st.multidup(3, 1);
- // stack should be [a, a, b, c, a, b, c]
- assertEquals("c", st.top());
- assertEquals(7, st.size());
+ assertStackEquals(st, "c", "b", "a", "c", "b", "a", "a");
- st.pop();
- assertEquals("b", st.pop());
- assertEquals("a", st.pop());
- assertEquals("c", st.top());
+ st.drop(3);
- // stack should be [a, a, b, c]
+ assertStackEquals(st, "c", "b", "a", "a");
- st.dup();
- assertEquals("c", st.top());
- assertEquals(5, st.size());
+ st.over();
- // stack should be [a, a, b, c, c]
- assertEquals("c", st.pop());
- assertEquals(4, st.size());
+ assertStackEquals(st, "b", "c", "b", "a", "a");
+
+ st.drop(2);
+
+ assertStackEquals(st, "b", "a", "a");
+
+ st.multiover(2, 2);
+
+ assertStackEquals(st, "a", "a", "a", "a", "b", "a", "a");
+
+ st.drop(6);
+
+ assertStackEquals(st, "a");
+
+ st.push("b");
+ st.push("c");
+
+ assertStackEquals(st, "c", "b", "a");
+
+ st.pick();
+
+ assertStackEquals(st, "a", "c", "b", "a");
+
+ st.swap();
+
+ assertStackEquals(st, "c", "a", "b", "a");
+
+ st.deepdup();
+
+ assertStackEquals(st, "c", "a", "a", "b", "a");
+
+ st.swap();
+ st.deepswap();
+
+ assertStackEquals(st, "a", "a", "c", "b", "a");
+
+ st.rot();
+
+ assertStackEquals(st, "c", "a", "a", "b", "a");
+
+ st.invrot();
+
+ assertStackEquals(st, "a", "a", "c", "b", "a");
+ }
+
+ @Test
+ public void testDataComb() {
+ Stack<Integer> stk = new SimpleStack<>();
+
+ stk.pushAll(2, 3, 4);
+
+ assertStackEquals(stk, 4, 3, 2);
+
+ stk.dip((st) -> {
+ int x = stk.pop();
+ int y = stk.pop();
+
+ stk.push(x + y);
+ });
+
+ assertStackEquals(stk, 4, 5);
+
+ stk.dip(2, (st) -> {
+ stk.push(6);
+ });
+
+ assertStackEquals(stk, 4, 5, 6);
+
+ stk.keep((st) -> {
+ int v = st.pop();
+
+ st.push(v + 1);
+ });
+
+ assertStackEquals(stk, 4, 5, 5, 6);
+
+ stk.multicleave(2, (st) -> {
+ int x = st.pop();
+ int y = st.pop();
+
+ st.push(x + y);
+ }, (st) -> {
+ int x = st.pop();
+ int y = st.pop();
+
+ st.push(y - x);
+ });
+
+ assertStackEquals(stk, 1, 9, 5, 6);
+
+ stk.spread((st) -> {
+ int x = st.pop();
+ int y = st.pop();
+
+ st.push(x + y);
+ }, (st) -> {
+ int y = st.pop();
+
+ st.push(y + 1);
+ });
+
+ assertStackEquals(stk, 10, 6, 6);
+
+ stk.apply(2, (st) -> {
+ int lhs = st.pop();
+ st.push(lhs - st.pop());
+ });
- // stack should be [a, a, b, c]
+ assertStackEquals(stk, 2);
}
}