001// Copyright 2007, 2008, 2011 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.commons.util; 016 017/** 018 * A simple, streamlined implementation of {@link java.util.Stack}. The implementation is <em>not</em> threadsafe. 019 * 020 * @param <E> the type of elements stored in the map 021 * @see CollectionFactory#newStack() 022 */ 023public class Stack<E> 024{ 025 private static final int MINIMUM_SIZE = 3; 026 027 private static final int DEFAULT_ARRAY_SIZE = 20; 028 029 private Object[] items; 030 031 private int index = -1; 032 033 /** 034 * Normal constructor supporting an initial size of 20. 035 */ 036 public Stack() 037 { 038 this(DEFAULT_ARRAY_SIZE); 039 } 040 041 /** 042 * @param initialSize the initial size of the internal array (which will be expanded as necessary). For best 043 * efficiency, set this to the maximum depth of the stack. 044 */ 045 public Stack(int initialSize) 046 { 047 items = new Object[Math.max(initialSize, MINIMUM_SIZE)]; 048 } 049 050 /** 051 * Returns true if the stack is empty. 052 */ 053 public boolean isEmpty() 054 { 055 return index < 0; 056 } 057 058 /** 059 * Returns the number of items currently in the stack. 060 */ 061 public int getDepth() 062 { 063 return index + 1; 064 } 065 066 /** 067 * Clears the stack, the same as popping off all elements. 068 */ 069 public void clear() 070 { 071 for (int i = 0; i <= index; i++) items[i] = null; 072 073 index = -1; 074 } 075 076 /** 077 * Pushes a new item onto the stack. 078 */ 079 public void push(E item) 080 { 081 index++; 082 083 if (index == items.length) 084 { 085 int newCapacity = (items.length * 3) / 2 + 1; 086 Object[] newItems = new Object[newCapacity]; 087 System.arraycopy(items, 0, newItems, 0, items.length); 088 089 items = newItems; 090 } 091 092 items[index] = item; 093 } 094 095 /** 096 * Pops the top element off the stack and returns it. 097 * 098 * @return the top element of the stack 099 * @throws IllegalStateException if the stack is empty 100 */ 101 @SuppressWarnings("unchecked") 102 public E pop() 103 { 104 checkIfEmpty(); 105 106 Object result = items[index]; 107 108 items[index] = null; 109 110 index--; 111 112 return (E) result; 113 } 114 115 private void checkIfEmpty() 116 { 117 if (index < 0) throw new IllegalStateException("Stack is empty."); 118 } 119 120 /** 121 * Returns the top element of the stack without affecting the stack. 122 * 123 * @return top element on the stack 124 * @throws IllegalStateException if the stack is empty 125 */ 126 @SuppressWarnings("unchecked") 127 public E peek() 128 { 129 checkIfEmpty(); 130 131 return (E) items[index]; 132 } 133 134 /** 135 * Describes the stack, listing the element in order of depth (top element first). 136 * 137 * @return string description of the stack 138 */ 139 @Override 140 public String toString() 141 { 142 StringBuilder builder = new StringBuilder("Stack["); 143 144 for (int i = index; i >= 0; i--) 145 { 146 if (i != index) builder.append(", "); 147 148 builder.append(String.valueOf(items[i])); 149 } 150 151 builder.append(']'); 152 153 return builder.toString(); 154 } 155 156 /** 157 * Returns a snapshot of the current state of the stack as an array of objects. The first object is the deepest in 158 * the stack, the last object is the most shallowest (most recently pushed onto the stack). The returned array may 159 * be manipulated (it is a copy). 160 * 161 * @return the stack as an object array 162 */ 163 public Object[] getSnapshot() 164 { 165 Object[] result = new Object[index + 1]; 166 167 System.arraycopy(items, 0, result, 0, index + 1); 168 169 return result; 170 } 171}