// Copyright 2007, 2008, 2011 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.apache.tapestry5.ioc.util; import org.apache.tapestry5.ioc.internal.util.CollectionFactory; /** * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe. * * @param <E> the type of elements stored in the map * @see CollectionFactory#newStack() */ public class Stack<E> { private static final int MINIMUM_SIZE = 3; private static final int DEFAULT_ARRAY_SIZE = 20; private Object[] items; private int index = -1; /** * Normal constructor supporting an initial size of 20. */ public Stack() { this(DEFAULT_ARRAY_SIZE); } /** * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best * efficiency, set this to the maximum depth of the stack. */ public Stack(int initialSize) { items = new Object[Math.max(initialSize, MINIMUM_SIZE)]; } /** * Returns true if the stack is empty. */ public boolean isEmpty() { return index < 0; } /** * Returns the number of items currently in the stack. */ public int getDepth() { return index + 1; } /** * Clears the stack, the same as popping off all elements. */ public void clear() { for (int i = 0; i <= index; i++) items[i] = null; index = -1; } /** * Pushes a new item onto the stack. */ public void push(E item) { index++; if (index == items.length) { int newCapacity = (items.length * 3) / 2 + 1; Object[] newItems = new Object[newCapacity]; System.arraycopy(items, 0, newItems, 0, items.length); items = newItems; } items[index] = item; } /** * Pops the top element off the stack and returns it. * * @return the top element of the stack * @throws IllegalStateException if the stack is empty */ @SuppressWarnings("unchecked") public E pop() { checkIfEmpty(); Object result = items[index]; items[index] = null; index--; return (E) result; } private void checkIfEmpty() { if (index < 0) throw new IllegalStateException("Stack is empty."); } /** * Returns the top element of the stack without affecting the stack. * * @return top element on the stack * @throws IllegalStateException if the stack is empty */ @SuppressWarnings("unchecked") public E peek() { checkIfEmpty(); return (E) items[index]; } /** * Describes the stack, listing the element in order of depth (top element first). * * @return string description of the stack */ @Override public String toString() { StringBuilder builder = new StringBuilder("Stack["); for (int i = index; i >= 0; i--) { if (i != index) builder.append(", "); builder.append(String.valueOf(items[i])); } builder.append(']'); return builder.toString(); } /** * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in * the stack, the last object is the most shallowest (most recently pushed onto the stack). The returned array may * be manipulated (it is a copy). * * @return the stack as an object array */ public Object[] getSnapshot() { Object[] result = new Object[index + 1]; System.arraycopy(items, 0, result, 0, index + 1); return result; } }