1 /* 2 * Copyright the original author or authors. 3 * 4 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.mozilla.org/MPL/MPL-1.1.html 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import org.as2lib.core.BasicClass; 18 import org.as2lib.data.holder.Stack; 19 import org.as2lib.data.holder.Iterator; 20 import org.as2lib.data.holder.ProtectedIterator; 21 import org.as2lib.data.holder.array.ArrayIterator; 22 import org.as2lib.data.holder.EmptyDataHolderException; 23 import org.as2lib.util.Stringifier; 24 import org.as2lib.data.holder.stack.StackStringifier; 25 26 /** 27 * {@code SimpleStack} holds data in a 'last-in, first-out' manner. 28 * 29 * <p>It is a simple implementation of the {@code Stack} interface and realizes all 30 * its basic concepts. 31 * 32 * <p>'last-in, first-out' means that the last value that has been pushed to the 33 * stack is the first that is popped from the stack. 34 * 35 * <p>The usage of a stack is quite simple. You have one method to push values, 36 * {@link #push}, and one method to pop values, {@link #pop}. You can also peek at 37 * the top of the stack to see what's the last value that has been pushed to the 38 * stack without removing it {@link #peek}. 39 * 40 * <p>If you want to iterate over the values of the stack you can either use the 41 * iterator returned by the {@link #iterator} method or the array that contains the 42 * stack's values returned by the {@link #toArray} method. 43 * 44 * <p>The two methods {@link #isEmpty} and {@link #size} let you find out whether 45 * the stack contains values and how many values it contains. 46 * 47 * <p>You can modify the string representation that is returned by the {@link #toString} 48 * method using the static {@link #setStringifier} method. 49 * 50 * <p>Example: 51 * <code> 52 * // the stack is constructed somewhere 53 * var stack:Stack = new SimpleStack(); 54 * stack.push("value1"); 55 * stack.push("value2"); 56 * stack.push("value3"); 57 * // the stack is used 58 * trace(stack.peek()); 59 * while (!stack.isEmpty()) { 60 * trace(stack.pop()); 61 * } 62 * </code> 63 * 64 * <p>Output: 65 * <pre> 66 * value3 67 * value3 68 * value2 69 * value1 70 * </pre> 71 * 72 * <p>You can alternatively pass-in the content of the stack on construction. 73 * <code> 74 * var stack:Stack = new SimpleStack(["value1", "value2", "value3"]); 75 * // .. 76 * </code> 77 * 78 * @author Simon Wacker 79 */ 80 class org.as2lib.data.holder.stack.SimpleStack extends BasicClass implements Stack { 81 82 /** Stringifies stacks. */ 83 private static var stringifier:Stringifier; 84 85 /** Contains the inserted values. */ 86 private var values:Array; 87 88 /** 89 * Returns the stringifier that stringifies stacks. 90 * 91 * <p>If no stringifier has been set manually the default stringifier will be returned 92 * which is an instance of class {@link StackStringifier}. 93 * 94 * @return the stringifier that stringifies stacks 95 */ 96 public static function getStringifier(Void):Stringifier { 97 if (!stringifier) stringifier = new StackStringifier(); 98 return stringifier; 99 } 100 101 /** 102 * Sets the new stringifier that stringifies stacks. 103 * 104 * <p>If the passed-in {@code stackStringifier} is {@code null} or {@code undefined} 105 * the static {@link #getStringifier} method will return the default stringifier. 106 * 107 * @param stackStringifier the new stack stringifier 108 */ 109 public static function setStringifier(stackStringifier:Stringifier):Void { 110 stringifier = stackStringifier; 111 } 112 113 /** 114 * Constructs a new {@code SimpleStack} instance. 115 * 116 * <p>The stack steps through the passed-in {@code source} beginning at position 117 * 0 and pushes all contained elements to this stack. 118 * 119 * <code> 120 * var stack:SimpleStack = new SimpleStack([1, 2, 3]); 121 * while (!stack.isEmpty()) { 122 * trace(stack.pop()); 123 * } 124 * </code> 125 * 126 * <p>The output is made in the following order: 3, 2, 1 127 * 128 * @param source (optional) an array that contains values to populate this stack with 129 */ 130 public function SimpleStack(source:Array) { 131 if (source) { 132 values = source.concat(); 133 } else { 134 values = new Array(); 135 } 136 } 137 138 /** 139 * Pushes the passed-in {@code value} to this stack. 140 * 141 * <p>{@code null} or {@code undefined} values are allowed. 142 * 143 * @param value the value to push to this stack 144 */ 145 public function push(value):Void { 146 values.push(value); 147 } 148 149 /** 150 * Removes and returns the lastly pushed value. 151 * 152 * @return the lastly pushed value 153 * @throws EmptyDataHolderException if this stack is empty 154 */ 155 public function pop(Void) { 156 if (isEmpty()) { 157 throw new EmptyDataHolderException("You tried to pop an element from an empty Stack.", this, arguments); 158 } 159 return values.pop(); 160 } 161 162 /** 163 * Returns the lastly pushed value without removing it. 164 * 165 * @return the lastly pushed value 166 * @throws EmptyDataHolderException if this stack is empty 167 */ 168 public function peek(Void) { 169 if (isEmpty()) { 170 throw new EmptyDataHolderException("You tried to peek an element from an empty Stack.", this, arguments); 171 } 172 return values[values.length-1]; 173 } 174 175 /** 176 * Returns an iterator to iterate over the values of this stack. 177 * 178 * @return an iterator to iterate over this stack 179 * @see #toArray 180 */ 181 public function iterator(Void):Iterator { 182 var reversedValues:Array = values.slice(); 183 reversedValues.reverse(); 184 return (new ProtectedIterator(new ArrayIterator(reversedValues))); 185 } 186 187 /** 188 * Returns whether this stack is empty. 189 * 190 * @return {@code true} if this stack is empty else {@code false} 191 */ 192 public function isEmpty(Void):Boolean { 193 return (values.length < 1); 194 } 195 196 /** 197 * Returns the number of pushed values. 198 * 199 * @return the number of pushed values 200 * @see #push 201 */ 202 public function size(Void):Number { 203 return values.length; 204 } 205 206 /** 207 * Returns the array representation of this stack. 208 * 209 * <p>The elements are copied onto the array in a 'last-in, first-out' order, similar 210 * to the order of the elements returned by a succession of calls to the {@link #pop} 211 * method. 212 * 213 * @return the array representation of this stack 214 */ 215 public function toArray(Void):Array { 216 var result:Array = values.concat(); 217 result.reverse(); 218 return result; 219 } 220 221 /** 222 * Returns the string representation of this stack. 223 * 224 * <p>The string representation is obtained using the stringifier returned by the 225 * static {@link #getStringifier} method. 226 * 227 * @return the string representation of this stack 228 */ 229 public function toString():String { 230 return getStringifier().execute(this); 231 } 232 233 }