Edouard@3484: /*
Edouard@3484: 
Edouard@3484: From https://github.com/keyvan-m-sadeghi/pythonic
Edouard@3484: 
Edouard@3484: Slightly modified in order to be usable in browser (i.e. not as a node.js module)
Edouard@3484: 
Edouard@3484: The MIT License (MIT)
Edouard@3484: 
Edouard@3484: Copyright (c) 2016 Assister.Ai
Edouard@3484: 
Edouard@3484: Permission is hereby granted, free of charge, to any person obtaining a copy of
Edouard@3484: this software and associated documentation files (the "Software"), to deal in
Edouard@3484: the Software without restriction, including without limitation the rights to
Edouard@3484: use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
Edouard@3484: the Software, and to permit persons to whom the Software is furnished to do so,
Edouard@3484: subject to the following conditions:
Edouard@3484: 
Edouard@3484: The above copyright notice and this permission notice shall be included in all
Edouard@3484: copies or substantial portions of the Software.
Edouard@3484: 
Edouard@3484: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Edouard@3484: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
Edouard@3484: FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
Edouard@3484: COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
Edouard@3484: IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Edouard@3484: CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Edouard@3484: */
Edouard@3484: 
Edouard@3484: class Iterator {
Edouard@3484:     constructor(generator) {
Edouard@3484:         this[Symbol.iterator] = generator;
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     async * [Symbol.asyncIterator]() {
Edouard@3484:         for (const element of this) {
Edouard@3484:             yield await element;
Edouard@3484:         }
Edouard@3484:     }
Edouard@3484: 
Edouard@3485:     forEach(callback) {
Edouard@3485:         for (const element of this) {
Edouard@3485:             callback(element);
Edouard@3485:         }
Edouard@3485:     }
Edouard@3485: 
Edouard@3484:     map(callback) {
Edouard@3484:         const result = [];
Edouard@3484:         for (const element of this) {
Edouard@3484:             result.push(callback(element));
Edouard@3484:         }
Edouard@3484: 
Edouard@3484:         return result;
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     filter(callback) {
Edouard@3484:         const result = [];
Edouard@3484:         for (const element of this) {
Edouard@3484:             if (callback(element)) {
Edouard@3484:                 result.push(element);
Edouard@3484:             }
Edouard@3484:         }
Edouard@3484: 
Edouard@3484:         return result;
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     reduce(callback, initialValue) {
Edouard@3484:         let empty = typeof initialValue === 'undefined';
Edouard@3484:         let accumulator = initialValue;
Edouard@3484:         let index = 0;
Edouard@3484:         for (const currentValue of this) {
Edouard@3484:             if (empty) {
Edouard@3484:                 accumulator = currentValue;
Edouard@3484:                 empty = false;
Edouard@3484:                 continue;
Edouard@3484:             }
Edouard@3484: 
Edouard@3484:             accumulator = callback(accumulator, currentValue, index, this);
Edouard@3484:             index++;
Edouard@3484:         }
Edouard@3484: 
Edouard@3484:         if (empty) {
Edouard@3484:             throw new TypeError('Reduce of empty Iterator with no initial value');
Edouard@3484:         }
Edouard@3484: 
Edouard@3484:         return accumulator;
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     some(callback) {
Edouard@3484:         for (const element of this) {
Edouard@3484:             if (callback(element)) {
Edouard@3484:                 return true;
Edouard@3484:             }
Edouard@3484:         }
Edouard@3484: 
Edouard@3484:         return false;
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     every(callback) {
Edouard@3484:         for (const element of this) {
Edouard@3484:             if (!callback(element)) {
Edouard@3484:                 return false;
Edouard@3484:             }
Edouard@3484:         }
Edouard@3484: 
Edouard@3484:         return true;
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     static fromIterable(iterable) {
Edouard@3484:         return new Iterator(function * () {
Edouard@3484:             for (const element of iterable) {
Edouard@3484:                 yield element;
Edouard@3484:             }
Edouard@3484:         });
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     toArray() {
Edouard@3484:         return Array.from(this);
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     next() {
Edouard@3484:         if (!this.currentInvokedGenerator) {
Edouard@3484:             this.currentInvokedGenerator = this[Symbol.iterator]();
Edouard@3484:         }
Edouard@3484: 
Edouard@3484:         return this.currentInvokedGenerator.next();
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     reset() {
Edouard@3484:         delete this.currentInvokedGenerator;
Edouard@3484:     }
Edouard@3484: }
Edouard@3484: 
Edouard@3484: function rangeSimple(stop) {
Edouard@3484:     return new Iterator(function * () {
Edouard@3484:         for (let i = 0; i < stop; i++) {
Edouard@3484:             yield i;
Edouard@3484:         }
Edouard@3484:     });
Edouard@3484: }
Edouard@3484: 
Edouard@3484: function rangeOverload(start, stop, step = 1) {
Edouard@3484:     return new Iterator(function * () {
Edouard@3484:         for (let i = start; i < stop; i += step) {
Edouard@3484:             yield i;
Edouard@3484:         }
Edouard@3484:     });
Edouard@3484: }
Edouard@3484: 
Edouard@3484: function range(...args) {
Edouard@3484:     if (args.length < 2) {
Edouard@3484:         return rangeSimple(...args);
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     return rangeOverload(...args);
Edouard@3484: }
Edouard@3484: 
Edouard@3484: function enumerate(iterable) {
Edouard@3484:     return new Iterator(function * () {
Edouard@3484:         let index = 0;
Edouard@3484:         for (const element of iterable) {
Edouard@3484:             yield [index, element];
Edouard@3484:             index++;
Edouard@3484:         }
Edouard@3484:     });
Edouard@3484: }
Edouard@3484: 
Edouard@3484: const _zip = longest => (...iterables) => {
Edouard@3594:     if (iterables.length == 0) {
Edouard@3594:         // works starting with 1 iterable
Edouard@3594:         // [a,b,c] -> [[a],[b],[c]]
Edouard@3594:         // [a,b,c],[d,e,f] -> [[a,d],[b,e],[c,f]]
Edouard@3594:         throw new TypeError("zip takes 1 iterables at least, "+iterables.length+" given");
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     return new Iterator(function * () {
Edouard@3484:         const iterators = iterables.map(iterable => Iterator.fromIterable(iterable));
Edouard@3484:         while (true) {
Edouard@3484:             const row = iterators.map(iterator => iterator.next());
Edouard@3484:             const check = longest ? row.every.bind(row) : row.some.bind(row);
Edouard@3484:             if (check(next => next.done)) {
Edouard@3484:                 return;
Edouard@3484:             }
Edouard@3484: 
Edouard@3484:             yield row.map(next => next.value);
Edouard@3484:         }
Edouard@3484:     });
Edouard@3484: };
Edouard@3484: 
Edouard@3484: const zip = _zip(false), zipLongest= _zip(true);
Edouard@3484: 
Edouard@3484: function items(obj) {
Edouard@3484:     let {keys, get} = obj;
Edouard@3484:     if (obj instanceof Map) {
Edouard@3484:         keys = keys.bind(obj);
Edouard@3484:         get = get.bind(obj);
Edouard@3484:     } else {
Edouard@3484:         keys = function () {
Edouard@3484:             return Object.keys(obj);
Edouard@3484:         };
Edouard@3484: 
Edouard@3484:         get = function (key) {
Edouard@3484:             return obj[key];
Edouard@3484:         };
Edouard@3484:     }
Edouard@3484: 
Edouard@3484:     return new Iterator(function * () {
Edouard@3484:         for (const key of keys()) {
Edouard@3484:             yield [key, get(key)];
Edouard@3484:         }
Edouard@3484:     });
Edouard@3484: }
Edouard@3484: 
Edouard@3484: /*
Edouard@3484: module.exports = {Iterator, range, enumerate, zip: _zip(false), zipLongest: _zip(true), items};
Edouard@3484: */