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.env.except.IllegalArgumentException; 19 import org.as2lib.env.except.IllegalStateException; 20 import org.as2lib.data.holder.Iterator; 21 import org.as2lib.data.holder.NoSuchElementException; 22 23 /** 24 * {@code ArrayIterator} can be used to iterate over arrays. 25 * 26 * <p>The usage of this iterator is quite simple. There is one method to check 27 * whether there are more elements left to iterate over {@link #hasNext}, one method 28 * to get the next element {@link #next} and one to remove the current element 29 * {@link #remove}. 30 * 31 * <p>Example: 32 * <code> 33 * var iterator:Iterator = new ArrayIterator(["value1", "value2", "value3"]); 34 * while (iterator.hasNext()) { 35 * trace(iterator.next()); 36 * } 37 * </code> 38 * <p>Output: 39 * <pre> 40 * value1 41 * value2 42 * value3 43 * </pre> 44 * 45 * @author Simon Wacker 46 * @author Michael Herrmann 47 * @author Martin Heidegger 48 */ 49 class org.as2lib.data.holder.array.ArrayIterator extends BasicClass implements Iterator { 50 51 /** The target data holder. */ 52 private var t:Array; 53 54 /** The current index of the iteration. */ 55 private var i:Number; 56 57 /** 58 * Constructs a new {@code ArrayIterator} instance. 59 * 60 * @param target the array to iterate over 61 * @throws IllegalArgumentException if the passed-in {@code target} array is 62 * {@code null} or {@code undefined} 63 */ 64 public function ArrayIterator(target:Array) { 65 // IllegalArgumentException if the passed array is not available. 66 if (!target) throw new IllegalArgumentException("Argument 'target' [" + target + "] must not be 'null' nor 'undefined'.", this, arguments); 67 68 // Usual handling of the arguments. 69 this.t = target; 70 i = -1; 71 72 // Prepare of fast internal replacement 73 var t:Array = target; 74 var g:Number = -1; 75 var p:Object = ArrayIterator.prototype; 76 var s:ArrayIterator = this; 77 78 // Replacement of internal methods as performance upgrade. 79 // - Only if this class is used, else the OOP functionality would be broken. 80 // - With more than 50 elements, else this method would be slower 81 if (this["__proto__"] == p && t.length > 50) { 82 83 // Replace for .next() if .hasNext was not called 84 var y:Function = function() { 85 if(g < t.length-1) { 86 arguments.callee = p.next; 87 throw new NoSuchElementException("There is no more element.", this, arguments); 88 } 89 return t[++g]; 90 }; 91 // Replace for .next() if .hasNext was called and there is something next 92 var x:Function = function() { 93 s.next = y; 94 return t[++g]; 95 }; 96 // Replace for .next() if .hasNext found that there is no next 97 var z:Function = function() { 98 s.next = y; 99 arguments.callee = p.next; 100 throw new NoSuchElementException("There is no more element.", this, arguments); 101 }; 102 // .next replacement 103 next = y; 104 // .hasNext replacement 105 hasNext = function() { 106 if(g < t.length-1) { 107 s.next = x; 108 return true; 109 } else { 110 s.next = z; 111 return false; 112 } 113 }; 114 // .remove replacement 115 remove = function() { 116 if (g < 0) { 117 arguments.callee = p.remove; 118 throw new IllegalStateException("You tried to remove an element before calling the 'next' method. There is thus no element selected to remove.", this, arguments); 119 } 120 t.splice(g--, 1); 121 }; 122 } 123 } 124 125 /** 126 * Returns whether there exists another element to iterate over. 127 * 128 * @return {@code true} if there is at least one lement left to iterate over 129 */ 130 public function hasNext(Void):Boolean { 131 return (i < t.length-1); 132 } 133 134 /** 135 * Returns the next element of the array. 136 * 137 * @return the next element of the array 138 * @throws NoSuchElementException if there is no next element 139 */ 140 public function next(Void) { 141 if (!hasNext()) { 142 throw new NoSuchElementException("There is no more element.", this, arguments); 143 } 144 return t[++i]; 145 } 146 147 /** 148 * Removes the currently selected element from this iterator and from the array this 149 * iterator iterates over. 150 * 151 * @throws IllegalStateException if you try to remove an element when none is selected 152 */ 153 public function remove(Void):Void { 154 if (i < 0) { 155 throw new IllegalStateException("You tried to remove an element before calling the 'next' method. There is thus no element selected to remove.", this, arguments); 156 } 157 t.splice(i--, 1); 158 } 159 160 } 161