package bjc.utils.esodata; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; /** * A stack, with support for combinators. * * A FILO stack with support for forth/factor style combinators. * *

*

Stack underflow

*

* NOTE: In general, using any operation that attempts to remove more data from * the stack than exists will cause a {@link StackUnderflowException} 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 StackUnderflowException extends RuntimeException { /** * */ 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 abstract boolean empty(); /** * 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); } /* * 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) { final List lst = new ArrayList<>(n); for (int i = n; i > 0; i--) { lst.set(i - 1, pop()); } for (int i = 0; i < m; i++) { for (final T elm : lst) { push(elm); } } } /** * Duplicate the top n items of the stack. * * @param n * The number of items to duplicate. */ public void dup(final int n) { multidup(n, 2); } /** * 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) { final List lst = new ArrayList<>(n); final T elm = pop(); for (int i = n; i > 0; i--) { lst.set(i - 1, pop()); } for (final T nelm : lst) { push(nelm); } push(elm); for (int i = 1; i < m; i++) { for (final T nelm : lst) { push(nelm); } } } /** * Duplicate the n elements below the top one. * * @param n * The number of items to duplicate. */ public void over(final int n) { multiover(n, 2); } /** * 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); } /** * Swap the top two items on the stack. */ public void swap() { final T y = pop(); final T x = pop(); push(y); push(x); } /** * 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() { final T z = pop(); final T y = pop(); final T x = pop(); push(y); push(x); push(z); } /** * 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 cons. * * @param n * The number of elements to hide. * @param cons * The action to hide the elements from */ public void dip(final int n, final Consumer> cons) { final List elms = new ArrayList<>(n); for (int i = n; i > 0; i--) { elms.set(i - 1, pop()); } cons.accept(this); for (final T elm : elms) { push(elm); } } /** * Hide the top element of the stack from cons. * * @param cons * The action to hide the top from */ public void dip(final Consumer> cons) { dip(1, cons); } /** * Copy the top n elements on the stack, replacing them once cons is * done. * * @param n * The number of elements to copy. * @param cons * The action to execute. */ public void keep(final int n, final Consumer> cons) { dup(n); dip(n, cons); } /** * Apply all the actions in conses to the top n elements of the stack. * * @param n * The number of elements to give to cons. * @param conses * The actions to execute. */ public void multicleave(final int n, final List>> conses) { final List elms = new ArrayList<>(n); for (int i = n; i > 0; i--) { elms.set(i - 1, pop()); } for (final Consumer> cons : conses) { for (final T elm : elms) { push(elm); } cons.accept(this); } } /** * Apply all the actions in conses to the top element of the stack. * * @param conses * The actions to execute. */ public void cleave(final List>> conses) { multicleave(1, conses); } /** * Apply every action in cons to n arguments. * * @param n * The number of parameters each action takes. * @param conses * The actions to execute. */ public void multispread(final int n, final List>> conses) { final List> nelms = new ArrayList<>(conses.size()); for (int i = conses.size(); i > 0; i--) { final List elms = new ArrayList<>(n); for (int j = n; j > 0; j--) { elms.set(j, pop()); } nelms.set(i, elms); } int i = 0; for (final List elms : nelms) { for (final T elm : elms) { push(elm); } conses.get(i).accept(this); i += 1; } } /** * Apply the actions in cons to corresponding elements from the stack. * * @param conses * The actions to execute. */ public void spread(final List>> conses) { multispread(1, conses); } /** * Apply the action in cons 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 cons * The action to execute. */ public void multiapply(final int n, final int m, final Consumer> cons) { final List>> conses = new ArrayList<>(m); for (int i = 0; i < m; i++) { conses.add(cons); } multispread(n, conses); } /** * Apply cons n times to the corresponding elements in the stack. * * @param n * The number of times to execute cons. * @param cons * The action to execute. */ public void apply(final int n, final Consumer> cons) { multiapply(1, n, cons); } /* * Misc. functions */ /** * Get an array representing this stack. * * @return The stack as an array. */ public abstract T[] toArray(); }