edu.stanford.nlp.util.TreeShapedStack Maven / Gradle / Ivy
package edu.stanford.nlp.util;
import java.util.Collections;
import java.util.EmptyStackException;
import java.util.List;
/**
* Represents a stack where one prefix of the stack can branch in
* several directions. Calling "push" on this object returns a new
* object which points to the previous state. Calling "pop" returns a
* pointer to the previous state. The only way to access the current
* node's information is with "peek".
*
* Note that if you have an earlier node in the tree, you have no way
* of recovering later nodes. It is essential to keep the ends of the
* stack you are interested in.
*/
public class TreeShapedStack {
/**
* Creates an empty stack.
*/
public TreeShapedStack() {
this(null, null, 0);
}
private TreeShapedStack(TreeShapedStack previous, T data, int size) {
this.previous = previous;
this.data = data;
this.size = size;
}
/**
* Returns the previous state. If the size of the stack is 0, an
* exception is thrown. If the size is 1, an empty node is
* returned.
*/
public TreeShapedStack pop() {
if (size == 0) {
throw new EmptyStackException();
}
return previous;
}
/**
* Returns a new node with the new data attached.
*/
public TreeShapedStack push(T data) {
return new TreeShapedStack<>(this, data, size + 1);
}
/**
* Returns the data in the top node of the stack. If there is no
* data, eg the stack size is 0, an exception is thrown.
*/
public T peek() {
if (size == 0) {
throw new EmptyStackException();
}
return data;
}
/**
* How many nodes in this branch of the stack
*/
public int size() {
return size;
}
/**
* Returns the current stack as a list
*/
public List asList() {
List result = Generics.newArrayList(size);
TreeShapedStack current = this;
for (int index = 0; index < size; ++index) {
result.add(current.data);
current = current.pop();
}
Collections.reverse(result);
return result;
}
@Override
public String toString() {
return "[" + internalToString(" ") + "]";
}
public String toString(String delimiter) {
return "[" + internalToString(delimiter) + "]";
}
private String internalToString(String delimiter) {
if (size() == 0) {
return " ";
} else if (size() == 1) {
return data.toString();
} else {
return previous.internalToString(delimiter) + "," + delimiter + data.toString();
}
}
@Override
public int hashCode() {
int hash = size();
if (size() > 0 && peek() != null) {
hash ^= peek().hashCode();
}
return hash;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof TreeShapedStack)) {
return false;
}
TreeShapedStack> other = (TreeShapedStack>) o;
TreeShapedStack current = this;
if (other.size() != this.size()) {
return false;
}
for (int i = 0; i < size(); ++i) {
T currentObject = current.peek();
Object otherObject = other.peek();
if (!(currentObject == otherObject || (currentObject != null && currentObject.equals(otherObject)))) {
return false;
}
other = other.pop();
current = current.pop();
}
return true;
}
final T data;
final int size;
final TreeShapedStack previous;
}