Update wmts-hidpi, add nicer-api-docs
This commit is contained in:
702
nicer-api-docs/closure-library/closure/goog/iter/iter.js
Normal file
702
nicer-api-docs/closure-library/closure/goog/iter/iter.js
Normal file
@@ -0,0 +1,702 @@
|
||||
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Python style iteration utilities.
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.iter');
|
||||
goog.provide('goog.iter.Iterator');
|
||||
goog.provide('goog.iter.StopIteration');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
|
||||
|
||||
// TODO(nnaze): Add more functions from Python's itertools.
|
||||
// http://docs.python.org/library/itertools.html
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {goog.iter.Iterator|{length:number}|{__iterator__}}
|
||||
*/
|
||||
goog.iter.Iterable;
|
||||
|
||||
|
||||
// For script engines that already support iterators.
|
||||
if ('StopIteration' in goog.global) {
|
||||
/**
|
||||
* Singleton Error object that is used to terminate iterations.
|
||||
* @type {Error}
|
||||
*/
|
||||
goog.iter.StopIteration = goog.global['StopIteration'];
|
||||
} else {
|
||||
/**
|
||||
* Singleton Error object that is used to terminate iterations.
|
||||
* @type {Error}
|
||||
* @suppress {duplicate}
|
||||
*/
|
||||
goog.iter.StopIteration = Error('StopIteration');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class/interface for iterators. An iterator needs to implement a {@code next}
|
||||
* method and it needs to throw a {@code goog.iter.StopIteration} when the
|
||||
* iteration passes beyond the end. Iterators have no {@code hasNext} method.
|
||||
* It is recommended to always use the helper functions to iterate over the
|
||||
* iterator or in case you are only targeting JavaScript 1.7 for in loops.
|
||||
* @constructor
|
||||
*/
|
||||
goog.iter.Iterator = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next value of the iteration. This will throw the object
|
||||
* {@see goog.iter#StopIteration} when the iteration passes the end.
|
||||
* @return {*} Any object or value.
|
||||
*/
|
||||
goog.iter.Iterator.prototype.next = function() {
|
||||
throw goog.iter.StopIteration;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the {@code Iterator} object itself. This is used to implement
|
||||
* the iterator protocol in JavaScript 1.7
|
||||
* @param {boolean=} opt_keys Whether to return the keys or values. Default is
|
||||
* to only return the values. This is being used by the for-in loop (true)
|
||||
* and the for-each-in loop (false). Even though the param gives a hint
|
||||
* about what the iterator will return there is no guarantee that it will
|
||||
* return the keys when true is passed.
|
||||
* @return {!goog.iter.Iterator} The object itself.
|
||||
*/
|
||||
goog.iter.Iterator.prototype.__iterator__ = function(opt_keys) {
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that knows how to iterate over the values in the object.
|
||||
* @param {goog.iter.Iterable} iterable If the object is an iterator it
|
||||
* will be returned as is. If the object has a {@code __iterator__} method
|
||||
* that will be called to get the value iterator. If the object is an
|
||||
* array-like object we create an iterator for that.
|
||||
* @return {!goog.iter.Iterator} An iterator that knows how to iterate over the
|
||||
* values in {@code iterable}.
|
||||
*/
|
||||
goog.iter.toIterator = function(iterable) {
|
||||
if (iterable instanceof goog.iter.Iterator) {
|
||||
return iterable;
|
||||
}
|
||||
if (typeof iterable.__iterator__ == 'function') {
|
||||
return iterable.__iterator__(false);
|
||||
}
|
||||
if (goog.isArrayLike(iterable)) {
|
||||
var i = 0;
|
||||
var newIter = new goog.iter.Iterator;
|
||||
newIter.next = function() {
|
||||
while (true) {
|
||||
if (i >= iterable.length) {
|
||||
throw goog.iter.StopIteration;
|
||||
}
|
||||
// Don't include deleted elements.
|
||||
if (!(i in iterable)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
return iterable[i++];
|
||||
}
|
||||
};
|
||||
return newIter;
|
||||
}
|
||||
|
||||
|
||||
// TODO(arv): Should we fall back on goog.structs.getValues()?
|
||||
throw Error('Not implemented');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for each element in the iterator with the element of the
|
||||
* iterator passed as argument.
|
||||
*
|
||||
* @param {goog.iter.Iterable} iterable The iterator to iterate
|
||||
* over. If the iterable is an object {@code toIterator} will be called on
|
||||
* it.
|
||||
* @param {function(this:T,?,?,?):?} f The function to call for every
|
||||
* element. This function
|
||||
* takes 3 arguments (the element, undefined, and the iterator) and the
|
||||
* return value is irrelevant. The reason for passing undefined as the
|
||||
* second argument is so that the same function can be used in
|
||||
* {@see goog.array#forEach} as well as others.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this' within
|
||||
* {@code f}.
|
||||
* @template T
|
||||
*/
|
||||
goog.iter.forEach = function(iterable, f, opt_obj) {
|
||||
if (goog.isArrayLike(iterable)) {
|
||||
/** @preserveTry */
|
||||
try {
|
||||
// NOTES: this passes the index number to the second parameter
|
||||
// of the callback contrary to the documentation above.
|
||||
goog.array.forEach(/** @type {goog.array.ArrayLike} */(iterable), f,
|
||||
opt_obj);
|
||||
} catch (ex) {
|
||||
if (ex !== goog.iter.StopIteration) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iterable = goog.iter.toIterator(iterable);
|
||||
/** @preserveTry */
|
||||
try {
|
||||
while (true) {
|
||||
f.call(opt_obj, iterable.next(), undefined, iterable);
|
||||
}
|
||||
} catch (ex) {
|
||||
if (ex !== goog.iter.StopIteration) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for every element in the iterator, and if the function
|
||||
* returns true adds the element to a new iterator.
|
||||
*
|
||||
* @param {goog.iter.Iterable} iterable The iterator to iterate over.
|
||||
* @param {function(this:T,?,undefined,?):boolean} f The function to call for
|
||||
* every element. This function
|
||||
* takes 3 arguments (the element, undefined, and the iterator) and should
|
||||
* return a boolean. If the return value is true the element will be
|
||||
* included in the returned iteror. If it is false the element is not
|
||||
* included.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this' within
|
||||
* {@code f}.
|
||||
* @return {!goog.iter.Iterator} A new iterator in which only elements that
|
||||
* passed the test are present.
|
||||
* @template T
|
||||
*/
|
||||
goog.iter.filter = function(iterable, f, opt_obj) {
|
||||
var iterator = goog.iter.toIterator(iterable);
|
||||
var newIter = new goog.iter.Iterator;
|
||||
newIter.next = function() {
|
||||
while (true) {
|
||||
var val = iterator.next();
|
||||
if (f.call(opt_obj, val, undefined, iterator)) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
};
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new iterator that returns the values in a range. This function
|
||||
* can take 1, 2 or 3 arguments:
|
||||
* <pre>
|
||||
* range(5) same as range(0, 5, 1)
|
||||
* range(2, 5) same as range(2, 5, 1)
|
||||
* </pre>
|
||||
*
|
||||
* @param {number} startOrStop The stop value if only one argument is provided.
|
||||
* The start value if 2 or more arguments are provided. If only one
|
||||
* argument is used the start value is 0.
|
||||
* @param {number=} opt_stop The stop value. If left out then the first
|
||||
* argument is used as the stop value.
|
||||
* @param {number=} opt_step The number to increment with between each call to
|
||||
* next. This can be negative.
|
||||
* @return {!goog.iter.Iterator} A new iterator that returns the values in the
|
||||
* range.
|
||||
*/
|
||||
goog.iter.range = function(startOrStop, opt_stop, opt_step) {
|
||||
var start = 0;
|
||||
var stop = startOrStop;
|
||||
var step = opt_step || 1;
|
||||
if (arguments.length > 1) {
|
||||
start = startOrStop;
|
||||
stop = opt_stop;
|
||||
}
|
||||
if (step == 0) {
|
||||
throw Error('Range step argument must not be zero');
|
||||
}
|
||||
|
||||
var newIter = new goog.iter.Iterator;
|
||||
newIter.next = function() {
|
||||
if (step > 0 && start >= stop || step < 0 && start <= stop) {
|
||||
throw goog.iter.StopIteration;
|
||||
}
|
||||
var rv = start;
|
||||
start += step;
|
||||
return rv;
|
||||
};
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Joins the values in a iterator with a delimiter.
|
||||
* @param {goog.iter.Iterable} iterable The iterator to get the values from.
|
||||
* @param {string} deliminator The text to put between the values.
|
||||
* @return {string} The joined value string.
|
||||
*/
|
||||
goog.iter.join = function(iterable, deliminator) {
|
||||
return goog.iter.toArray(iterable).join(deliminator);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* For every element in the iterator call a function and return a new iterator
|
||||
* with that value.
|
||||
*
|
||||
* @param {goog.iter.Iterable} iterable The iterator to iterate over.
|
||||
* @param {function(this:T,?,undefined,?):?} f The function to call for every
|
||||
* element. This function
|
||||
* takes 3 arguments (the element, undefined, and the iterator) and should
|
||||
* return a new value.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this' within
|
||||
* {@code f}.
|
||||
* @return {!goog.iter.Iterator} A new iterator that returns the results of
|
||||
* applying the function to each element in the original iterator.
|
||||
* @template T
|
||||
*/
|
||||
goog.iter.map = function(iterable, f, opt_obj) {
|
||||
var iterator = goog.iter.toIterator(iterable);
|
||||
var newIter = new goog.iter.Iterator;
|
||||
newIter.next = function() {
|
||||
while (true) {
|
||||
var val = iterator.next();
|
||||
return f.call(opt_obj, val, undefined, iterator);
|
||||
}
|
||||
};
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Passes every element of an iterator into a function and accumulates the
|
||||
* result.
|
||||
*
|
||||
* @param {goog.iter.Iterable} iterable The iterator to iterate over.
|
||||
* @param {function(this:T,V,?):V} f The function to call for every
|
||||
* element. This function takes 2 arguments (the function's previous result
|
||||
* or the initial value, and the value of the current element).
|
||||
* function(previousValue, currentElement) : newValue.
|
||||
* @param {V} val The initial value to pass into the function on the first call.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within f.
|
||||
* @return {V} Result of evaluating f repeatedly across the values of
|
||||
* the iterator.
|
||||
* @template T,V
|
||||
*/
|
||||
goog.iter.reduce = function(iterable, f, val, opt_obj) {
|
||||
var rval = val;
|
||||
goog.iter.forEach(iterable, function(val) {
|
||||
rval = f.call(opt_obj, rval, val);
|
||||
});
|
||||
return rval;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Goes through the values in the iterator. Calls f for each these and if any of
|
||||
* them returns true, this returns true (without checking the rest). If all
|
||||
* return false this will return false.
|
||||
*
|
||||
* @param {goog.iter.Iterable} iterable The iterator object.
|
||||
* @param {function(this:T,?,undefined,?):boolean} f The function to call for
|
||||
* every value. This function
|
||||
* takes 3 arguments (the value, undefined, and the iterator) and should
|
||||
* return a boolean.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this' within
|
||||
* {@code f}.
|
||||
* @return {boolean} true if any value passes the test.
|
||||
* @template T
|
||||
*/
|
||||
goog.iter.some = function(iterable, f, opt_obj) {
|
||||
iterable = goog.iter.toIterator(iterable);
|
||||
/** @preserveTry */
|
||||
try {
|
||||
while (true) {
|
||||
if (f.call(opt_obj, iterable.next(), undefined, iterable)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
if (ex !== goog.iter.StopIteration) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Goes through the values in the iterator. Calls f for each these and if any of
|
||||
* them returns false this returns false (without checking the rest). If all
|
||||
* return true this will return true.
|
||||
*
|
||||
* @param {goog.iter.Iterable} iterable The iterator object.
|
||||
* @param {function(this:T,?,undefined,?):boolean} f The function to call for
|
||||
* every value. This function
|
||||
* takes 3 arguments (the value, undefined, and the iterator) and should
|
||||
* return a boolean.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this' within
|
||||
* {@code f}.
|
||||
* @return {boolean} true if every value passes the test.
|
||||
* @template T
|
||||
*/
|
||||
goog.iter.every = function(iterable, f, opt_obj) {
|
||||
iterable = goog.iter.toIterator(iterable);
|
||||
/** @preserveTry */
|
||||
try {
|
||||
while (true) {
|
||||
if (!f.call(opt_obj, iterable.next(), undefined, iterable)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
if (ex !== goog.iter.StopIteration) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Takes zero or more iterators and returns one iterator that will iterate over
|
||||
* them in the order chained.
|
||||
* @param {...goog.iter.Iterator} var_args Any number of iterator objects.
|
||||
* @return {!goog.iter.Iterator} Returns a new iterator that will iterate over
|
||||
* all the given iterators' contents.
|
||||
*/
|
||||
goog.iter.chain = function(var_args) {
|
||||
var args = arguments;
|
||||
var length = args.length;
|
||||
var i = 0;
|
||||
var newIter = new goog.iter.Iterator;
|
||||
|
||||
/**
|
||||
* @return {*} The next item in the iteration.
|
||||
* @this {goog.iter.Iterator}
|
||||
*/
|
||||
newIter.next = function() {
|
||||
/** @preserveTry */
|
||||
try {
|
||||
if (i >= length) {
|
||||
throw goog.iter.StopIteration;
|
||||
}
|
||||
var current = goog.iter.toIterator(args[i]);
|
||||
return current.next();
|
||||
} catch (ex) {
|
||||
if (ex !== goog.iter.StopIteration || i >= length) {
|
||||
throw ex;
|
||||
} else {
|
||||
// In case we got a StopIteration increment counter and try again.
|
||||
i++;
|
||||
return this.next();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Builds a new iterator that iterates over the original, but skips elements as
|
||||
* long as a supplied function returns true.
|
||||
* @param {goog.iter.Iterable} iterable The iterator object.
|
||||
* @param {function(this:T,?,undefined,?):boolean} f The function to call for
|
||||
* every value. This function
|
||||
* takes 3 arguments (the value, undefined, and the iterator) and should
|
||||
* return a boolean.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this' within
|
||||
* {@code f}.
|
||||
* @return {!goog.iter.Iterator} A new iterator that drops elements from the
|
||||
* original iterator as long as {@code f} is true.
|
||||
* @template T
|
||||
*/
|
||||
goog.iter.dropWhile = function(iterable, f, opt_obj) {
|
||||
var iterator = goog.iter.toIterator(iterable);
|
||||
var newIter = new goog.iter.Iterator;
|
||||
var dropping = true;
|
||||
newIter.next = function() {
|
||||
while (true) {
|
||||
var val = iterator.next();
|
||||
if (dropping && f.call(opt_obj, val, undefined, iterator)) {
|
||||
continue;
|
||||
} else {
|
||||
dropping = false;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Builds a new iterator that iterates over the original, but only as long as a
|
||||
* supplied function returns true.
|
||||
* @param {goog.iter.Iterable} iterable The iterator object.
|
||||
* @param {function(this:T,?,undefined,?):boolean} f The function to call for
|
||||
* every value. This function
|
||||
* takes 3 arguments (the value, undefined, and the iterator) and should
|
||||
* return a boolean.
|
||||
* @param {T=} opt_obj This is used as the 'this' object in f when called.
|
||||
* @return {!goog.iter.Iterator} A new iterator that keeps elements in the
|
||||
* original iterator as long as the function is true.
|
||||
* @template T
|
||||
*/
|
||||
goog.iter.takeWhile = function(iterable, f, opt_obj) {
|
||||
var iterator = goog.iter.toIterator(iterable);
|
||||
var newIter = new goog.iter.Iterator;
|
||||
var taking = true;
|
||||
newIter.next = function() {
|
||||
while (true) {
|
||||
if (taking) {
|
||||
var val = iterator.next();
|
||||
if (f.call(opt_obj, val, undefined, iterator)) {
|
||||
return val;
|
||||
} else {
|
||||
taking = false;
|
||||
}
|
||||
} else {
|
||||
throw goog.iter.StopIteration;
|
||||
}
|
||||
}
|
||||
};
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts the iterator to an array
|
||||
* @param {goog.iter.Iterable} iterable The iterator to convert to an array.
|
||||
* @return {!Array} An array of the elements the iterator iterates over.
|
||||
*/
|
||||
goog.iter.toArray = function(iterable) {
|
||||
// Fast path for array-like.
|
||||
if (goog.isArrayLike(iterable)) {
|
||||
return goog.array.toArray(/** @type {!goog.array.ArrayLike} */(iterable));
|
||||
}
|
||||
iterable = goog.iter.toIterator(iterable);
|
||||
var array = [];
|
||||
goog.iter.forEach(iterable, function(val) {
|
||||
array.push(val);
|
||||
});
|
||||
return array;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Iterates over 2 iterators and returns true if they contain the same sequence
|
||||
* of elements and have the same length.
|
||||
* @param {goog.iter.Iterable} iterable1 The first iterable object.
|
||||
* @param {goog.iter.Iterable} iterable2 The second iterable object.
|
||||
* @return {boolean} true if the iterators contain the same sequence of
|
||||
* elements and have the same length.
|
||||
*/
|
||||
goog.iter.equals = function(iterable1, iterable2) {
|
||||
iterable1 = goog.iter.toIterator(iterable1);
|
||||
iterable2 = goog.iter.toIterator(iterable2);
|
||||
var b1, b2;
|
||||
/** @preserveTry */
|
||||
try {
|
||||
while (true) {
|
||||
b1 = b2 = false;
|
||||
var val1 = iterable1.next();
|
||||
b1 = true;
|
||||
var val2 = iterable2.next();
|
||||
b2 = true;
|
||||
if (val1 != val2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
if (ex !== goog.iter.StopIteration) {
|
||||
throw ex;
|
||||
} else {
|
||||
if (b1 && !b2) {
|
||||
// iterable1 done but iterable2 is not done.
|
||||
return false;
|
||||
}
|
||||
if (!b2) {
|
||||
/** @preserveTry */
|
||||
try {
|
||||
// iterable2 not done?
|
||||
val2 = iterable2.next();
|
||||
// iterable2 not done but iterable1 is done
|
||||
return false;
|
||||
} catch (ex1) {
|
||||
if (ex1 !== goog.iter.StopIteration) {
|
||||
throw ex1;
|
||||
}
|
||||
// iterable2 done as well... They are equal
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Advances the iterator to the next position, returning the given default value
|
||||
* instead of throwing an exception if the iterator has no more entries.
|
||||
* @param {goog.iter.Iterable} iterable The iterable object.
|
||||
* @param {*} defaultValue The value to return if the iterator is empty.
|
||||
* @return {*} The next item in the iteration, or defaultValue if the iterator
|
||||
* was empty.
|
||||
*/
|
||||
goog.iter.nextOrValue = function(iterable, defaultValue) {
|
||||
try {
|
||||
return goog.iter.toIterator(iterable).next();
|
||||
} catch (e) {
|
||||
if (e != goog.iter.StopIteration) {
|
||||
throw e;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cartesian product of zero or more sets. Gives an iterator that gives every
|
||||
* combination of one element chosen from each set. For example,
|
||||
* ([1, 2], [3, 4]) gives ([1, 3], [1, 4], [2, 3], [2, 4]).
|
||||
* @see http://docs.python.org/library/itertools.html#itertools.product
|
||||
* @param {...!goog.array.ArrayLike.<*>} var_args Zero or more sets, as arrays.
|
||||
* @return {!goog.iter.Iterator} An iterator that gives each n-tuple (as an
|
||||
* array).
|
||||
*/
|
||||
goog.iter.product = function(var_args) {
|
||||
var someArrayEmpty = goog.array.some(arguments, function(arr) {
|
||||
return !arr.length;
|
||||
});
|
||||
|
||||
// An empty set in a cartesian product gives an empty set.
|
||||
if (someArrayEmpty || !arguments.length) {
|
||||
return new goog.iter.Iterator();
|
||||
}
|
||||
|
||||
var iter = new goog.iter.Iterator();
|
||||
var arrays = arguments;
|
||||
|
||||
// The first indicies are [0, 0, ...]
|
||||
var indicies = goog.array.repeat(0, arrays.length);
|
||||
|
||||
iter.next = function() {
|
||||
|
||||
if (indicies) {
|
||||
var retVal = goog.array.map(indicies, function(valueIndex, arrayIndex) {
|
||||
return arrays[arrayIndex][valueIndex];
|
||||
});
|
||||
|
||||
// Generate the next-largest indicies for the next call.
|
||||
// Increase the rightmost index. If it goes over, increase the next
|
||||
// rightmost (like carry-over addition).
|
||||
for (var i = indicies.length - 1; i >= 0; i--) {
|
||||
// Assertion prevents compiler warning below.
|
||||
goog.asserts.assert(indicies);
|
||||
if (indicies[i] < arrays[i].length - 1) {
|
||||
indicies[i]++;
|
||||
break;
|
||||
}
|
||||
|
||||
// We're at the last indicies (the last element of every array), so
|
||||
// the iteration is over on the next call.
|
||||
if (i == 0) {
|
||||
indicies = null;
|
||||
break;
|
||||
}
|
||||
// Reset the index in this column and loop back to increment the
|
||||
// next one.
|
||||
indicies[i] = 0;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
throw goog.iter.StopIteration;
|
||||
};
|
||||
|
||||
return iter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create an iterator to cycle over the iterable's elements indefinitely.
|
||||
* For example, ([1, 2, 3]) would return : 1, 2, 3, 1, 2, 3, ...
|
||||
* @see: http://docs.python.org/library/itertools.html#itertools.cycle.
|
||||
* @param {!goog.iter.Iterable} iterable The iterable object.
|
||||
* @return {!goog.iter.Iterator} An iterator that iterates indefinitely over
|
||||
* the values in {@code iterable}.
|
||||
*/
|
||||
goog.iter.cycle = function(iterable) {
|
||||
|
||||
var baseIterator = goog.iter.toIterator(iterable);
|
||||
|
||||
// We maintain a cache to store the iterable elements as we iterate
|
||||
// over them. The cache is used to return elements once we have
|
||||
// iterated over the iterable once.
|
||||
var cache = [];
|
||||
var cacheIndex = 0;
|
||||
|
||||
var iter = new goog.iter.Iterator();
|
||||
|
||||
// This flag is set after the iterable is iterated over once
|
||||
var useCache = false;
|
||||
|
||||
iter.next = function() {
|
||||
var returnElement = null;
|
||||
|
||||
// Pull elements off the original iterator if not using cache
|
||||
if (!useCache) {
|
||||
try {
|
||||
// Return the element from the iterable
|
||||
returnElement = baseIterator.next();
|
||||
cache.push(returnElement);
|
||||
return returnElement;
|
||||
} catch (e) {
|
||||
// If an exception other than StopIteration is thrown
|
||||
// or if there are no elements to iterate over (the iterable was empty)
|
||||
// throw an exception
|
||||
if (e != goog.iter.StopIteration || goog.array.isEmpty(cache)) {
|
||||
throw e;
|
||||
}
|
||||
// set useCache to true after we know that a 'StopIteration' exception
|
||||
// was thrown and the cache is not empty (to handle the 'empty iterable'
|
||||
// use case)
|
||||
useCache = true;
|
||||
}
|
||||
}
|
||||
|
||||
returnElement = cache[cacheIndex];
|
||||
cacheIndex = (cacheIndex + 1) % cache.length;
|
||||
|
||||
return returnElement;
|
||||
};
|
||||
|
||||
return iter;
|
||||
};
|
||||
Reference in New Issue
Block a user