165 lines
4.9 KiB
JavaScript
165 lines
4.9 KiB
JavaScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
export var Iterable;
|
|
(function (Iterable) {
|
|
function is(thing) {
|
|
return thing && typeof thing === 'object' && typeof thing[Symbol.iterator] === 'function';
|
|
}
|
|
Iterable.is = is;
|
|
const _empty = Object.freeze([]);
|
|
function empty() {
|
|
return _empty;
|
|
}
|
|
Iterable.empty = empty;
|
|
function* single(element) {
|
|
yield element;
|
|
}
|
|
Iterable.single = single;
|
|
function from(iterable) {
|
|
return iterable || _empty;
|
|
}
|
|
Iterable.from = from;
|
|
function isEmpty(iterable) {
|
|
return !iterable || iterable[Symbol.iterator]().next().done === true;
|
|
}
|
|
Iterable.isEmpty = isEmpty;
|
|
function first(iterable) {
|
|
return iterable[Symbol.iterator]().next().value;
|
|
}
|
|
Iterable.first = first;
|
|
function some(iterable, predicate) {
|
|
for (const element of iterable) {
|
|
if (predicate(element)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
Iterable.some = some;
|
|
function find(iterable, predicate) {
|
|
for (const element of iterable) {
|
|
if (predicate(element)) {
|
|
return element;
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
Iterable.find = find;
|
|
function* filter(iterable, predicate) {
|
|
for (const element of iterable) {
|
|
if (predicate(element)) {
|
|
yield element;
|
|
}
|
|
}
|
|
}
|
|
Iterable.filter = filter;
|
|
function* map(iterable, fn) {
|
|
let index = 0;
|
|
for (const element of iterable) {
|
|
yield fn(element, index++);
|
|
}
|
|
}
|
|
Iterable.map = map;
|
|
function* concat(...iterables) {
|
|
for (const iterable of iterables) {
|
|
for (const element of iterable) {
|
|
yield element;
|
|
}
|
|
}
|
|
}
|
|
Iterable.concat = concat;
|
|
function* concatNested(iterables) {
|
|
for (const iterable of iterables) {
|
|
for (const element of iterable) {
|
|
yield element;
|
|
}
|
|
}
|
|
}
|
|
Iterable.concatNested = concatNested;
|
|
function reduce(iterable, reducer, initialValue) {
|
|
let value = initialValue;
|
|
for (const element of iterable) {
|
|
value = reducer(value, element);
|
|
}
|
|
return value;
|
|
}
|
|
Iterable.reduce = reduce;
|
|
function forEach(iterable, fn) {
|
|
let index = 0;
|
|
for (const element of iterable) {
|
|
fn(element, index++);
|
|
}
|
|
}
|
|
Iterable.forEach = forEach;
|
|
/**
|
|
* Returns an iterable slice of the array, with the same semantics as `array.slice()`.
|
|
*/
|
|
function* slice(arr, from, to = arr.length) {
|
|
if (from < 0) {
|
|
from += arr.length;
|
|
}
|
|
if (to < 0) {
|
|
to += arr.length;
|
|
}
|
|
else if (to > arr.length) {
|
|
to = arr.length;
|
|
}
|
|
for (; from < to; from++) {
|
|
yield arr[from];
|
|
}
|
|
}
|
|
Iterable.slice = slice;
|
|
/**
|
|
* Consumes `atMost` elements from iterable and returns the consumed elements,
|
|
* and an iterable for the rest of the elements.
|
|
*/
|
|
function consume(iterable, atMost = Number.POSITIVE_INFINITY) {
|
|
const consumed = [];
|
|
if (atMost === 0) {
|
|
return [consumed, iterable];
|
|
}
|
|
const iterator = iterable[Symbol.iterator]();
|
|
for (let i = 0; i < atMost; i++) {
|
|
const next = iterator.next();
|
|
if (next.done) {
|
|
return [consumed, Iterable.empty()];
|
|
}
|
|
consumed.push(next.value);
|
|
}
|
|
return [consumed, { [Symbol.iterator]() { return iterator; } }];
|
|
}
|
|
Iterable.consume = consume;
|
|
/**
|
|
* Consumes `atMost` elements from iterable and returns the consumed elements,
|
|
* and an iterable for the rest of the elements.
|
|
*/
|
|
function collect(iterable) {
|
|
return consume(iterable)[0];
|
|
}
|
|
Iterable.collect = collect;
|
|
/**
|
|
* Returns whether the iterables are the same length and all items are
|
|
* equal using the comparator function.
|
|
*/
|
|
function equals(a, b, comparator = (at, bt) => at === bt) {
|
|
const ai = a[Symbol.iterator]();
|
|
const bi = b[Symbol.iterator]();
|
|
while (true) {
|
|
const an = ai.next();
|
|
const bn = bi.next();
|
|
if (an.done !== bn.done) {
|
|
return false;
|
|
}
|
|
else if (an.done) {
|
|
return true;
|
|
}
|
|
else if (!comparator(an.value, bn.value)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
Iterable.equals = equals;
|
|
})(Iterable || (Iterable = {}));
|