package bjc.esodata; import java.util.*; import java.util.function.*; /* * @TODO 10/11/17 Ben Culkin :StackCombinators * Implement more combinators for the stack. */ /** * A stack, with support for forth/factor style stack combinators. * *

*

Stack underflow

*

* NOTE: In general, using any operation that attempts to remove more data from * the stack than exists will cause a {@link StackUnderflow} to be * thrown. Check the size of the stack if you want to avoid this. *

*

* * @param * The datatype stored in the stack. * * @author Ben Culkin */ public abstract class Stack { /** * The exception thrown when attempting to access an element from the * stack that isn't there. * * @author EVE */ public static class StackUnderflow extends RuntimeException { /* The ID of the exception */ private static final long serialVersionUID = 1423867176204571539L; } /** * Push an element onto the stack. * * @param elm * The element to insert. */ public abstract void push(T elm); /** * Pop an element off of the stack. * * @return The element on top of the stack. */ public abstract T pop(); /** * Retrieve the top element of this stack without removing it from the * stack. * * @return The top element of this stack. */ public abstract T top(); /** * Get the number of elements in the stack. * * @return the number of elements in the stack. */ public abstract int size(); /** * Check if the stack is empty. * * @return Whether or not the stack is empty. */ public boolean isEmpty() { return size() == 0; } /** * Create a spaghetti stack branching off of this one. * * @return A spaghetti stack with this stack as a parent. */ public Stack spaghettify() { return new SpaghettiStack<>(this); } /* * 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 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 multipop(int n) { List 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 multipoprev(int n) { LinkedList lst = new LinkedList<>(); for (int i = 0; i < n; i++) { lst.addFirst(pop()); } return lst; } /* * Basic combinators */ /** * Drop n items from the stack. * * @param n * The number of items to drop. */ public void drop(final int n) { for(int i = 0; i < n; i++) { pop(); } } /** Drop one item from the stack. */ public void drop() { drop(1); } /** * Delete n items below the current one. * * @param n * The number of items below the top to delete. */ public void nip(final int n) { final T elm = pop(); drop(n); push(elm); } /** Delete the second element in the stack. */ public void nip() { nip(1); } /** * Replicate the top n items of the stack m times. * * @param n * The number of items to duplicate. * * @param m * The number of times to duplicate items. */ public void multidup(final int n, final int m) { List lst = multipoprev(n); for(int i = 0; i <= m; i++) { pushAll(lst); } } /** * Duplicate the top n items of the stack. * * @param n * The number of items to duplicate. */ public void dup(final int n) { multidup(n, 1); } /** Duplicate the top item on the stack. */ public void dup() { dup(1); } /** * Replicate the n elements below the top one m times. * * @param n * The number of items to duplicate. * * @param m * The number of times to duplicate items. */ public void multiover(final int n, final int m) { T elm = pop(); List lst = multipoprev(n); for(final T nelm : lst) { push(nelm); } push(elm); for(int i = 0; i < m; i++) { pushAll(lst); } } /** * Duplicate the n elements below the top one. * * @param n * The number of items to duplicate. */ public void over(final int n) { multiover(n, 1); } /** Duplicate the second item in the stack. */ public void over() { over(1); } /** Duplicate the third item in the stack. */ public void pick() { final T z = pop(); final T y = pop(); final T x = pop(); push(x); push(y); push(z); 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 kep = multipoprev(m); List 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() { multirot(2, 1); } /** Duplicate the second item below the first item. */ public void deepdup() { final T y = pop(); final T x = pop(); push(x); push(x); push(y); } /** Swap the second and third items in the stack. */ public void deepswap() { deepmultirot(2, 1, 1); } /** * Rotate the top three items on the stack */ public void rot() { final T z = pop(); final T y = pop(); final T x = pop(); push(y); push(z); push(x); } /** Inversely rotate the top three items on the stack */ public void invrot() { final T z = pop(); final T y = pop(); final T x = pop(); push(z); push(x); push(y); } /* * Dataflow Combinators */ /** * Hides the top n elements on the stack from an action. * * @param n * The number of elements to hide. * * @param action * The action to hide the elements from */ public void dip(final int n, final Consumer> action) { List elms = multipoprev(n); action.accept(this); pushAll(elms); } /** * Hide the top element of the stack from an action. * * @param action * The action to hide the top from */ public void dip(final Consumer> action) { dip(1, action); } /** * Copy the top n elements on the stack, replacing them once an action * is done. * * @param n * The number of elements to copy. * * @param action * The action to execute. */ public void keep(final int n, final Consumer> action) { 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> action) { keep(1, action); } /** * 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 List>> actions) { List elms = multipoprev(n); for(final Consumer> 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>... actions) { List elms = multipoprev(n); for(final Consumer> action : actions) { pushAll(elms); action.accept(this); } } /** * Apply all the actions in a list to the top element of the stack. * * @param actions * The actions to execute. */ public void cleave(final List>> actions) { multicleave(1, actions); } /** * 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>... actions) { multicleave(1, actions); } /** * 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 List>> actions) { List> nelms = new LinkedList<>(); for (int i = 0; i < actions.size(); i++) { List elms = multipoprev(n); nelms.add(elms); } Iterator>> itr = actions.iterator(); for(final List elms : nelms) { pushAll(elms); itr.next().accept(this); } } /** * 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>... actions) { List> nelms = new LinkedList<>(); for (int i = 0; i < actions.length; i++) { List elms = multipoprev(n); nelms.add(elms); } int i = 0; for(final List elms : nelms) { pushAll(elms); actions[i++].accept(this); } } /** * Apply the actions in a list of actions to corresponding elements from * the stack. * * @param conses * The actions to execute. */ public void spread(final List>> conses) { multispread(1, conses); } /** * 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>... conses) { multispread(1, conses); } /** * Apply an action to the first m groups of n arguments. * * @param n * The number of arguments cons takes. * * @param m * The number of time to call cons. * * @param action * The action to execute. */ public void multiapply(final int n, final int m, final Consumer> action) { final List>> actions = new ArrayList<>(m); for(int i = 0; i < m; i++) { actions.add(action); } multispread(n, actions); } /** * Apply an action n times to the corresponding elements in the stack. * * @param n * The number of times to execute cons. * * @param action * The action to execute. */ public void apply(final int n, final Consumer> action) { multiapply(1, n, action); } /* * Misc. functions */ /** * Get an array representing this stack. * * @return The stack as an array. */ public abstract T[] toArray(); }