Path: blob/trunk/third_party/closure/goog/iter/iter.js
4115 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview Python style iteration utilities.8*/91011goog.provide('goog.iter');12goog.provide('goog.iter.Iterable');13goog.provide('goog.iter.Iterator');1415goog.require('goog.array');16goog.require('goog.asserts');17goog.require('goog.debug');18goog.require('goog.functions');19goog.require('goog.math');2021goog.require('goog.utils');222324/**25* @typedef {{length:number}|{__iterator__}}26*/27goog.iter.Iterable;282930/**31* Class/interface for iterators.32* @constructor33* @template VALUE34* @implements {Iterator<VALUE>}35* @deprecated Use objects implementing JavaScript iterable protocol introduced36* in ES6.37* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols38*/39goog.iter.Iterator = function() {};404142/**43* Returns the next value of the iteration as an an ES6 IIterableResult.44* @return {!IIterableResult<VALUE>}45* @override46*/47goog.iter.Iterator.prototype.next = function() {48'use strict';49return goog.iter.ES6_ITERATOR_DONE;50};515253/**54* An ES6 Iteration protocol result indicating iteration has completed for an55* iterator.56* @const {!IIterableResult<?>}57*/58goog.iter.ES6_ITERATOR_DONE = goog.debug.freeze({done: true, value: undefined});596061/**62* Wraps a VALUE in the ES6 Iterator protocol's IIterableResult container,63* including the compiler-mandated 'done' key, set to false.64* @param {VALUE} value65* @return {!IIterableResult<VALUE>} An ES6 Iteration Protocol compatible result66* object, indicating iteration is not done.67* @template VALUE68*/69goog.iter.createEs6IteratorYield = function(value) {70return {value, done: false};71};727374/**75* Returns the `Iterator` object itself. This is used to implement76* the iterator protocol in JavaScript 1.777* @param {boolean=} opt_keys Whether to return the keys or values. Default is78* to only return the values. This is being used by the for-in loop (true)79* and the for-each-in loop (false). Even though the param gives a hint80* about what the iterator will return there is no guarantee that it will81* return the keys when true is passed.82* @return {!goog.iter.Iterator<VALUE>} The object itself.83*/84goog.iter.Iterator.prototype.__iterator__ = function(opt_keys) {85'use strict';86return this;87};888990/**91* Returns an iterator that knows how to iterate over the values in the object.92* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable If the93* object is an iterator it will be returned as is. If the object has an94* `__iterator__` method that will be called to get the value95* iterator. If the object is an array-like object we create an iterator96* for that.97* @return {!goog.iter.Iterator<VALUE>} An iterator that knows how to iterate98* over the values in `iterable`.99* @template VALUE100*/101goog.iter.toIterator = function(iterable) {102'use strict';103if (iterable instanceof goog.iter.Iterator) {104return iterable;105}106if (typeof iterable.__iterator__ == 'function') {107return /** @type {{__iterator__:function(this:?, boolean=)}} */ (iterable)108.__iterator__(false);109}110if (goog.utils.isArrayLike(iterable)) {111const like = /** @type {!IArrayLike<number|string>} */ (iterable);112let i = 0;113const newIter =114/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());115/**116* @return {!IIterableResult<VALUE>}117* @override118*/119newIter.next = function() {120'use strict';121while (true) {122if (i >= like.length) {123return goog.iter.ES6_ITERATOR_DONE;124}125// Don't include deleted elements.126if (!(i in like)) {127i++;128continue;129}130return goog.iter.createEs6IteratorYield(like[i++]);131}132};133134return newIter;135}136137138// TODO(arv): Should we fall back on goog.structs.getValues()?139throw new Error('Not implemented');140};141142143/**144* Calls a function for each element in the iterator with the element of the145* iterator passed as argument.146*147* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator148* to iterate over. If the iterable is an object `toIterator` will be149* called on it.150* @param {function(this:THIS,VALUE,?,!goog.iter.Iterator<VALUE>)} f151* The function to call for every element. This function takes 3 arguments152* (the element, undefined, and the iterator) and the return value is153* irrelevant. The reason for passing undefined as the second argument is154* so that the same function can be used in {@see goog.array.forEach} as155* well as others. The third parameter is of type "number" for156* arraylike objects, undefined, otherwise.157* @param {THIS=} opt_obj The object to be used as the value of 'this' within158* `f`.159* @template THIS, VALUE160*/161goog.iter.forEach = function(iterable, f, opt_obj) {162'use strict';163if (goog.utils.isArrayLike(iterable)) {164// NOTES: this passes the index number to the second parameter165// of the callback contrary to the documentation above.166goog.array.forEach(167/** @type {IArrayLike<?>} */ (iterable), f, opt_obj);168} else {169const iterator = goog.iter.toIterator(iterable);170while (true) {171const {done, value} = iterator.next();172if (done) return;173f.call(opt_obj, value, undefined, iterator);174}175}176};177178179/**180* Calls a function for every element in the iterator, and if the function181* returns true adds the element to a new iterator.182*183* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator184* to iterate over.185* @param {186* function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f187* The function to call for every element. This function takes 3 arguments188* (the element, undefined, and the iterator) and should return a boolean.189* If the return value is true the element will be included in the returned190* iterator. If it is false the element is not included.191* @param {THIS=} opt_obj The object to be used as the value of 'this' within192* `f`.193* @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements194* that passed the test are present.195* @template THIS, VALUE196*/197goog.iter.filter = function(iterable, f, opt_obj) {198'use strict';199const iterator = goog.iter.toIterator(iterable);200const newIter =201/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());202/**203* @return {!IIterableResult<VALUE>}204* @override205*/206newIter.next = function() {207'use strict';208while (true) {209const {done, value} = iterator.next();210if (done) return goog.iter.ES6_ITERATOR_DONE;211if (f.call(opt_obj, value, undefined, iterator)) {212return goog.iter.createEs6IteratorYield(value);213}214}215};216217return newIter;218};219220221/**222* Calls a function for every element in the iterator, and if the function223* returns false adds the element to a new iterator.224*225* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator226* to iterate over.227* @param {228* function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f229* The function to call for every element. This function takes 3 arguments230* (the element, undefined, and the iterator) and should return a boolean.231* If the return value is false the element will be included in the returned232* iterator. If it is true the element is not included.233* @param {THIS=} opt_obj The object to be used as the value of 'this' within234* `f`.235* @return {!goog.iter.Iterator<VALUE>} A new iterator in which only elements236* that did not pass the test are present.237* @template THIS, VALUE238*/239goog.iter.filterFalse = function(iterable, f, opt_obj) {240'use strict';241return goog.iter.filter(iterable, goog.functions.not(f), opt_obj);242};243244245/**246* Creates a new iterator that returns the values in a range. This function247* can take 1, 2 or 3 arguments:248* <pre>249* range(5) same as range(0, 5, 1)250* range(2, 5) same as range(2, 5, 1)251* </pre>252*253* @param {number} startOrStop The stop value if only one argument is provided.254* The start value if 2 or more arguments are provided. If only one255* argument is used the start value is 0.256* @param {number=} opt_stop The stop value. If left out then the first257* argument is used as the stop value.258* @param {number=} opt_step The number to increment with between each call to259* next. This can be negative.260* @return {!goog.iter.Iterator<number>} A new iterator that returns the values261* in the range.262*/263goog.iter.range = function(startOrStop, opt_stop, opt_step) {264'use strict';265let start = 0;266let stop = startOrStop;267let step = opt_step || 1;268if (arguments.length > 1) {269start = startOrStop;270stop = +opt_stop;271}272if (step == 0) {273throw new Error('Range step argument must not be zero');274}275276const newIter =277/** @type {!goog.iter.Iterator<number>} */ (new goog.iter.Iterator());278/**279* @return {!IIterableResult<number>}280* @override281*/282newIter.next = function() {283'use strict';284if (step > 0 && start >= stop || step < 0 && start <= stop) {285return goog.iter.ES6_ITERATOR_DONE;286}287const rv = start;288start += step;289return goog.iter.createEs6IteratorYield(rv);290};291292return newIter;293};294295296/**297* Joins the values in a iterator with a delimiter.298* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator299* to get the values from.300* @param {string} deliminator The text to put between the values.301* @return {string} The joined value string.302* @template VALUE303*/304goog.iter.join = function(iterable, deliminator) {305'use strict';306return goog.iter.toArray(iterable).join(deliminator);307};308309310/**311* For every element in the iterator call a function and return a new iterator312* with that value.313*314* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The315* iterator to iterate over.316* @param {317* function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):RESULT} f318* The function to call for every element. This function takes 3 arguments319* (the element, undefined, and the iterator) and should return a new value.320* @param {THIS=} opt_obj The object to be used as the value of 'this' within321* `f`.322* @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the323* results of applying the function to each element in the original324* iterator.325* @template THIS, VALUE, RESULT326*/327goog.iter.map = function(iterable, f, opt_obj) {328'use strict';329const iterator = goog.iter.toIterator(iterable);330const newIter =331/** @type {!goog.iter.Iterator<RESULT>} */ (new goog.iter.Iterator());332/**333* @return {!IIterableResult<RESULT>}334* @override335*/336newIter.next = function() {337'use strict';338const {done, value} = iterator.next();339if (done) return goog.iter.ES6_ITERATOR_DONE;340const mappedVal = f.call(opt_obj, value, undefined, iterator);341return goog.iter.createEs6IteratorYield(mappedVal);342};343344return newIter;345};346347348/**349* Passes every element of an iterator into a function and accumulates the350* result.351*352* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable<VALUE>} iterable The353* iterator to iterate over.354* @param {function(this:THIS,RVALUE,VALUE):RVALUE} f The function to call for355* every element. This function takes 2 arguments (the function's previous356* result or the initial value, and the value of the current element).357* function(previousValue, currentElement) : newValue.358* @param {RVALUE} val The initial value to pass into the function on the first359* call.360* @param {THIS=} opt_obj The object to be used as the value of 'this' within361* f.362* @return {RVALUE} Result of evaluating f repeatedly across the values of363* the iterator.364* @template THIS, VALUE, RVALUE365*/366goog.iter.reduce = function(iterable, f, val, opt_obj) {367'use strict';368let rval = val;369goog.iter.forEach(iterable, function(val) {370'use strict';371rval = f.call(opt_obj, rval, val);372});373return rval;374};375376377/**378* Goes through the values in the iterator. Calls f for each of these, and if379* any of them returns true, this returns true (without checking the rest). If380* all return false this will return false.381*382* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator383* object.384* @param {385* function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f386* The function to call for every value. This function takes 3 arguments387* (the value, undefined, and the iterator) and should return a boolean.388* @param {THIS=} opt_obj The object to be used as the value of 'this' within389* `f`.390* @return {boolean} true if any value passes the test.391* @template THIS, VALUE392*/393goog.iter.some = function(iterable, f, opt_obj) {394'use strict';395const iterator = goog.iter.toIterator(iterable);396397while (true) {398const {done, value} = iterator.next();399if (done) return false;400if (f.call(opt_obj, value, undefined, iterator)) {401return true;402}403}404};405406407/**408* Goes through the values in the iterator. Calls f for each of these and if any409* of them returns false this returns false (without checking the rest). If all410* return true this will return true.411*412* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator413* object.414* @param {415* function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f416* The function to call for every value. This function takes 3 arguments417* (the value, undefined, and the iterator) and should return a boolean.418* @param {THIS=} opt_obj The object to be used as the value of 'this' within419* `f`.420* @return {boolean} true if every value passes the test.421* @template THIS, VALUE422*/423goog.iter.every = function(iterable, f, opt_obj) {424'use strict';425const iterator = goog.iter.toIterator(iterable);426427while (true) {428const {done, value} = iterator.next();429if (done) return true;430if (!f.call(opt_obj, value, undefined, iterator)) {431return false;432}433}434};435436437/**438* Takes zero or more iterables and returns one iterator that will iterate over439* them in the order chained.440* @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any441* number of iterable objects.442* @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will443* iterate over all the given iterables' contents.444* @template VALUE445*/446goog.iter.chain = function(var_args) {447'use strict';448return goog.iter.chainFromIterable(arguments);449};450451452/**453* Takes a single iterable containing zero or more iterables and returns one454* iterator that will iterate over each one in the order given.455* @see https://goo.gl/5NRp5d456* @param {goog.iter.Iterator<?>|goog.iter.Iterable} iterable The iterable of457* iterables to chain.458* @return {!goog.iter.Iterator<VALUE>} Returns a new iterator that will459* iterate over all the contents of the iterables contained within460* `iterable`.461* @template VALUE462*/463goog.iter.chainFromIterable = function(iterable) {464'use strict';465const iteratorOfIterators = goog.iter.toIterator(iterable);466const iter =467/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());468let current = null;469470/**471* @return {!IIterableResult<VALUE>}472* @override473*/474iter.next = function() {475'use strict';476while (true) {477if (current == null) {478const it = iteratorOfIterators.next();479if (it.done) return goog.iter.ES6_ITERATOR_DONE;480const value = /** @type {!goog.iter.Iterator<VALUE>} */ (it.value);481current = goog.iter.toIterator(value);482}483const it = current.next();484if (it.done) {485// If the child iterator is out of values, set current to null which486// triggers iterating over the parent above.487current = null;488continue;489}490const value = /** @type {VALUE} */ (it.value);491return goog.iter.createEs6IteratorYield(value);492}493};494495return iter;496};497498499/**500* Builds a new iterator that iterates over the original, but skips elements as501* long as a supplied function returns true.502* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator503* object.504* @param {505* function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f506* The function to call for every value. This function takes 3 arguments507* (the value, undefined, and the iterator) and should return a boolean.508* @param {THIS=} opt_obj The object to be used as the value of 'this' within509* `f`.510* @return {!goog.iter.Iterator<VALUE>} A new iterator that drops elements from511* the original iterator as long as `f` is true.512* @template THIS, VALUE513*/514goog.iter.dropWhile = function(iterable, f, opt_obj) {515'use strict';516const iterator = goog.iter.toIterator(iterable);517518const newIter =519/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());520let dropping = true;521522/**523* @return {!IIterableResult<VALUE>}524* @override525*/526newIter.next = function() {527'use strict';528while (true) {529const {done, value} = iterator.next();530if (done) return goog.iter.ES6_ITERATOR_DONE;531if (dropping && f.call(opt_obj, value, undefined, iterator)) {532continue;533} else {534dropping = false;535}536return goog.iter.createEs6IteratorYield(value);537}538};539540return newIter;541};542543544/**545* Builds a new iterator that iterates over the original, but only as long as a546* supplied function returns true.547* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator548* object.549* @param {550* function(this:THIS,VALUE,undefined,!goog.iter.Iterator<VALUE>):boolean} f551* The function to call for every value. This function takes 3 arguments552* (the value, undefined, and the iterator) and should return a boolean.553* @param {THIS=} opt_obj This is used as the 'this' object in f when called.554* @return {!goog.iter.Iterator<VALUE>} A new iterator that keeps elements in555* the original iterator as long as the function is true.556* @template THIS, VALUE557*/558goog.iter.takeWhile = function(iterable, f, opt_obj) {559'use strict';560const iterator = goog.iter.toIterator(iterable);561const iter =562/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());563564/**565* @return {!IIterableResult<VALUE>}566* @override567*/568iter.next = function() {569'use strict';570const {done, value} = iterator.next();571if (done) return goog.iter.ES6_ITERATOR_DONE;572if (f.call(opt_obj, value, undefined, iterator)) {573return goog.iter.createEs6IteratorYield(value);574}575return goog.iter.ES6_ITERATOR_DONE;576};577578return iter;579};580581582/**583* Converts the iterator to an array584* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterator585* to convert to an array.586* @return {!Array<VALUE>} An array of the elements the iterator iterates over.587* @template VALUE588*/589goog.iter.toArray = function(iterable) {590'use strict';591// Fast path for array-like.592if (goog.utils.isArrayLike(iterable)) {593return goog.array.toArray(/** @type {!IArrayLike<?>} */ (iterable));594}595iterable = goog.iter.toIterator(iterable);596const array = [];597goog.iter.forEach(iterable, function(val) {598'use strict';599array.push(val);600});601return array;602};603604605/**606* Iterates over two iterables and returns true if they contain the same607* sequence of elements and have the same length.608* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable1 The first609* iterable object.610* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable2 The second611* iterable object.612* @param {function(VALUE,VALUE):boolean=} opt_equalsFn Optional comparison613* function.614* Should take two arguments to compare, and return true if the arguments615* are equal. Defaults to {@link goog.array.defaultCompareEquality} which616* compares the elements using the built-in '===' operator.617* @return {boolean} true if the iterables contain the same sequence of elements618* and have the same length.619* @template VALUE620*/621goog.iter.equals = function(iterable1, iterable2, opt_equalsFn) {622'use strict';623const fillValue = {};624const pairs = goog.iter.zipLongest(fillValue, iterable1, iterable2);625const equalsFn = opt_equalsFn || goog.array.defaultCompareEquality;626return goog.iter.every(pairs, function(pair) {627'use strict';628return equalsFn(pair[0], pair[1]);629});630};631632633/**634* Advances the iterator to the next position, returning the given default value635* instead of throwing an exception if the iterator has no more entries.636* @param {goog.iter.Iterator<VALUE>|goog.iter.Iterable} iterable The iterable637* object.638* @param {VALUE} defaultValue The value to return if the iterator is empty.639* @return {VALUE} The next item in the iteration, or defaultValue if the640* iterator was empty.641* @template VALUE642*/643goog.iter.nextOrValue = function(iterable, defaultValue) {644'use strict';645const iterator = /** @type {!goog.iter.Iterator<VALUE>} */ (646goog.iter.toIterator(iterable));647const {done, value} = iterator.next();648if (done) return defaultValue;649return value;650};651652653/**654* Cartesian product of zero or more sets. Gives an iterator that gives every655* combination of one element chosen from each set. For example,656* ([1, 2], [3, 4]) gives ([1, 3], [1, 4], [2, 3], [2, 4]).657* @see http://docs.python.org/library/itertools.html#itertools.product658* @param {...!IArrayLike<VALUE>} var_args Zero or more sets, as659* arrays.660* @return {!goog.iter.Iterator<!Array<VALUE>>} An iterator that gives each661* n-tuple (as an array).662* @template VALUE663*/664goog.iter.product = function(var_args) {665'use strict';666const someArrayEmpty = Array.prototype.some.call(arguments, function(arr) {667'use strict';668return !arr.length;669});670671// An empty set in a cartesian product gives an empty set.672if (someArrayEmpty || !arguments.length) {673return /** @type {!goog.iter.Iterator<!Array<VALUE>>} */ (674new goog.iter.Iterator());675}676677const iter =678/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());679const arrays = arguments;680681// The first indices are [0, 0, ...]682/** @type {?Array<number>} */683let indices = goog.array.repeat(0, arrays.length);684685/**686* @return {!IIterableResult<VALUE>}687* @override688*/689iter.next = function() {690'use strict';691if (indices) {692const retVal = goog.array.map(indices, function(valueIndex, arrayIndex) {693'use strict';694return arrays[arrayIndex][valueIndex];695});696697// Generate the next-largest indices for the next call.698// Increase the rightmost index. If it goes over, increase the next699// rightmost (like carry-over addition).700for (let i = indices.length - 1; i >= 0; i--) {701// Assertion prevents compiler warning below.702goog.asserts.assert(indices);703if (indices[i] < arrays[i].length - 1) {704indices[i]++;705break;706}707708// We're at the last indices (the last element of every array), so709// the iteration is over on the next call.710if (i == 0) {711indices = null;712break;713}714// Reset the index in this column and loop back to increment the715// next one.716indices[i] = 0;717}718return goog.iter.createEs6IteratorYield(retVal);719}720721return goog.iter.ES6_ITERATOR_DONE;722};723724725return iter;726};727728729/**730* Create an iterator to cycle over the iterable's elements indefinitely.731* For example, ([1, 2, 3]) would return : 1, 2, 3, 1, 2, 3, ...732* @see: http://docs.python.org/library/itertools.html#itertools.cycle.733* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The734* iterable object.735* @return {!goog.iter.Iterator<VALUE>} An iterator that iterates indefinitely736* over the values in `iterable`.737* @template VALUE738*/739goog.iter.cycle = function(iterable) {740'use strict';741const baseIterator = /** @type {!goog.iter.Iterator<VALUE>} */ (742goog.iter.toIterator(iterable));743744// We maintain a cache to store the iterable elements as we iterate745// over them. The cache is used to return elements once we have746// iterated over the iterable once.747const cache = [];748let cacheIndex = 0;749750const iter =751/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());752753// This flag is set after the iterable is iterated over once754let useCache = false;755756/**757* @return {!IIterableResult<VALUE>}758* @override759*/760iter.next = function() {761'use strict';762let returnElement = null;763764// Pull elements off the original iterator if not using cache765if (!useCache) {766const it = baseIterator.next();767if (it.done) {768if (goog.array.isEmpty(cache)) {769return goog.iter.ES6_ITERATOR_DONE;770}771// set useCache to true after we've exhausted the inner iterator and772// there is at least one element in the cache.773useCache = true;774// Fallthrough to using the cache immediately.775} else {776cache.push(it.value);777return it;778}779}780781returnElement = cache[cacheIndex];782cacheIndex = (cacheIndex + 1) % cache.length;783784return goog.iter.createEs6IteratorYield(returnElement);785};786787return iter;788};789790791/**792* Creates an iterator that counts indefinitely from a starting value.793* @see http://docs.python.org/2/library/itertools.html#itertools.count794* @param {number=} opt_start The starting value. Default is 0.795* @param {number=} opt_step The number to increment with between each call to796* next. Negative and floating point numbers are allowed. Default is 1.797* @return {!goog.iter.Iterator<number>} A new iterator that returns the values798* in the series.799*/800goog.iter.count = function(opt_start, opt_step) {801'use strict';802let counter = opt_start || 0;803const step = (opt_step !== undefined) ? opt_step : 1;804const iter =805/** @type {!goog.iter.Iterator<number>} */ (new goog.iter.Iterator());806807/**808* @return {!IIterableResult<number>}809* @override @see {!goog.iter.Iterator}810*/811iter.next = function() {812'use strict';813const returnValue = counter;814counter += step;815return goog.iter.createEs6IteratorYield(returnValue);816};817818return iter;819};820821822/**823* Creates an iterator that returns the same object or value repeatedly.824* @param {VALUE} value Any object or value to repeat.825* @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the826* repeated value.827* @template VALUE828*/829goog.iter.repeat = function(value) {830'use strict';831const iter =832/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());833834/**835* @return {!IIterableResult<VALUE>}836* @override837*/838iter.next = function() {839return goog.iter.createEs6IteratorYield(value);840};841842return iter;843};844845846/**847* Creates an iterator that returns running totals from the numbers in848* `iterable`. For example, the array {@code [1, 2, 3, 4, 5]} yields849* {@code 1 -> 3 -> 6 -> 10 -> 15}.850* @see http://docs.python.org/3.2/library/itertools.html#itertools.accumulate851* @param {!goog.iter.Iterator<number>|!goog.iter.Iterable} iterable The852* iterable of numbers to accumulate.853* @return {!goog.iter.Iterator<number>} A new iterator that returns the854* numbers in the series.855*/856goog.iter.accumulate = function(iterable) {857'use strict';858const iterator = goog.iter.toIterator(iterable);859let total = 0;860const iter =861/** @type {!goog.iter.Iterator<number>} */ (new goog.iter.Iterator());862863/**864* @return {!IIterableResult<number>}865* @override @see {!goog.iter.Iterator}866*/867iter.next = function() {868'use strict';869const {done, value} = iterator.next();870if (done) return goog.iter.ES6_ITERATOR_DONE;871total += value;872return goog.iter.createEs6IteratorYield(total);873};874875return iter;876};877878879/**880* Creates an iterator that returns arrays containing the ith elements from the881* provided iterables. The returned arrays will be the same size as the number882* of iterables given in `var_args`. Once the shortest iterable is883* exhausted, subsequent calls to `next()` will return884* `goog.iter.ES6_ITERATOR_DONE`.885* @see http://docs.python.org/2/library/itertools.html#itertools.izip886* @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any887* number of iterable objects.888* @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns889* arrays of elements from the provided iterables.890* @template VALUE891*/892goog.iter.zip = function(var_args) {893'use strict';894const args = arguments;895const iter =896/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());897898if (args.length > 0) {899const iterators = goog.array.map(args, goog.iter.toIterator);900let allDone = false;901/**902* @return {!IIterableResult<VALUE>}903* @override904*/905iter.next = function() {906'use strict';907if (allDone) return goog.iter.ES6_ITERATOR_DONE;908909const arr = [];910for (let i = 0, iterator; iterator = iterators[i++];) {911const it = /** @type {!IIterableResult<VALUE>} */ (iterator.next());912if (it.done) {913// One of the iterators being zipped is done, so set allDone and914// return.915allDone = true;916return goog.iter.ES6_ITERATOR_DONE;917}918arr.push(it.value);919}920return goog.iter.createEs6IteratorYield(arr);921};922}923924return iter;925};926927928/**929* Creates an iterator that returns arrays containing the ith elements from the930* provided iterables. The returned arrays will be the same size as the number931* of iterables given in `var_args`. Shorter iterables will be extended932* with `fillValue`. Once the longest iterable is exhausted, subsequent933* calls to `next()` will return `goog.iter.ES6_ITERATOR_DONE`.934* @see http://docs.python.org/2/library/itertools.html#itertools.izip_longest935* @param {VALUE} fillValue The object or value used to fill shorter iterables.936* @param {...!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} var_args Any937* number of iterable objects.938* @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator that returns939* arrays of elements from the provided iterables.940* @template VALUE941*/942goog.iter.zipLongest = function(fillValue, var_args) {943'use strict';944const args = Array.prototype.slice.call(arguments, 1);945const iter =946/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());947948if (args.length > 0) {949const iterators = goog.array.map(args, goog.iter.toIterator);950951let allDone = false; // set to true once all iterators are empty.952/**953* @return {!IIterableResult<VALUE>}954* @override955*/956iter.next = function() {957'use strict';958if (allDone) return goog.iter.ES6_ITERATOR_DONE;959960let iteratorsHaveValues = false;961const arr = [];962for (let i = 0, iterator; iterator = iterators[i++];) {963const it = /** @type {!IIterableResult<VALUE>} */ (iterator.next());964if (it.done) {965// If this iterator is empty, others might not be, so use the966// fillValue.967arr.push(fillValue);968continue;969}970arr.push(it.value);971iteratorsHaveValues = true;972}973974if (!iteratorsHaveValues) {975allDone = true;976return goog.iter.ES6_ITERATOR_DONE;977}978return goog.iter.createEs6IteratorYield(arr);979};980}981982return iter;983};984985986/**987* Creates an iterator that filters `iterable` based on a series of988* `selectors`. On each call to `next()`, one item is taken from989* both the `iterable` and `selectors` iterators. If the item from990* `selectors` evaluates to true, the item from `iterable` is given.991* Otherwise, it is skipped. Once either `iterable` or `selectors`992* is exhausted, subsequent calls to `next()` will return993* `goog.iter.ES6_ITERATOR_DONE`.994* @see http://docs.python.org/2/library/itertools.html#itertools.compress995* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The996* iterable to filter.997* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} selectors An998* iterable of items to be evaluated in a boolean context to determine if999* the corresponding element in `iterable` should be included in the1000* result.1001* @return {!goog.iter.Iterator<VALUE>} A new iterator that returns the1002* filtered values.1003* @template VALUE1004*/1005goog.iter.compress = function(iterable, selectors) {1006'use strict';1007const valueIterator = goog.iter.toIterator(iterable);1008const selectorIterator = goog.iter.toIterator(selectors);10091010const iter =1011/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());10121013let allDone = false;10141015/**1016* @return {!IIterableResult<VALUE>}1017* @override1018*/1019iter.next = function() {1020if (allDone) return goog.iter.ES6_ITERATOR_DONE;10211022while (true) {1023const valIt = valueIterator.next();1024if (valIt.done) {1025allDone = true;1026return goog.iter.ES6_ITERATOR_DONE;1027}10281029const selectorIt = selectorIterator.next();1030if (selectorIt.done) {1031allDone = true;1032return goog.iter.ES6_ITERATOR_DONE;1033}10341035const val = valIt.value;1036const selectorVal = selectorIt.value;1037if (selectorVal) return goog.iter.createEs6IteratorYield(val);1038}1039};10401041return iter;1042};1043104410451046/**1047* Implements the `goog.iter.groupBy` iterator.1048* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1049* iterable to group.1050* @param {function(VALUE): KEY=} opt_keyFunc Optional function for1051* determining the key value for each group in the `iterable`. Default1052* is the identity function.1053* @constructor1054* @extends {goog.iter.Iterator<!Array<?>>}1055* @template KEY, VALUE1056* @private1057*/1058goog.iter.GroupByIterator_ = function(iterable, opt_keyFunc) {1059'use strict';1060/**1061* The iterable to group, coerced to an iterator.1062* @type {!goog.iter.Iterator}1063*/1064this.iterator = goog.iter.toIterator(iterable);10651066/**1067* A function for determining the key value for each element in the iterable.1068* If no function is provided, the identity function is used and returns the1069* element unchanged.1070* @type {function(VALUE): KEY}1071*/1072this.keyFunc = opt_keyFunc || goog.functions.identity;10731074/**1075* The target key for determining the start of a group.1076* @type {KEY}1077*/1078this.targetKey;10791080/**1081* The current key visited during iteration.1082* @type {KEY}1083*/1084this.currentKey;10851086/**1087* The current value being added to the group.1088* @type {VALUE}1089*/1090this.currentValue;1091};1092goog.utils.inherits(goog.iter.GroupByIterator_, goog.iter.Iterator);109310941095/**1096* @return {!IIterableResult<!Array<?>>}1097* @override1098*/1099goog.iter.GroupByIterator_.prototype.next = function() {1100'use strict';1101while (this.currentKey == this.targetKey) {1102const it = this.iterator.next();1103if (it.done) return goog.iter.ES6_ITERATOR_DONE;1104this.currentValue = it.value;1105this.currentKey = this.keyFunc(this.currentValue);1106}1107this.targetKey = this.currentKey;1108return goog.iter.createEs6IteratorYield(1109[this.currentKey, this.groupItems_(this.targetKey)]);1110};111111121113/**1114* Performs the grouping of objects using the given key.1115* @param {KEY} targetKey The target key object for the group.1116* @return {!Array<VALUE>} An array of grouped objects.1117* @private1118*/1119goog.iter.GroupByIterator_.prototype.groupItems_ = function(targetKey) {1120'use strict';1121const arr = [];1122while (this.currentKey == targetKey) {1123arr.push(this.currentValue);1124const it = this.iterator.next();1125if (it.done) break;1126this.currentValue = it.value;1127this.currentKey = this.keyFunc(this.currentValue);1128}1129return arr;1130};113111321133/**1134* Creates an iterator that returns arrays containing elements from the1135* `iterable` grouped by a key value. For iterables with repeated1136* elements (i.e. sorted according to a particular key function), this function1137* has a `uniq`-like effect. For example, grouping the array:1138* {@code [A, B, B, C, C, A]} produces1139* {@code [A, [A]], [B, [B, B]], [C, [C, C]], [A, [A]]}.1140* @see http://docs.python.org/2/library/itertools.html#itertools.groupby1141* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1142* iterable to group.1143* @param {function(VALUE): KEY=} opt_keyFunc Optional function for1144* determining the key value for each group in the `iterable`. Default1145* is the identity function.1146* @return {!goog.iter.Iterator<!Array<?>>} A new iterator that returns1147* arrays of consecutive key and groups.1148* @template KEY, VALUE1149*/1150goog.iter.groupBy = function(iterable, opt_keyFunc) {1151'use strict';1152return new goog.iter.GroupByIterator_(iterable, opt_keyFunc);1153};115411551156/**1157* Gives an iterator that gives the result of calling the given function1158* <code>f</code> with the arguments taken from the next element from1159* <code>iterable</code> (the elements are expected to also be iterables).1160*1161* Similar to {@see goog.iter.map} but allows the function to accept multiple1162* arguments from the iterable.1163*1164* @param {!goog.iter.Iterator<?>|!goog.iter.Iterable} iterable The iterable of1165* iterables to iterate over.1166* @param {function(this:THIS,...*):RESULT} f The function to call for every1167* element. This function takes N+2 arguments, where N represents the1168* number of items from the next element of the iterable. The two1169* additional arguments passed to the function are undefined and the1170* iterator itself. The function should return a new value.1171* @param {THIS=} opt_obj The object to be used as the value of 'this' within1172* `f`.1173* @return {!goog.iter.Iterator<RESULT>} A new iterator that returns the1174* results of applying the function to each element in the original1175* iterator.1176* @template THIS, RESULT1177*/1178goog.iter.starMap = function(iterable, f, opt_obj) {1179'use strict';1180const iterator = goog.iter.toIterator(iterable);1181const iter =1182/** @type {!goog.iter.Iterator<RESULT>} */ (new goog.iter.Iterator());11831184/**1185* @return {!IIterableResult<RESULT>}1186* @override1187*/1188iter.next = function() {1189'use strict';1190const it = /** @type {!IIterableResult<!goog.iter.Iterator<?>>} */ (1191iterator.next());1192if (it.done) return goog.iter.ES6_ITERATOR_DONE;1193const args = goog.iter.toArray(it.value);1194const value = f.apply(opt_obj, [].concat(args, undefined, iterator));1195return goog.iter.createEs6IteratorYield(value);1196};119711981199return iter;1200};120112021203/**1204* Returns an array of iterators each of which can iterate over the values in1205* `iterable` without advancing the others.1206* @see http://docs.python.org/2/library/itertools.html#itertools.tee1207* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1208* iterable to tee.1209* @param {number=} opt_num The number of iterators to create. Default is 2.1210* @return {!Array<goog.iter.Iterator<VALUE>>} An array of iterators.1211* @template VALUE1212*/1213goog.iter.tee = function(iterable, opt_num) {1214'use strict';1215const iterator = goog.iter.toIterator(iterable);1216const num = (typeof opt_num === 'number') ? opt_num : 2;1217const buffers = goog.array.map(goog.array.range(num), function() {1218'use strict';1219return [];1220});12211222/***1223* @return {boolean} True iff something was added to the buffers, false1224* otherwise. Used to signal whether there were any more iterators, or if1225* the parent iterator should indicate exhaustion.1226*/1227function addNextIteratorValueToBuffers() {1228'use strict';1229const {done, value} = iterator.next();1230if (done) return false;1231for (let i = 0, buffer; buffer = buffers[i++];) {1232buffer.push(value);1233}1234return true;1235}12361237/***1238* @param {!Array<VALUE>} buffer1239* @return {!goog.iter.Iterator<VALUE>}1240*/1241function createIterator(buffer) {1242'use strict';1243// Each tee'd iterator has an associated buffer (initially empty). When a1244// tee'd iterator's buffer is empty, it calls1245// addNextIteratorValueToBuffers(), adding the next value to all tee'd1246// iterators' buffers, and then returns that value. This allows each1247// iterator to be advanced independently.1248const iter =1249/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());12501251/**1252* @return {!IIterableResult<VALUE>}1253* @override1254*/1255iter.next = function() {1256'use strict';1257if (goog.array.isEmpty(buffer)) {1258const added = addNextIteratorValueToBuffers();1259if (!added) return goog.iter.ES6_ITERATOR_DONE;1260}1261goog.asserts.assert(!goog.array.isEmpty(buffer));1262return goog.iter.createEs6IteratorYield(buffer.shift());1263};12641265return iter;1266}12671268return goog.array.map(buffers, createIterator);1269};127012711272/**1273* Creates an iterator that returns arrays containing a count and an element1274* obtained from the given `iterable`.1275* @see http://docs.python.org/2/library/functions.html#enumerate1276* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1277* iterable to enumerate.1278* @param {number=} opt_start Optional starting value. Default is 0.1279* @return {!goog.iter.Iterator<!Array<?>>} A new iterator containing1280* count/item pairs.1281* @template VALUE1282*/1283goog.iter.enumerate = function(iterable, opt_start) {1284'use strict';1285return goog.iter.zip(goog.iter.count(opt_start), iterable);1286};128712881289/**1290* Creates an iterator that returns the first `limitSize` elements from an1291* iterable. If this number is greater than the number of elements in the1292* iterable, all the elements are returned.1293* @see http://goo.gl/V0sihp Inspired by the limit iterator in Guava.1294* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1295* iterable to limit.1296* @param {number} limitSize The maximum number of elements to return.1297* @return {!goog.iter.Iterator<VALUE>} A new iterator containing1298* `limitSize` elements.1299* @template VALUE1300*/1301goog.iter.limit = function(iterable, limitSize) {1302'use strict';1303goog.asserts.assert(goog.math.isInt(limitSize) && limitSize >= 0);13041305const iterator = goog.iter.toIterator(iterable);13061307const iter =1308/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());1309let remaining = limitSize;13101311/**1312* @return {!IIterableResult<VALUE>}1313* @override1314*/1315iter.next = function() {1316'use strict';1317if (remaining-- > 0) {1318return iterator.next();1319}1320return goog.iter.ES6_ITERATOR_DONE;1321};13221323return iter;1324};132513261327/**1328* Creates an iterator that is advanced `count` steps ahead. Consumed1329* values are silently discarded. If `count` is greater than the number1330* of elements in `iterable`, an empty iterator is returned. Subsequent1331* calls to `next()` will return `goog.iter.ES6_ITERATOR_DONE`.1332* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1333* iterable to consume.1334* @param {number} count The number of elements to consume from the iterator.1335* @return {!goog.iter.Iterator<VALUE>} An iterator advanced zero or more steps1336* ahead.1337* @template VALUE1338*/1339goog.iter.consume = function(iterable, count) {1340'use strict';1341goog.asserts.assert(goog.math.isInt(count) && count >= 0);13421343const iterator = goog.iter.toIterator(iterable);13441345while (count-- > 0) {1346goog.iter.nextOrValue(iterator, null);1347}13481349return iterator;1350};135113521353/**1354* Creates an iterator that returns a range of elements from an iterable.1355* Similar to {@see goog.array.slice} but does not support negative indexes.1356* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1357* iterable to slice.1358* @param {number} start The index of the first element to return.1359* @param {number=} opt_end The index after the last element to return. If1360* defined, must be greater than or equal to `start`.1361* @return {!goog.iter.Iterator<VALUE>} A new iterator containing a slice of1362* the original.1363* @template VALUE1364*/1365goog.iter.slice = function(iterable, start, opt_end) {1366'use strict';1367goog.asserts.assert(goog.math.isInt(start) && start >= 0);13681369let iterator = goog.iter.consume(iterable, start);13701371if (typeof opt_end === 'number') {1372goog.asserts.assert(goog.math.isInt(opt_end) && opt_end >= start);1373iterator = goog.iter.limit(iterator, opt_end - start /* limitSize */);1374}13751376return iterator;1377};137813791380/**1381* Checks an array for duplicate elements.1382* @param {?IArrayLike<VALUE>} arr The array to check for1383* duplicates.1384* @return {boolean} True, if the array contains duplicates, false otherwise.1385* @private1386* @template VALUE1387*/1388// TODO(user): Consider moving this into goog.array as a public function.1389goog.iter.hasDuplicates_ = function(arr) {1390'use strict';1391const deduped = [];1392goog.array.removeDuplicates(arr, deduped);1393return arr.length != deduped.length;1394};139513961397/**1398* Creates an iterator that returns permutations of elements in1399* `iterable`.1400*1401* Permutations are obtained by taking the Cartesian product of1402* `opt_length` iterables and filtering out those with repeated1403* elements. For example, the permutations of {@code [1,2,3]} are1404* {@code [[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1]]}.1405* @see http://docs.python.org/2/library/itertools.html#itertools.permutations1406* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1407* iterable from which to generate permutations.1408* @param {number=} opt_length Length of each permutation. If omitted, defaults1409* to the length of `iterable`.1410* @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing the1411* permutations of `iterable`.1412* @template VALUE1413*/1414goog.iter.permutations = function(iterable, opt_length) {1415'use strict';1416const elements = goog.iter.toArray(iterable);1417const length =1418(typeof opt_length === 'number') ? opt_length : elements.length;14191420const sets = goog.array.repeat(elements, length);1421const product = goog.iter.product.apply(undefined, sets);14221423return goog.iter.filter(product, function(arr) {1424'use strict';1425return !goog.iter.hasDuplicates_(arr);1426});1427};142814291430/**1431* Creates an iterator that returns combinations of elements from1432* `iterable`.1433*1434* Combinations are obtained by taking the {@see goog.iter.permutations} of1435* `iterable` and filtering those whose elements appear in the order they1436* are encountered in `iterable`. For example, the 3-length combinations1437* of {@code [0,1,2,3]} are {@code [[0,1,2], [0,1,3], [0,2,3], [1,2,3]]}.1438* @see http://docs.python.org/2/library/itertools.html#itertools.combinations1439* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1440* iterable from which to generate combinations.1441* @param {number} length The length of each combination.1442* @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing1443* combinations from the `iterable`.1444* @template VALUE1445*/1446goog.iter.combinations = function(iterable, length) {1447'use strict';1448const elements = goog.iter.toArray(iterable);1449const indexes = goog.iter.range(elements.length);1450const indexIterator = goog.iter.permutations(indexes, length);1451// sortedIndexIterator will now give arrays of with the given length that1452// indicate what indexes into "elements" should be returned on each iteration.1453const sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) {1454'use strict';1455return goog.array.isSorted(arr);1456});14571458const iter =1459/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());14601461function getIndexFromElements(index) {1462return elements[index];1463}1464/**1465* @return {!IIterableResult<!Array<VALUE>>}1466* @override1467*/1468iter.next = function() {1469'use strict';1470const {done, value} = sortedIndexIterator.next();1471if (done) return goog.iter.ES6_ITERATOR_DONE;1472return goog.iter.createEs6IteratorYield(1473goog.array.map(value, getIndexFromElements));1474};14751476return iter;1477};147814791480/**1481* Creates an iterator that returns combinations of elements from1482* `iterable`, with repeated elements possible.1483*1484* Combinations are obtained by taking the Cartesian product of `length`1485* iterables and filtering those whose elements appear in the order they are1486* encountered in `iterable`. For example, the 2-length combinations of1487* {@code [1,2,3]} are {@code [[1,1], [1,2], [1,3], [2,2], [2,3], [3,3]]}.1488* @see https://goo.gl/C0yXe41489* @see https://goo.gl/djOCsk1490* @param {!goog.iter.Iterator<VALUE>|!goog.iter.Iterable} iterable The1491* iterable to combine.1492* @param {number} length The length of each combination.1493* @return {!goog.iter.Iterator<!Array<VALUE>>} A new iterator containing1494* combinations from the `iterable`.1495* @template VALUE1496*/1497goog.iter.combinationsWithReplacement = function(iterable, length) {1498'use strict';1499const elements = goog.iter.toArray(iterable);1500const indexes = goog.array.range(elements.length);1501const sets = goog.array.repeat(indexes, length);1502const indexIterator = goog.iter.product.apply(undefined, sets);1503// sortedIndexIterator will now give arrays of with the given length that1504// indicate what indexes into "elements" should be returned on each iteration.1505const sortedIndexIterator = goog.iter.filter(indexIterator, function(arr) {1506'use strict';1507return goog.array.isSorted(arr);1508});15091510const iter =1511/** @type {!goog.iter.Iterator<VALUE>} */ (new goog.iter.Iterator());15121513function getIndexFromElements(index) {1514return elements[index];1515}15161517/**1518* @return {!IIterableResult<!Array<VALUE>>}1519* @override1520*/1521iter.next = function() {1522'use strict';1523const {done, value} = sortedIndexIterator.next();1524if (done) return goog.iter.ES6_ITERATOR_DONE;1525return goog.iter.createEs6IteratorYield(goog.array.map(1526/** @type {!Array<number>} */ (value), getIndexFromElements));1527};15281529return iter;1530};153115321533