From d48e496c5f8ac592ea50f53fac92ae2315080119 Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Fri, 20 Oct 2017 13:53:05 +0200 Subject: [PATCH] simplified iterators --- src/structure/collections/int-pair.ts | 2 +- src/structure/collections/iterator.ts | 52 +++++++++++++++------------ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/structure/collections/int-pair.ts b/src/structure/collections/int-pair.ts index 9e1bdd3c8..251b145cd 100644 --- a/src/structure/collections/int-pair.ts +++ b/src/structure/collections/int-pair.ts @@ -28,4 +28,4 @@ namespace IntPair { } } -export default IntPair +export default IntPair \ No newline at end of file diff --git a/src/structure/collections/iterator.ts b/src/structure/collections/iterator.ts index 8dd89ed87..79fdbd0f9 100644 --- a/src/structure/collections/iterator.ts +++ b/src/structure/collections/iterator.ts @@ -5,64 +5,72 @@ */ /** - * ES6 compatible mutable iterator. Use with care. + * ES6 compatible iterator. * - * "Idiomatic" usage: + * "Idiomatic" usage is to use the move function, because it does not make any allocations. * * const it = ...; - * for (let v = it.nextValue(); !it.done; v = it.nextValue()) { ... } + * for (let v = it.move(); it.hasNext; v = it.move()) { ... } */ interface Iterator<T> { [Symbol.iterator](): Iterator<T>, - readonly done: boolean, - readonly value: T, + readonly hasNext: boolean, next(): { done: boolean, value: T }, - nextValue(): T + move(): T } class ArrayIteratorImpl<T> implements Iterator<T> { private xs: ArrayLike<T> = []; private index: number = -1; private length: number = 0; + private lastValue: T; [Symbol.iterator]() { return this; }; - done = true; - value: T = void 0 as any; + hasNext: boolean; next() { - const index = ++this.index; - if (index < this.length) this.value = this.xs[index]; - else this.done = true; - return this; + const value = this.move(); + return { value, done: !this.hasNext }; } - nextValue() { return this.next().value; } + move() { + const index = ++this.index; + if (index < this.length) this.lastValue = this.xs[index]; + else this.hasNext = false; + return this.lastValue; + } constructor(xs: ArrayLike<T>) { this.length = xs.length; - this.done = false; + this.hasNext = xs.length > 0; this.xs = xs; this.index = -1; + // try to avoid deoptimization with undefined values + this.lastValue = xs.length > 0 ? xs[0] : void 0 as any; return this; } } class RangeIteratorImpl implements Iterator<number> { + private value: number; + [Symbol.iterator]() { return this; }; - done = true; - value: number; + hasNext: boolean; next() { - ++this.value; - this.done = this.value > this.max; - return this; + const value = this.value; + return { value, done: !this.hasNext } } - nextValue() { return this.next().value; } + move() { + ++this.value; + this.hasNext = this.value <= this.max; + return this.value; + } constructor(min: number, private max: number) { this.value = min - 1; - this.done = false; + this.hasNext = max >= min; return this; } } @@ -75,7 +83,7 @@ namespace Iterator { export function toArray<T>(it: Iterator<T>): T[] { const ret = []; - for (let v = it.nextValue(); !it.done; v = it.nextValue()) ret[ret.length] = v; + for (let v = it.move(); it.hasNext; v = it.move()) ret[ret.length] = v; return ret; } } -- GitLab