1 /** 2 * The Render Engine 3 * Iterator 4 * 5 * @fileoverview A set of objects which can be used to create a collection 6 * of objects, and to iterate over a container. 7 * 8 * @author: Brett Fattori (brettf@renderengine.com) 9 * @author: $Author: bfattori@gmail.com $ 10 * @version: $Revision: 1572 $ 11 * 12 * Copyright (c) 2011 Brett Fattori (brettf@renderengine.com) 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a copy 15 * of this software and associated documentation files (the "Software"), to deal 16 * in the Software without restriction, including without limitation the rights 17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 * copies of the Software, and to permit persons to whom the Software is 19 * furnished to do so, subject to the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be included in 22 * all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 * THE SOFTWARE. 31 * 32 */ 33 34 // The class this file defines and its required classes 35 R.Engine.define({ 36 "class":"R.lang.Iterator", 37 "requires":[ 38 "R.engine.PooledObject" 39 ] 40 }); 41 42 /** 43 * @class Create an iterator over a {@link R.struct.Container} or <code>Array</code> instance. An 44 * iterator is a convenient object to traverse the list of objects 45 * within the container. The benefit of using an iterator with a <code>R.struct.Container</code> is 46 * that if the container is modified, the <code>R.lang.Iterator</code> will reflect these changes. 47 * <p/> 48 * The simplest way to traverse the list is as follows: 49 * <pre> 50 * for (var itr = R.lang.Iterator.create(containerObj); itr.hasNext(); ) { 51 * // Get the next object in the container 52 * var o = itr.next(); 53 * 54 * // Do something with the object 55 * o.doSomething(); 56 * } 57 * 58 * // Destroy the iterator when done 59 * itr.destroy(); 60 * </pre> 61 * The last step is important so that you're not creating a lot 62 * of objects, especially if the iterator is used repeatedly. 63 * Since the iterator is a pooled object, it will be reused. 64 * 65 * @param container {R.struct.Container} The container to iterate over. 66 * @constructor 67 * @extends R.engine.PooledObject 68 * @description Create an iterator over a collection 69 */ 70 R.lang.Iterator = function () { 71 "use strict"; 72 return R.engine.PooledObject.extend(/** @scope R.lang.Iterator.prototype */{ 73 74 c:null, 75 aO:null, 76 p:null, 77 r:false, 78 arr:false, 79 80 /** 81 * @private 82 */ 83 constructor:function (container /*, actualContainerObj */) { 84 this.base("Iterator"); 85 this.c = container; 86 this.aO = (arguments.length == 2 ? arguments[1] : null); 87 this.arr = $.isArray(container); // Handle plain Arrays too 88 this.p = this.arr ? 0 : container._head; 89 this.r = false; 90 }, 91 92 /** 93 * Release the iterator back into the object pool. 94 */ 95 release:function () { 96 this.base(); 97 this.c = null; 98 this.aO = null; 99 this.arr = false; 100 this.p = null; 101 this.r = false; 102 }, 103 104 /** 105 * Reset the iterator to the start of the collection. 106 */ 107 reset:function () { 108 this.p = this.arr ? (this.r ? this.c.length - 1 : 0) : (this.r ? this.c._tail : this.c._head); 109 }, 110 111 /** 112 * Reverse the order of the elements in the container (non-destructive) before 113 * iterating over them. You cannot call this method after you have called {@link #next}, 114 * otherwise, use {@link #reset} before calling this method. 115 */ 116 reverse:function () { 117 Assert((this.arr ? this.p == 0 : this.p === this.c._head), "Cannot reverse Iterator after calling next()"); 118 this.r = true; 119 this.p = this.arr ? this.c.length - 1 : this.c._tail; 120 }, 121 122 /** 123 * Get the next element from the iterator. 124 * @return {Object} The next element in the iterator 125 * @throws {Error} An error if called when no more elements are available 126 */ 127 next:function () { 128 // Make sure the container wasn't destroyed 129 if (this.arr ? (this.aO != null ? this.aO.isDestroyed() : false) : this.c.isDestroyed()) { 130 throw new Error("Invalid iterator over destroyed container!"); 131 } 132 133 var o = null; 134 if (this.arr) { 135 // For arrays 136 Assert(this.p > -1 && this.p < this.c.length, "Iterator[" + this.getId() + "] - next() is out of range"); 137 o = this.c[this.p]; 138 this.p += (this.r ? -1 : 1); 139 } else { 140 // For containers 141 // Get the next and move the pointer 142 o = this.p.ptr; 143 this.p = (this.r ? this.p.prev : this.p.next); 144 145 if (o == null) { 146 Assert(false, "Iterator[" + this.getId() + "] - next() is out of range"); 147 } 148 } 149 150 return o; 151 }, 152 153 /** 154 * Returns <tt>true</tt> if the iterator has more elements. 155 * @return {Boolean} 156 */ 157 hasNext:function () { 158 // As long as the container hasn't been destroyed 159 if (this.arr ? (this.aO != null ? !this.aO.isDestroyed() : true) : !this.c.isDestroyed()) { 160 if (this.arr) { 161 // For arrays (and R.struct.Container) 162 var nxt = this.r ? -1 : 1, n = this.p, 163 dead = (this.c[n] && this.c[n].isDestroyed && this.c[n].isDestroyed()); 164 while ((n > -1 && n < this.c.length) && dead) { 165 // Skip dead objects 166 n += nxt; 167 this.p = n; 168 } 169 return (n > -1 && n < this.c.length); 170 } else { 171 // If the container hasn't been destroyed 172 while (this.p != null && this.p.ptr != null && this.p.ptr.isDestroyed()) { 173 // Skip destroyed objects 174 this.p = (this.r ? this.p.prev : this.p.next); 175 } 176 return this.p != null; 177 } 178 } 179 return false; 180 } 181 182 }, /** @scope R.lang.Iterator.prototype */{ 183 /** 184 * Get the class name of this object 185 * 186 * @return {String} "R.lang.Iterator" 187 */ 188 getClassName:function () { 189 return "R.lang.Iterator"; 190 }, 191 192 /** 193 * Create an instance of an iterator over the given container. 194 * @param container {R.struct.Container|Array} An <code>Array</code> or {@link R.struct.Container} 195 * @return {R.lang.Iterator} An iterator over the container 196 * @static 197 */ 198 over:function (container) { 199 return R.lang.Iterator.create(container); 200 } 201 202 }); 203 204 };