/*
* Kodkod -- Copyright (c) 2005-present, Emina Torlak
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package kodkod.util.collections;
import java.util.EmptyStackException;
import java.util.Iterator;
/**
* Represents a last-in-first-out (LIFO) stack of objects.
* The usual push and pop operations are provided, as well as a method to peek at the top item on the stack,
* a method to test for whether the stack is empty, and an iterator over the elements in the stack
* (that does not support removal). When a stack is first created, it contains no items.
*
* @specfield size: int
* @specfield elems: [0..size)->one T
* @author Emina Torlak
*/
public abstract class Stack<T> implements Iterable<T> {
/**
* Constructs a new stack.
*/
protected Stack() {}
/**
* Returns the size of this stack.
* @return this.size
*/
public abstract int size();
/**
* Pushes an item onto the top of this stack and returns it.
* @ensures this.size' = this.size + 1 && this.elems'[0] = item &&
* all i: [0..this.size) | this.elems'[i+1] = this.elems[i]
* @return item
*/
public abstract T push(T item);
/**
* Removes the object at the top of this stack and returns that object as the value of this function.
* @ensures this.size' = this.size - 1 &&
* all i: [1..this.size) | this.elems'[i-1] = this.elems[i]
* @return this.elems[0]
* @throws EmptyStackException no this.elems
*/
public abstract T pop();
/**
* Looks at the object at the top of this stack without removing it from the stack.
* @return this.elems[0]
* @throws EmptyStackException no this.elems
*/
public abstract T peek();
/**
* Returns the 1-based position where an object is on this stack.
* If the object o occurs as an item in this stack, this method
* returns the distance from the top of the stack of the occurrence
* nearest the top of the stack; the topmost item on the stack is
* considered to be at distance 1. The equals method is used to
* compare o to the items in this stack.
* @return o in this.elems[int] => min(this.elems.o) + 1, -1
*/
public abstract int search(Object o);
/**
* Returns true if the stack is empty; otherwise returns false.
* @return no this.elems
*/
public abstract boolean empty();
/**
* Iterates over the items in this Stack, starting
* at the top of the stack and working its way down.
* @return iterator over the elements in this stack.
*/
public abstract Iterator<T> iterator();
/**
* Returns true if both o1 and o2 are null, or
* if they are non-null and 'equals' to each other.
* @return o1=null && o2=null || o1.equals(o2)
*/
static boolean equal(Object o1, Object o2) {
return (o1==null ? o2==null : o1.equals(o2));
}
/**
* Returns true if o is a stack containing the same elements
* as this stack, in the same order.
* @return o in Stack && this.elems = o.elems
*/
@SuppressWarnings("unchecked")
public boolean equals(Object o) {
if (this==o) return true;
else if (o instanceof Stack) {
final Stack<T> s = (Stack<T>) o;
if (size() != s.size()) return false;
final Iterator<T> iter0 = iterator(), iter1 = s.iterator();
while(iter0.hasNext()) {
if (!equal(iter0.next(), iter1.next()))
return false;
}
return true;
}
return false;
}
/**
* Returns the hashcode for this stack.
* @return the hashcode for this stack.
*/
public int hashCode() {
int code = 0;
for(T item : this) {
if (item!=null) code += item.hashCode();
}
return code;
}
/**
* Returns a string represention of this stack.
*/
public String toString() {
final StringBuilder buffer = new StringBuilder("[ ");
final Iterator<T> elems = iterator();
if (elems.hasNext()) buffer.append(elems.next());
while(elems.hasNext()) {
buffer.append(", ");
buffer.append(elems.next());
}
buffer.append(" ]");
return buffer.toString();
}
}