Skip to content
Snippets Groups Projects
Commit d48e496c authored by David Sehnal's avatar David Sehnal
Browse files

simplified iterators

parent a91b5123
Branches
Tags
No related merge requests found
...@@ -5,64 +5,72 @@ ...@@ -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 = ...; * 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> { interface Iterator<T> {
[Symbol.iterator](): Iterator<T>, [Symbol.iterator](): Iterator<T>,
readonly done: boolean, readonly hasNext: boolean,
readonly value: T,
next(): { done: boolean, value: T }, next(): { done: boolean, value: T },
nextValue(): T move(): T
} }
class ArrayIteratorImpl<T> implements Iterator<T> { class ArrayIteratorImpl<T> implements Iterator<T> {
private xs: ArrayLike<T> = []; private xs: ArrayLike<T> = [];
private index: number = -1; private index: number = -1;
private length: number = 0; private length: number = 0;
private lastValue: T;
[Symbol.iterator]() { return this; }; [Symbol.iterator]() { return this; };
done = true; hasNext: boolean;
value: T = void 0 as any;
next() { next() {
const index = ++this.index; const value = this.move();
if (index < this.length) this.value = this.xs[index]; return { value, done: !this.hasNext };
else this.done = true;
return this;
} }
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>) { constructor(xs: ArrayLike<T>) {
this.length = xs.length; this.length = xs.length;
this.done = false; this.hasNext = xs.length > 0;
this.xs = xs; this.xs = xs;
this.index = -1; this.index = -1;
// try to avoid deoptimization with undefined values
this.lastValue = xs.length > 0 ? xs[0] : void 0 as any;
return this; return this;
} }
} }
class RangeIteratorImpl implements Iterator<number> { class RangeIteratorImpl implements Iterator<number> {
private value: number;
[Symbol.iterator]() { return this; }; [Symbol.iterator]() { return this; };
done = true; hasNext: boolean;
value: number;
next() { next() {
++this.value; const value = this.value;
this.done = this.value > this.max; return { value, done: !this.hasNext }
return this;
} }
nextValue() { return this.next().value; } move() {
++this.value;
this.hasNext = this.value <= this.max;
return this.value;
}
constructor(min: number, private max: number) { constructor(min: number, private max: number) {
this.value = min - 1; this.value = min - 1;
this.done = false; this.hasNext = max >= min;
return this; return this;
} }
} }
...@@ -75,7 +83,7 @@ namespace Iterator { ...@@ -75,7 +83,7 @@ namespace Iterator {
export function toArray<T>(it: Iterator<T>): T[] { export function toArray<T>(it: Iterator<T>): T[] {
const ret = []; 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; return ret;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment