1 // ==========================================================================
  2 // Project:   SproutCore Costello - Property Observing Library
  3 // Copyright: ©2006-2011 Strobe Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 /**
  9   @class
 10 
 11   An object that iterates over all of the values in an object.
 12 
 13   An instance of this object is returned every time you call the
 14   enumerator() method on an object that implements the SC.Enumerable mixin.
 15 
 16   Once you create an enumerator instance, you can call nextObject() on it
 17   until you can iterated through the entire collection.  Once you have
 18   exhausted the enumerator, you can reuse it if you want by calling reset().
 19 
 20   @since SproutCore 1.0
 21 */
 22 SC.Enumerator = function(enumerableObject) {
 23   this.enumerable = enumerableObject ;
 24   this.reset() ;
 25   return this ;
 26 } ;
 27 
 28 SC.Enumerator.prototype = /** @scope SC.Enumerator.prototype */{
 29 
 30   /**
 31     Returns the next object in the enumeration or undefined when complete.
 32 
 33     @returns {Object} the next object or undefined
 34   */
 35   nextObject: function() {
 36     var index = this._index ;
 37     var len = this._length;
 38     if (index >= len) return undefined ; // nothing to do
 39 
 40     // get the value
 41     var ret = this.enumerable.nextObject(index, this._previousObject, this._context) ;
 42     this._previousObject = ret ;
 43     this._index = index + 1 ;
 44 
 45     if (index >= len) {
 46       this._context = SC.Enumerator._pushContext(this._context);
 47     }
 48 
 49     return ret ;
 50   },
 51 
 52   /**
 53     Resets the enumerator to the beginning.  This is a nice way to reuse
 54     an existing enumerator.
 55 
 56     @returns {Object} this
 57   */
 58   reset: function() {
 59     var e = this.enumerable ;
 60     if (!e) SC.throw("Enumerator has been destroyed");
 61     this._length = e.get ? e.get('length') : e.length ;
 62     var len = this._length;
 63     this._index = 0;
 64     this._previousObject = null ;
 65     this._context = (len > 0) ? SC.Enumerator._popContext() : null;
 66   },
 67 
 68   /**
 69     Releases the enumerators enumerable object.  You cannot use this object
 70     anymore.  This is not often needed but it is useful when you need to
 71     make sure memory gets cleared.
 72 
 73     @returns {Object} null
 74   */
 75   destroy: function() {
 76     this.enumerable = this._length = this._index = this._previousObject = this._context = null;
 77   }
 78 
 79 } ;
 80 
 81 /**
 82   Use this method to manually create a new Enumerator object.  Usually you
 83   will not access this method directly but instead call enumerator() on the
 84   item you want to enumerate.
 85 
 86   @param {SC.Enumerable}  enumerableObject enumerable object.
 87   @returns {SC.Enumerator} the enumerator
 88 */
 89 SC.Enumerator.create = function(enumerableObject) {
 90   return new SC.Enumerator(enumerableObject) ;
 91 };
 92 
 93 // Private context caching methods.  This avoids recreating lots of context
 94 // objects.
 95 
 96 SC.Enumerator._popContext = function() {
 97   var ret = this._contextCache ? this._contextCache.pop() : null ;
 98   return ret || {} ;
 99 } ;
100 
101 SC.Enumerator._pushContext = function(context) {
102   this._contextCache = this._contextCache || [] ;
103   var cache = this._contextCache;
104   cache.push(context);
105   return null ;
106 };
107 
108