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.util.ObjectUtil; 19 import org.as2lib.env.except.IllegalArgumentException; 20 import org.as2lib.env.reflect.ReflectUtil; 21 import org.as2lib.data.holder.Stack; 22 import org.as2lib.data.holder.Iterator; 23 24 /** 25 * {@code TypedStack} is a wrapper for {@link Stack} instances that ensures that 26 * only values of a specific type can be added to the wrapped stack. 27 * 28 * <p>This class simply delegates all method invocations to the wrapped stack. If 29 * the specific method is responsible for adding values it first checks if the values 30 * to add are of the expected type. If they are the method invocation is forwarded, 31 * otherwise an {@link IllegalArgumentException} is thrown. 32 * 33 * @author Simon Wacker 34 */ 35 class org.as2lib.data.holder.stack.TypedStack extends BasicClass implements Stack { 36 37 /** The wrapped Stack. */ 38 private var stack:Stack; 39 40 /** The type of the values that are allowed. */ 41 private var type:Function; 42 43 /** 44 * Constructs a new {@code TypedStack} instance. 45 * 46 * <p>If the passed-in stack does already contain values, these values do not get 47 * type-checked. 48 * 49 * @param type the type of values the stack can have 50 * @param stack the stack to type-check 51 * @throws IllegalArgumentException if the passed-in {@code type} is {@code null} 52 * or {@code undefined} 53 * @throws IllegalArgumentException if {@code stack} is {@code null} or 54 * {@code undefined} 55 */ 56 public function TypedStack(type:Function, stack:Stack) { 57 if (!type) throw new IllegalArgumentException("Argument 'type' [" + type + "] must not be 'null' nor 'undefined'.", this, arguments); 58 if (!stack) throw new IllegalArgumentException("Argument 'stack' [" + stack + "] must not be 'null' nor 'undefined'.", this, arguments); 59 this.type = type; 60 this.stack = stack; 61 } 62 63 /** 64 * Returns the type that all values in the wrapped stack have. 65 * 66 * <p>This is the type passed-in on construction. 67 * 68 * @return the type that all values of the wrapped stack have 69 */ 70 public function getType(Void):Function { 71 return type; 72 } 73 74 /** 75 * Pushes the passed-in value to this stack. 76 * 77 * <p>The value is only pushed if it is of the expected type. 78 * 79 * @param value the value to push to this stack 80 * @throws IllegalArgumentException if the type of the passed-in {@code value} is 81 * invalid 82 */ 83 public function push(value):Void { 84 validate(value); 85 stack.push(value); 86 } 87 88 /** 89 * Removes and returns the lastly pushed value. 90 * 91 * @return the lastly pushed value 92 * @throws org.as2lib.data.holder.EmptyDataHolderException if this stack is empty 93 */ 94 public function pop(Void) { 95 return stack.pop(); 96 } 97 98 /** 99 * Returns the lastly pushed value without removing it. 100 * 101 * @return the lastly pushed value 102 * @throws org.as2lib.data.holder.EmptyDataHolderException if this stack is empty 103 */ 104 public function peek(Void) { 105 return stack.peek(); 106 } 107 108 /** 109 * Returns an iterator to iterate over the values of this stack. 110 * 111 * @return an iterator to iterate over this stack's values 112 * @see #toArray 113 */ 114 public function iterator(Void):Iterator { 115 return stack.iterator(); 116 } 117 118 /** 119 * Returns whether this stack is empty. 120 * 121 * @return {@code true} if this stack is empty else {@code false} 122 */ 123 public function isEmpty(Void):Boolean { 124 return stack.isEmpty(); 125 } 126 127 /** 128 * Returns the number of pushed values. 129 * 130 * @return the number of pushed values 131 * @see #push 132 */ 133 public function size(Void):Number { 134 return stack.size(); 135 } 136 137 /** 138 * Returns an array representation of this stack. 139 * 140 * <p>The elements are copied onto the array in a 'last-in, first-out' order, similar 141 * to the order of the elements returned by a succession of calls to the {@link #pop} 142 * method. 143 * 144 * @return the array representation of this stack 145 */ 146 public function toArray(Void):Array { 147 return stack.toArray(); 148 } 149 150 /** 151 * Returns the string representation of the wrapped stack. 152 * 153 * @return the string representation of the wrapped stack 154 */ 155 public function toString():String { 156 return stack.toString(); 157 } 158 159 /** 160 * Validates the passed-in {@code value} based on its type. 161 * 162 * @param value the value whose type to validate 163 * @throws IllegalArgumentException if the type of the value is invalid 164 */ 165 private function validate(value):Void { 166 if (!ObjectUtil.typesMatch(value, type)) { 167 throw new IllegalArgumentException("Type mismatch between value [" + value + "] and type [" + ReflectUtil.getTypeNameForType(type) + "].", this, arguments); 168 } 169 } 170 171 }