UNPKG

@rimbu/stream

Version:

Efficient structure representing a sequence of elements, with powerful operations for TypeScript

1,603 lines 48.9 kB
var _a; import { RimbuError } from '@rimbu/base'; import { Comp, Eq, ErrBase, IndexRange, OptLazy, Range, TraverseState, } from '@rimbu/common'; import { Reducer, Transformer, } from '@rimbu/stream'; import { AlwaysIterator, AppendIterator, ArrayIterator, ArrayReverseIterator, CollectIterator, ConcatIterator, DropIterator, DropWhileIterator, FilterApplyIterator, FilterIterator, FilterPureIterator, IndexedIterator, MapApplyIterator, MapIterator, MapPureIterator, PrependIterator, RandomIntIterator, RandomIterator, RangeDownIterator, RangeUpIterator, ReducerFastIterator, RepeatIterator, TakeIterator, TransformerFastIterator, UnfoldIterator, ZipAllWithItererator, ZipWithIterator, emptyFastIterator, isFastIterator, } from '@rimbu/stream/custom'; function* yieldObjKeys(obj) { for (const key in obj) { yield key; } } function* yieldObjValues(obj) { for (const key in obj) { yield obj[key]; } } function* yieldObjEntries(obj) { for (const key in obj) { yield [key, obj[key]]; } } /** * A reusable base implementation for `Stream` that provides all high-level operations * in terms of a `FastIterator` returned from `[Symbol.iterator]`. * * Custom stream implementations in `@rimbu/stream/custom` extend this class. * @typeparam T - the element type */ export class StreamBase { stream() { return this; } equals(other, { eq = Eq.objectIs, negate = false } = {}) { const it1 = this[Symbol.iterator](); const it2 = fromStreamSource(other)[Symbol.iterator](); const done = Symbol('Done'); while (true) { const v1 = it1.fastNext(done); const v2 = it2.fastNext(done); if (done === v1 || done === v2) { return Object.is(v1, v2); } if (eq(v1, v2) === negate) { return false; } } } assumeNonEmpty() { return this; } asNormal() { return this; } prepend(value) { return new PrependStream(this, value).assumeNonEmpty(); } append(value) { return new AppendStream(this, value).assumeNonEmpty(); } forEach(f, options = {}) { const { state = TraverseState() } = options; if (state.halted) return; const done = Symbol('Done'); let value; const iterator = this[Symbol.iterator](); const { halt } = state; while (!state.halted && done !== (value = iterator.fastNext(done))) { f(value, state.nextIndex(), halt); } } forEachPure(f, ...args) { const done = Symbol('Done'); let value; const iterator = this[Symbol.iterator](); while (done !== (value = iterator.fastNext(done))) { f(value, ...args); } } indexed(options = {}) { const { startIndex = 0 } = options; return new IndexedStream(this, startIndex); } filter(pred, options = {}) { const { negate = false } = options; return new FilterStream(this, pred, negate); } filterPure(options, ...args) { const { pred, negate = false } = options; return new FilterPureStream(this, pred, args, negate); } withOnly(values) { if (values.length <= 0) { return this; } const set = new Set(values); return this.filterPure({ pred: (v) => set.has(v) }); } without(values) { if (values.length <= 0) { return this; } const set = new Set(values); return this.filterPure({ pred: (v) => set.has(v), negate: true }); } map(mapFun) { return new MapStream(this, mapFun); } mapPure(mapFun, ...args) { return new MapPureStream(this, mapFun, args); } collect(collectFun) { return new CollectStream(this, collectFun); } flatMap(flatMapFun) { return this.transform(Transformer.flatMap(flatMapFun)); } flatZip(flatMapFun) { return this.transform(Transformer.flatZip(flatMapFun)); } transform(transformer) { return new TransformerStream(this, transformer); } first(otherwise) { return this[Symbol.iterator]().fastNext(otherwise); } last(otherwise) { const done = Symbol('Done'); let value; let lastValue = done; const iterator = this[Symbol.iterator](); while (done !== (value = iterator.fastNext(done))) { lastValue = value; } if (done === lastValue) { return OptLazy(otherwise); } return lastValue; } single(otherwise) { const iterator = this[Symbol.iterator](); const done = Symbol('Done'); const value = iterator.fastNext(done); if (done !== value) { if (done === iterator.fastNext(done)) { return value; } } return OptLazy(otherwise); } count() { let result = 0; const done = Symbol('Done'); const iterator = this[Symbol.iterator](); while (done !== iterator.fastNext(done)) { result++; } return result; } countElement(value, options = {}) { const { eq = Eq.objectIs, negate = false } = options; let result = 0; const done = Symbol('Done'); const iterator = this[Symbol.iterator](); let current; while (done !== (current = iterator.fastNext(done))) { if (eq(value, current) !== negate) { result++; } } return result; } find(pred, options = {}) { const { occurrance = 1, negate = false, otherwise } = options; if (occurrance <= 0) { return OptLazy(otherwise); } const done = Symbol('Done'); const iterator = this[Symbol.iterator](); let value; let remain = occurrance; let index = 0; while (done !== (value = iterator.fastNext(done))) { if (pred(value, index++) !== negate && --remain <= 0) { return value; } } return OptLazy(otherwise); } elementAt(index, otherwise) { if (index < 0) { return OptLazy(otherwise); } const done = Symbol('Done'); const iterator = this[Symbol.iterator](); let value; let i = 0; while (i <= index && done !== (value = iterator.fastNext(done))) { if (i === index) { return value; } i++; } return OptLazy(otherwise); } indicesWhere(pred, options = {}) { return this.transform(Transformer.indicesWhere(pred, options)); } indicesOf(searchValue, options = {}) { return this.transform(Transformer.indicesOf(searchValue, options)); } indexWhere(pred, options = {}) { const { occurrance = 1, negate = false } = options; if (occurrance <= 0) { return undefined; } const done = Symbol('Done'); let value; const iterator = this[Symbol.iterator](); let index = 0; let occ = 0; while (done !== (value = iterator.fastNext(done))) { const i = index++; if (pred(value, i) !== negate) { occ++; if (occ >= occurrance) { return i; } } } return undefined; } indexOf(searchValue, options = {}) { const { occurrance = 1 } = options; if (occurrance <= 0) { return undefined; } const { eq = Eq.objectIs, negate = false } = options; const done = Symbol('Done'); let value; const iterator = this[Symbol.iterator](); let index = 0; let occ = 0; while (done !== (value = iterator.fastNext(done))) { const i = index++; if (eq(value, searchValue) !== negate) { occ++; if (occ >= occurrance) { return i; } } } return undefined; } some(pred, options = {}) { return undefined !== this.indexWhere(pred, options); } every(pred, options = {}) { const { negate = false } = options; return undefined === this.indexWhere(pred, { negate: !negate }); } contains(searchValue, options = {}) { const { amount = 1 } = options; if (amount <= 0) { return true; } const { eq, negate } = options; return (undefined !== this.indexOf(searchValue, { occurrance: amount, eq, negate })); } containsSlice(source, options = {}) { return this.reduce(Reducer.containsSlice(source, options)); } takeWhile(pred, options = {}) { const { negate = false } = options; return this.filter((value, index, halt) => { const result = pred(value, index) !== negate; if (!result) { halt(); } return result; }); } dropWhile(pred, options = {}) { const { negate = false } = options; return new DropWhileStream(this, pred, negate); } take(amount) { if (amount <= 0) { return emptyStream; } return new TakeStream(this, amount); } drop(amount) { if (amount <= 0) { return this; } return new DropStream(this, amount); } repeat(amount) { if (undefined !== amount && amount <= 1) { return this; } return new FromStream(() => new RepeatIterator(this, amount)); } concat(...others) { if (others.every(isEmptyStreamSourceInstance)) { return this.assumeNonEmpty(); } return new ConcatStream(this, others).assumeNonEmpty(); } min(otherwise) { return this.minBy(Comp.defaultComp().compare, otherwise); } minBy(compare, otherwise) { const done = Symbol('Done'); const iterator = this[Symbol.iterator](); let result = iterator.fastNext(done); if (done === result) return OptLazy(otherwise); let value; while (done !== (value = iterator.fastNext(done))) { if (compare(value, result) < 0) result = value; } return result; } max(otherwise) { return this.maxBy(Comp.defaultComp().compare, otherwise); } maxBy(compare, otherwise) { const done = Symbol('Done'); const iterator = this[Symbol.iterator](); let result = iterator.fastNext(done); if (done === result) return OptLazy(otherwise); let value; while (done !== (value = iterator.fastNext(done))) { if (compare(value, result) > 0) result = value; } return result; } intersperse(sep) { if (isEmptyStreamSourceInstance(sep)) { return this; } return this.transform(Transformer.intersperse(sep)); } join({ sep = '', start = '', end = '', valueToString = String, ifEmpty = undefined, } = {}) { const done = Symbol('Done'); const iterator = this[Symbol.iterator](); let value = iterator.fastNext(done); if (done === value) { if (undefined !== ifEmpty) { return ifEmpty; } return start.concat(end); } let result = start.concat(valueToString(value)); while (done !== (value = iterator.fastNext(done))) { result = result.concat(sep, valueToString(value)); } return result.concat(end); } mkGroup({ sep = emptyStream, start = emptyStream, end = emptyStream, } = {}) { return fromStreamSource(start).concat(this.intersperse(sep), end); } splitWhere(pred, options = {}) { return this.transform(Transformer.splitWhere(pred, options)); } splitOn(sepElem, options = {}) { return this.transform(Transformer.splitOn(sepElem, options)); } splitOnSlice(sepSeq, options = {}) { return this.transform(Transformer.splitOnSlice(sepSeq, options)); } distinctPrevious(options = {}) { return this.transform(Transformer.distinctPrevious(options)); } window(windowSize, options = {}) { return this.transform(Transformer.window(windowSize, options)); } partition(pred, options = {}) { return this.reduce(Reducer.partition(pred, options)); } groupBy(valueToKey, options = {}) { return this.reduce(Reducer.groupBy(valueToKey, options)); } fold(init, next) { return this.reduce(Reducer.fold(init, next)); } foldStream(init, next) { return this.reduceStream(Reducer.fold(init, next)); } reduce(shape) { const reducerInstance = Reducer.combine(shape).compile(); const done = Symbol('Done'); let value; const iter = this[Symbol.iterator](); while (!reducerInstance.halted && done !== (value = iter.fastNext(done))) { reducerInstance.next(value); } return reducerInstance.getOutput(); } reduceStream(shape) { const reducer = Reducer.combine(shape); return new ReducerStream(this, reducer); } toArray() { const iterator = this[Symbol.iterator](); const result = []; const done = Symbol('Done'); let value; while (done !== (value = iterator.fastNext(done))) { result.push(value); } return result; } toString() { return `Stream(...<potentially empty>)`; } toJSON() { return { dataType: 'Stream', value: this.toArray(), }; } } class FromStream extends StreamBase { constructor(createIterator) { super(); this[_a] = undefined; this[Symbol.iterator] = createIterator; } } _a = Symbol.iterator; class PrependStream extends StreamBase { constructor(source, item) { super(); this.source = source; this.item = item; } [Symbol.iterator]() { return new PrependIterator(this.source[Symbol.iterator](), this.item); } first() { return OptLazy(this.item); } last() { return this.source.last(this.item); } count() { return this.source.count() + 1; } forEach(f, options = {}) { const { state = TraverseState() } = options; if (state.halted) return; f(OptLazy(this.item), state.nextIndex(), state.halt); if (state.halted) return; this.source.forEach(f, { state }); } mapPure(mapFun, ...args) { return new PrependStream(this.source.mapPure(mapFun, ...args), () => mapFun(OptLazy(this.item), ...args)); } take(amount) { if (amount <= 0) { return emptyStream; } if (amount === 1) { return StreamConstructorsImpl.of(OptLazy(this.item)); } return new PrependStream(this.source.take(amount - 1), this.item); } drop(amount) { if (amount <= 0) { return this; } if (amount === 1) { return this.source; } return this.source.drop(amount - 1); } minBy(compare) { const token = Symbol(); const result = this.source.minBy(compare, token); const itemValue = OptLazy(this.item); if (token === result) { return itemValue; } return compare(result, itemValue) <= 0 ? result : itemValue; } maxBy(compare) { const token = Symbol(); const result = this.source.maxBy(compare, token); const itemValue = OptLazy(this.item); if (token === result) { return itemValue; } return compare(result, itemValue) > 0 ? result : itemValue; } toArray() { const result = this.source.toArray(); result.unshift(OptLazy(this.item)); return result; } } class AppendStream extends StreamBase { constructor(source, item) { super(); this.source = source; this.item = item; } [Symbol.iterator]() { return new AppendIterator(this.source[Symbol.iterator](), this.item); } first() { return this.source.first(this.item); } last() { return OptLazy(this.item); } count() { return this.source.count() + 1; } forEach(f, options = {}) { const { state = TraverseState() } = options; if (state.halted) return; this.source.forEach(f, { state }); if (state.halted) return; f(OptLazy(this.item), state.nextIndex(), state.halt); } mapPure(mapFun, ...args) { return new AppendStream(this.source.mapPure(mapFun, ...args), () => mapFun(OptLazy(this.item), ...args)); } minBy(compare) { const token = Symbol(); const result = this.source.minBy(compare, token); const itemValue = OptLazy(this.item); if (token === result) { return itemValue; } return compare(result, itemValue) <= 0 ? result : itemValue; } maxBy(compare) { const token = Symbol(); const result = this.source.maxBy(compare, token); const itemValue = OptLazy(this.item); if (token === result) { return itemValue; } return compare(result, itemValue) > 0 ? result : itemValue; } toArray() { const result = this.source.toArray(); result.push(OptLazy(this.item)); return result; } } class MapStream extends StreamBase { constructor(source, mapFun) { super(); this.source = source; this.mapFun = mapFun; } [Symbol.iterator]() { return new MapIterator(this.source[Symbol.iterator](), this.mapFun); } first(otherwise) { const done = Symbol('Done'); const value = this.source.first(done); if (done === value) return OptLazy(otherwise); return this.mapFun(value, 0); } last(otherwise) { const done = Symbol('Done'); const value = this.source.last(done); if (done === value) return OptLazy(otherwise); return this.mapFun(value, 0); } count() { return this.source.count(); } elementAt(index, otherwise) { const done = Symbol('Done'); const value = this.source.elementAt(index, done); if (done === value) return OptLazy(otherwise); return this.mapFun(value, index); } map(mapFun) { return new MapStream(this.source, (value, index) => mapFun(this.mapFun(value, index), index)); } take(amount) { if (amount <= 0) { return emptyStream; } return new MapStream(this.source.take(amount), this.mapFun); } drop(amount) { if (amount <= 0) { return this; } return new MapStream(this.source.drop(amount), this.mapFun); } } class MapPureStream extends StreamBase { constructor(source, mapFun, args) { super(); this.source = source; this.mapFun = mapFun; this.args = args; } [Symbol.iterator]() { return new MapPureIterator(this.source[Symbol.iterator](), this.mapFun, this.args); } first(otherwise) { const done = Symbol('Done'); const value = this.source.first(done); if (done === value) return OptLazy(otherwise); return this.mapFun(value, ...this.args); } last(otherwise) { const done = Symbol('Done'); const value = this.source.last(done); if (done === value) return OptLazy(otherwise); return this.mapFun(value, ...this.args); } count() { return this.source.count(); } elementAt(index, otherwise) { const done = Symbol('Done'); const value = this.source.elementAt(index, done); if (done === value) return OptLazy(otherwise); return this.mapFun(value, ...this.args); } mapPure(mapFun, ...args) { return new MapPureStream(this.source, (value, ...args) => mapFun(this.mapFun(value, ...this.args), ...args), args); } take(amount) { if (amount <= 0) { return emptyStream; } return new MapPureStream(this.source.take(amount), this.mapFun, this.args); } drop(amount) { if (amount <= 0) { return this; } return new MapPureStream(this.source.drop(amount), this.mapFun, this.args); } } class ConcatStream extends StreamBase { constructor(source, otherSources) { super(); this.source = source; this.otherSources = otherSources; } [Symbol.iterator]() { return new ConcatIterator(this.source, this.otherSources, streamSourceHelpers); } forEach(f, options = {}) { const { state = TraverseState() } = options; if (state.halted) return; this.source.forEach(f, { state }); let sourceIndex = -1; const sources = this.otherSources; const length = sources.length; while (!state.halted && ++sourceIndex < length) { const source = sources[sourceIndex]; if (!isEmptyStreamSourceInstance(source)) { fromStreamSource(source).forEach(f, { state }); } } } forEachPure(f, ...args) { this.source.forEachPure(f, ...args); let sourceIndex = -1; const sources = this.otherSources; const length = sources.length; while (++sourceIndex < length) { const source = sources[sourceIndex]; if (!isEmptyStreamSourceInstance(source)) { fromStreamSource(source).forEachPure(f, ...args); } } } last(otherwise) { const sources = this.otherSources; let sourceIndex = sources.length; while (--sourceIndex >= 0) { const source = sources[sourceIndex]; if (!isEmptyStreamSourceInstance(source)) { const done = Symbol('Done'); const value = fromStreamSource(source).last(done); if (done !== value) return value; } } return this.source.last(otherwise); } count() { let result = this.source.count(); const sources = this.otherSources; const length = sources.length; let sourceIndex = -1; while (++sourceIndex < length) { const source = sources[sourceIndex]; if (!isEmptyStreamSourceInstance(source)) { result += fromStreamSource(source).count(); } } return result; } filterPure(options, ...args) { return new ConcatStream(this.source.filterPure(options, ...args), this.otherSources.map((source) => fromStreamSource(source).filterPure(options, ...args))); } mapPure(mapFun, ...args) { return new ConcatStream(this.source.mapPure(mapFun, ...args), this.otherSources.map((source) => fromStreamSource(source).mapPure(mapFun, ...args))); } concat(...others2) { return new ConcatStream(this.source, this.otherSources.concat(others2)); } toArray() { let result = this.source.toArray(); let sourceIndex = -1; const sources = this.otherSources; const length = sources.length; while (++sourceIndex < length) { const source = sources[sourceIndex]; if (!isEmptyStreamSourceInstance(source)) { result = result.concat(fromStreamSource(source).toArray()); } } return result; } } class IndexedStream extends StreamBase { constructor(source, startIndex) { super(); this.source = source; this.startIndex = startIndex; } [Symbol.iterator]() { return new IndexedIterator(this.source[Symbol.iterator](), this.startIndex); } first(otherwise) { const token = Symbol(); const sourceFirst = this.source.first(token); if (token === sourceFirst) { return OptLazy(otherwise); } return [0, sourceFirst]; } count() { return this.source.count(); } elementAt(index, otherwise) { const token = Symbol(); const elementAtSource = this.source.elementAt(index, token); if (token === elementAtSource) { return OptLazy(otherwise); } return [index, elementAtSource]; } take(amount) { if (amount <= 0) { return emptyStream; } return new IndexedStream(this.source.take(amount), this.startIndex); } toArray() { let index = this.startIndex; const iterator = this.source[Symbol.iterator](); const result = []; const done = Symbol('Done'); let value; while (done !== (value = iterator.fastNext(done))) { result.push([index++, value]); } return result; } } class FilterStream extends StreamBase { constructor(source, pred, negate = false) { super(); this.source = source; this.pred = pred; this.negate = negate; } [Symbol.iterator]() { return new FilterIterator(this.source[Symbol.iterator](), this.pred, this.negate); } filterPure(options, ...args) { const { pred, negate = false } = options; const { pred: thisPred, negate: thisNegate } = this; return new FilterStream(this.source, (value, index, halt) => thisPred(value, index, halt) !== thisNegate && pred(value, ...args) !== negate); } mapPure(mapFun, ...args) { const { pred, negate } = this; return new CollectStream(this.source, (value, index, skip, halt) => pred(value, index, halt) !== negate ? mapFun(value, ...args) : skip); } } class FilterPureStream extends StreamBase { constructor(source, pred, args, negate = false) { super(); this.source = source; this.pred = pred; this.args = args; this.negate = negate; } [Symbol.iterator]() { return new FilterPureIterator(this.source[Symbol.iterator](), this.pred, this.args, this.negate); } filterPure(options, ...args) { const { pred, negate = false } = options; const thisPred = this.pred; const thisArgs = this.args; const thisNegate = this.negate; return new FilterPureStream(this.source, (value, ...args) => { return (thisPred(value, ...thisArgs) !== thisNegate && pred(value, ...args) !== negate); }, args); } mapPure(mapFun, ...args) { const { pred, negate, args: thisArgs } = this; return new CollectStream(this.source, (value, _, skip) => pred(value, ...thisArgs) !== negate ? mapFun(value, ...args) : skip); } } class CollectStream extends StreamBase { constructor(source, collectFun) { super(); this.source = source; this.collectFun = collectFun; } [Symbol.iterator]() { return new CollectIterator(this.source[Symbol.iterator](), this.collectFun); } filterPure(options, ...args) { const { pred, negate = false } = options; const { collectFun } = this; return new CollectStream(this.source, (value, index, skip, halt) => { const result = collectFun(value, index, skip, halt); if (skip === result || pred(result, ...args) === negate) { return skip; } return result; }); } mapPure(mapFun, ...args) { const { collectFun } = this; return new CollectStream(this.source, (value, index, skip, halt) => { const result = collectFun(value, index, skip, halt); if (skip === result) { return skip; } return mapFun(result, ...args); }); } } class DropWhileStream extends StreamBase { constructor(source, pred, negate) { super(); this.source = source; this.pred = pred; this.negate = negate; } [Symbol.iterator]() { return new DropWhileIterator(this.source[Symbol.iterator](), this.pred, this.negate); } } class TakeStream extends StreamBase { constructor(source, amount) { super(); this.source = source; this.amount = amount; } [Symbol.iterator]() { return new TakeIterator(this.source[Symbol.iterator](), this.amount); } take(amount) { if (amount <= 0) { return emptyStream; } if (amount >= this.amount) { return this; } return this.source.take(amount); } } class DropStream extends StreamBase { constructor(source, amount) { super(); this.source = source; this.amount = amount; } [Symbol.iterator]() { return new DropIterator(this.source[Symbol.iterator](), this.amount); } drop(amount) { if (amount <= 0) { return this; } return this.source.drop(this.amount + amount); } } class SlowIteratorAdapter { constructor(source) { this.source = source; } next() { return this.source.next(); } fastNext(otherwise) { const result = this.source.next(); if (result.done) { return OptLazy(otherwise); } return result.value; } } class FromIterable extends StreamBase { constructor(iterable) { super(); this.iterable = iterable; } [Symbol.iterator]() { const iterator = this.iterable[Symbol.iterator](); if (isFastIterator(iterator)) return iterator; return new SlowIteratorAdapter(iterator); } } class EmptyStream extends StreamBase { [Symbol.iterator]() { return emptyFastIterator; } stream() { return this; } assumeNonEmpty() { RimbuError.throwEmptyCollectionAssumedNonEmptyError(); } equals(other) { const done = Symbol('Done'); return done === fromStreamSource(other)[Symbol.iterator]().fastNext(done); } prepend(value) { return StreamConstructorsImpl.of(OptLazy(value)); } append(value) { return StreamConstructorsImpl.of(OptLazy(value)); } forEach() { // } forEachPure() { // } indexed() { return this; } map() { return this; } mapPure() { return this; } flatMap() { return this; } flatZip() { return this; } transform(transformer) { return fromStreamSource(transformer.compile().getOutput()); } filter() { return this; } filterPure() { return this; } withOnly() { return this; } without() { return this; } collect() { return this; } first(otherwise) { return OptLazy(otherwise); } last(otherwise) { return OptLazy(otherwise); } single(otherwise) { return OptLazy(otherwise); } count() { return 0; } countElement() { return 0; } find(pred, options = {}) { const { otherwise } = options; return OptLazy(otherwise); } elementAt(index, otherwise) { return OptLazy(otherwise); } indicesWhere() { return this; } indicesOf() { return this; } indexWhere() { return undefined; } indexOf() { return undefined; } some() { return false; } every() { return true; } contains() { return false; } containsSlice() { return false; } takeWhile() { return this; } dropWhile() { return this; } take() { return this; } drop() { return this; } repeat() { return this; } concat(...others) { if (others.every(isEmptyStreamSourceInstance)) return this; const [source1, source2, ...sources] = others; if (undefined === source2) return source1; return fromStreamSource(source1).concat(source2, ...sources); } min(otherwise) { return OptLazy(otherwise); } minBy(compare, otherwise) { return OptLazy(otherwise); } max(otherwise) { return OptLazy(otherwise); } maxBy(compare, otherwise) { return OptLazy(otherwise); } intersperse() { return this; } join({ start = '', end = '', ifEmpty = undefined } = {}) { if (undefined !== ifEmpty) return ifEmpty; return start.concat(end); } mkGroup({ start = emptyStream, end = emptyStream, } = {}) { return fromStreamSource(start).concat(end); } splitOn() { return this; } splitWhere() { return this; } splitOnSlice() { return this; } distinctPrevious() { return this; } window() { return this; } partition(pred, options = {}) { const { collectorTrue = Reducer.toArray(), collectorFalse = Reducer.toArray(), } = options; return [ collectorTrue.compile().getOutput(), collectorFalse.compile().getOutput(), ]; } fold(init) { return OptLazy(init); } foldStream() { return this; } reduce(shape) { const reducer = Reducer.combine(shape); const instance = reducer.compile(); return instance.getOutput(); } reduceStream() { return this; } toArray() { return []; } toString() { return `Stream(<empty>)`; } toJSON() { return { dataType: 'Stream', value: [], }; } } class ArrayStream extends StreamBase { constructor(array, startIndex = 0, endIndex = array.length - 1, reversed = false) { super(); this.array = array; this.startIndex = startIndex; this.endIndex = endIndex; this.reversed = reversed; this.length = endIndex - startIndex + 1; } [Symbol.iterator]() { if (!this.reversed) { return new ArrayIterator(this.array, this.startIndex, this.endIndex); } return new ArrayReverseIterator(this.array, this.startIndex, this.endIndex); } forEach(f, options = {}) { const { state = TraverseState() } = options; const startIndex = this.startIndex; const endIndex = this.endIndex; const array = this.array; const { halt } = state; if (!this.reversed) { let i = this.startIndex - 1; while (!state.halted && ++i <= endIndex) { f(array[i], state.nextIndex(), halt); } } else { let i = endIndex + 1; while (!state.halted && --i >= startIndex) { f(array[i], state.nextIndex(), halt); } } } first(otherwise) { if (this.length <= 0) { return OptLazy(otherwise); } if (!this.reversed) { return this.array[this.startIndex]; } return this.array[this.endIndex]; } last(otherwise) { if (this.length <= 0) { return OptLazy(otherwise); } if (!this.reversed) { return this.array[this.endIndex]; } return this.array[this.startIndex]; } count() { return this.endIndex - this.startIndex + 1; } find(pred, options = {}) { const { occurrance = 1, negate = false, otherwise } = options; const startIndex = this.startIndex; const endIndex = this.endIndex; const array = this.array; let remain = occurrance; let index = 0; if (!this.reversed) { let i = startIndex - 1; while (++i <= endIndex) { const value = array[i]; if (pred(value, index++) !== negate && --remain <= 0) return value; } } else { let i = endIndex + 1; while (--i >= startIndex) { const value = array[i]; if (pred(value, index++) !== negate && --remain <= 0) return value; } } return OptLazy(otherwise); } elementAt(index, otherwise) { if (index < 0 || index >= this.length) { return OptLazy(otherwise); } if (!this.reversed) { return this.array[index + this.startIndex]; } return this.array[this.endIndex - index]; } indexOf(searchValue, options = {}) { const { occurrance = 1 } = options; if (occurrance <= 0) return undefined; const { eq = Object.is, negate = false } = options; let remain = occurrance; const startIndex = this.startIndex; const endIndex = this.endIndex; const array = this.array; if (!this.reversed) { let i = startIndex - 1; while (++i <= endIndex) { if (eq(array[i], searchValue) !== negate && --remain <= 0) return i - startIndex; } } else { let i = endIndex + 1; while (--i >= startIndex) { if (eq(array[i], searchValue) !== negate && --remain <= 0) return endIndex - i; } } return undefined; } take(amount) { if (amount <= 0) return emptyStream; if (amount >= this.length) return this; if (!this.reversed) { return new ArrayStream(this.array, this.startIndex, this.startIndex + amount - 1, this.reversed); } return new ArrayStream(this.array, this.endIndex - (amount - 1), this.endIndex, this.reversed); } drop(amount) { if (amount <= 0) return this; if (amount >= this.length) return emptyStream; if (!this.reversed) { return new ArrayStream(this.array, this.startIndex + amount, this.endIndex, this.reversed); } return new ArrayStream(this.array, this.startIndex, this.endIndex - amount, this.reversed); } toArray() { const array = this.array; if (typeof array === 'string') { return super.toArray(); } if (this.reversed) { // use normal iterator return super.toArray(); } return array.slice(this.startIndex, this.endIndex + 1); } } class AlwaysStream extends StreamBase { constructor(value) { super(); this.value = value; } [Symbol.iterator]() { return new AlwaysIterator(this.value); } first() { return this.value; } append() { return this; } forEach(f, options = {}) { const { state = TraverseState() } = options; const value = this.value; while (!state.halted) { f(value, state.nextIndex(), state.halt); } } elementAt() { return this.value; } repeat() { return this; } concat() { return this.assumeNonEmpty(); } min() { return this.value; } minBy() { return this.value; } max() { return this.value; } maxBy() { return this.value; } } class MapApplyStream extends StreamBase { constructor(source, f, args) { super(); this.source = source; this.f = f; this.args = args; } [Symbol.iterator]() { return new MapApplyIterator(this.source, this.f, this.args, streamSourceHelpers); } mapPure(mapFun, ...args) { const { f, args: thisArgs } = this; return new MapApplyStream(this.source, (...args2) => mapFun(f(...args2), ...args), thisArgs); } } class FilterApplyStream extends StreamBase { constructor(source, pred, args, negate = false) { super(); this.source = source; this.pred = pred; this.args = args; this.negate = negate; } [Symbol.iterator]() { return new FilterApplyIterator(this.source, this.pred, this.args, this.negate, streamSourceHelpers); } } class RangeStream extends StreamBase { constructor(start, end, delta = 1) { super(); this.start = start; this.end = end; this.delta = delta; } [Symbol.iterator]() { if (this.delta >= 0) { return new RangeUpIterator(this.start, this.end, this.delta); } return new RangeDownIterator(this.start, this.end, this.delta); } } class ReducerStream extends StreamBase { constructor(source, reducer) { super(); this.source = source; this.reducer = reducer; } [Symbol.iterator]() { return new ReducerFastIterator(this.source[Symbol.iterator](), this.reducer.compile()); } } class TransformerStream extends StreamBase { constructor(source, transformer) { super(); this.source = source; this.transformer = transformer; } [Symbol.iterator]() { return new TransformerFastIterator(this.source[Symbol.iterator](), this.transformer.compile()); } } const emptyStream = Object.freeze(new EmptyStream()); function isStream(obj) { return obj instanceof StreamBase; } /** * Converts any `StreamSource` into a concrete `Stream` implementation. * @typeparam T - the element type * @param source - the source to convert */ export const fromStreamSource = (source) => { if (undefined === source || isEmptyStreamSourceInstance(source)) return emptyStream; if (isStream(source)) return source; if (typeof source === 'object' && `stream` in source) return source.stream(); if (Array.isArray(source)) { if (source.length <= 0) return emptyStream; return new ArrayStream(source); } return new FromIterable(source); }; /** * Returns true if the given `source` StreamSource is known to be empty. * @param source - a StreamSource * @note * If this function returns false, it does not guarantee that the Stream is not empty. It only * means that it is not known if it is empty. */ /** * Returns true if the given `source` is a `StreamSource` that is known to be empty. * If this function returns `false`, the source may still be empty; it is simply not known. * @param source - a potential stream source */ export function isEmptyStreamSourceInstance(source) { if (source === '') return true; if (typeof source === 'object') { if (source === emptyStream || source === null) return true; if (`length` in source && source.length === 0) return true; if (`size` in source && source.size === 0) return true; if (`isEmpty` in source && source.isEmpty === true) return true; } return false; } const streamSourceHelpers = { fromStreamSource, isEmptyStreamSourceInstance, }; /** * Default implementation of the `StreamConstructors` interface. * This instance backs the exported `Stream` value. */ export const StreamConstructorsImpl = Object.freeze({ empty() { return emptyStream; }, of(...values) { return fromStreamSource(values); }, from(...sources) { const [first, ...rest] = sources; if (rest.length <= 0) { return fromStreamSource(first); } const [rest1, ...restOther] = rest; return fromStreamSource(first).concat(rest1, ...restOther); }, fromArray(array, options = {}) { if (array.length === 0) return emptyStream; const { range, reversed = false } = options; if (undefined === range) { return new ArrayStream(array, undefined, undefined, reversed); } const result = IndexRange.getIndicesFor(range, array.length); if (result === 'empty') { return emptyStream; } if (result === 'all') { return new ArrayStream(array, undefined, undefined, reversed); } return new ArrayStream(array, result[0], result[1], reversed); }, fromObjectKeys(obj) { return fromStreamSource(yieldObjKeys(obj)); }, fromObjectValues(obj) { return fromStreamSource(yieldObjValues(obj)); }, fromObject(obj) { return fromStreamSource(yieldObjEntries(obj)); }, fromString(source, options = {}) { return StreamConstructorsImpl.fromArray(source, options); }, always(value) { return new AlwaysStream(value); }, applyForEach(source, f, ...args) { const iter = fromStreamSource(source)[Symbol.iterator](); const done = Symbol(); let values; while (done !== (values = iter.fastNext(done))) { f(...values, ...args); } }, applyMap(source, mapFun, ...args) { return new MapApplyStream(source, mapFun, args); }, applyFilter(source, options, ...args) { const { pred, negate = false } = options; return new FilterApplyStream(source, pred, args, negate); }, range(range, options = {}) { const { delta = 1 } = options; if (undefined !== range.amount) { if (range.amount <= 0) return emptyStream; let startIndex = 0; if (undefined !== range.start) { if (Array.isArray(range.start)) { startIndex = range.start[0]; if (!range.start[1]) startIndex++; } else startIndex = range.start; } const endIndex = startIndex + range.amount - 1; return new RangeStream(startIndex, endIndex, delta); } const { start, end } = Range.getNormalizedRange(range); let startIndex = 0; let endIndex = undefined; if (undefined !== start) { startIndex = start[0]; if (!start[1]) startIndex++; } if (undefined !== end) { endIndex = end[0]; if (!end[1]) endIndex--; } if (undefined !== endIndex) { if (delta > 0 && endIndex < startIndex) return emptyStream; else if (delta < 0 && startIndex <= endIndex) return emptyStream; } return new RangeStream(startIndex, endIndex, delta); }, random() { return new FromStream(() => new RandomIterator()); }, randomInt(min, max) { if (min >= max) ErrBase.msg('min should be smaller than max'); return new FromStream(() => new RandomIntIterator(min, max)); }, unfold(init, next) { return new FromStream(() => new UnfoldIterator(init, next)); }, zipWith(...sources) { return (zipFun) => { if (sources.some(isEmptyStreamSourceInstance)) { return emptyStream; } return new FromStream(() => new ZipWithIterator(sources, zipFun, streamSourceHelpers)); }; }, zip(...sources) { return StreamConstructorsImpl.zipWith(...sources)(Array); }, zipAllWith(...sources) { return (fillValue, zipFun) => { if (sources.every(isEmptyStreamSourceInstance)) { return emptyStream; } return new FromStream(() => new ZipAllWithItererator(fillValue, sources, zipFun, streamSourceHelpers)); }; }, zipAll(fillValue, ...sources) { return StreamConstructorsImpl.zipAllWith(...sources)(fillValue, Array); }, flatten(source) { return fromStreamSource(source).flatMap((s) => s); }, unzip(source, options) { const { length } = options; if (isEmptyStreamSourceInstance(source)) { return StreamConstructorsImpl.of(emptyStream).repeat(length).toArray(); } const result = []; let i = -1; while (++i < length) { const index = i; result[i] = source.map((t) => t[index]); } return result; }, }); //# sourceMappingURL=stream-custom.mjs.map