//Dstl (c) Crown Copyright 2017 package uk.gov.dstl.baleen.uima.grammar; import java.util.stream.Stream; import uk.gov.dstl.baleen.types.language.WordToken; /** * An immutable stack. * * @param <T> * the generic type */ public class ImmutableStack<T> { private final T head; private final ImmutableStack<T> tail; /** * Instantiates a new immutable stack. */ public ImmutableStack() { this(null, null); } /** * Instantiates a new immutable stack, with a head. * * @param head * the head */ public ImmutableStack(T head) { this(head, null); } /** * Instantiates a new non-empty immutable stack. * * @param head * the head * @param tail * the tail */ private ImmutableStack(T head, ImmutableStack<T> tail) { this.head = head; this.tail = tail; } /** * Checks if empty. * * @return true, if empty */ public boolean isEmpty() { return head == null && tail == null; } /** * Size of the stack (number of elements on the stack). * * @return the int */ public int size() { // TODO: This should not be recursive since it might cause a stack overflow, but out sizes // are small at the moment return (head == null ? 0 : 1) + (tail == null ? 0 : tail.size()); } /** * Gets the head. * * @return the head */ public T getHead() { return head; } /** * Gets the tail. * * @return the tail */ public ImmutableStack<T> getTail() { return tail; } /** * Push onto the stack. * * @param t * the t * @return the immutable stack */ public ImmutableStack<T> push(T t) { if (t == null) { return this; } else { return new ImmutableStack<>(t, this); } } /** * Pop from the stack. * * @return the immutable stack */ public ImmutableStack<T> pop() { return tail; } /** * Stream all the content of the stack (LIFO order). * * @return the stream */ public Stream<T> stream() { if (head == null) { return Stream.empty(); } else if (tail == null) { return Stream.of(head); } else { return Stream.concat(Stream.of(head), tail.stream()); } } /** * Does the stack contain the value other?. * * @param other * the other * @return true, if successful */ public boolean contains(WordToken other) { return head != null && head.equals(other) || tail != null && tail.contains(other); } }