@rimbu/stream
Version:
Efficient structure representing a sequence of elements, with powerful operations for TypeScript
1,582 lines • 48.1 kB
JavaScript
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]];
}
}
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;
}
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.
*/
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,
};
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