From b47af067e6cc8fe7fcbbb4ebc1cefeb4b43fdbba Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Sat, 28 Oct 2017 00:39:52 +0200
Subject: [PATCH] dropped ES6 support for iterators

---
 .../collections/_spec/iterators.spec.ts       |  5 +-
 .../collections/_spec/segmentation.spec.ts    |  3 +-
 .../collections/integer/impl/segmentation.ts  | 16 ++---
 src/mol-base/collections/iterator.ts          | 43 ++++----------
 src/mol-data/_spec/atom-set.spec.ts           |  4 +-
 src/mol-data/atom-set/base.ts                 | 19 +++---
 src/perf-tests/iterators.ts                   | 59 +++++++++++--------
 src/perf-tests/sets.ts                        |  8 ++-
 8 files changed, 73 insertions(+), 84 deletions(-)

diff --git a/src/mol-base/collections/_spec/iterators.spec.ts b/src/mol-base/collections/_spec/iterators.spec.ts
index fba704b58..d5b34f527 100644
--- a/src/mol-base/collections/_spec/iterators.spec.ts
+++ b/src/mol-base/collections/_spec/iterators.spec.ts
@@ -8,7 +8,10 @@ import Iterator from '../iterator'
 
 function iteratorToArray<T>(it: Iterator<T>): T[] {
     const ret = [];
-    for (let v = it.move(); !it.done; v = it.move()) ret[ret.length] = v;
+    while (it.hasNext) {
+        const v = it.move();
+        ret[ret.length] = v;
+    }
     return ret;
 }
 
diff --git a/src/mol-base/collections/_spec/segmentation.spec.ts b/src/mol-base/collections/_spec/segmentation.spec.ts
index cac55f128..27b3708fd 100644
--- a/src/mol-base/collections/_spec/segmentation.spec.ts
+++ b/src/mol-base/collections/_spec/segmentation.spec.ts
@@ -22,7 +22,8 @@ describe('segments', () => {
         const it = Segmentation.segments(segs, data);
 
         const t = Object.create(null);
-        for (let s = it.move(); !it.done; s = it.move()) {
+        while (it.hasNext) {
+            const s = it.move();
             for (let j = s.start; j < s.end; j++) {
                 const x = t[s.index];
                 const v = OrderedSet.getAt(data, j);
diff --git a/src/mol-base/collections/integer/impl/segmentation.ts b/src/mol-base/collections/integer/impl/segmentation.ts
index af0dc2488..542b4daf2 100644
--- a/src/mol-base/collections/integer/impl/segmentation.ts
+++ b/src/mol-base/collections/integer/impl/segmentation.ts
@@ -33,21 +33,15 @@ class SegmentIterator implements Iterator<Segs.Segment> {
     private value: Segs.Segment = { index: 0, start: 0, end: 0 };
     private last: number = 0;
 
-    [Symbol.iterator]() { return new SegmentIterator(this.segments, this.set, this.inputRange); };
-    done: boolean = false;
-
-    next() {
-        const value = this.move();
-        return { value, done: this.done }
-    }
+    hasNext: boolean = false;
 
     move() {
-        this.done = this.segmentEnd <= this.segmentStart;
-        while (!this.done) {
+        while (this.hasNext) {
             if (!this.updateValue()) {
                 this.updateSegmentRange();
             } else {
                 this.value.index = this.segmentStart++;
+                this.hasNext = this.segmentEnd > this.segmentStart;
                 break;
             }
         }
@@ -73,10 +67,10 @@ class SegmentIterator implements Iterator<Segs.Segment> {
         const max = OrderedSet.getAt(this.set, Interval.max(this.setRange));
         this.segmentStart = this.getSegmentIndex(min);
         this.segmentEnd = this.getSegmentIndex(max) + 1;
-        this.done = this.segmentEnd <= this.segmentStart;
+        this.hasNext = this.segmentEnd > this.segmentStart;
     }
 
-    constructor(private segments: OrderedSet, private set: OrderedSet, private inputRange: Interval) {
+    constructor(private segments: OrderedSet, private set: OrderedSet, inputRange: Interval) {
         this.last = OrderedSet.max(segments);
         this.setRange = inputRange;
         this.updateSegmentRange();
diff --git a/src/mol-base/collections/iterator.ts b/src/mol-base/collections/iterator.ts
index 8024ecde8..9d4ff64d6 100644
--- a/src/mol-base/collections/iterator.ts
+++ b/src/mol-base/collections/iterator.ts
@@ -10,12 +10,10 @@
  * "Idiomatic" usage is to use the move function, because it does not make any allocations.
  *
  * const it = ...;
- * for (let v = it.move(); !it.done; v = it.move()) { ... }
+ * while (it.hasNext) { const v = it.move(); ... } 
  */
 interface Iterator<T> {
-    [Symbol.iterator](): Iterator<T>,
-    readonly done: boolean,
-    next(): { done: boolean, value: T },
+    readonly hasNext: boolean,
     move(): T
 }
 
@@ -25,24 +23,18 @@ class ArrayIteratorImpl<T> implements Iterator<T> {
     private length: number = 0;
     private lastValue: T;
 
-    [Symbol.iterator]() { return new ArrayIteratorImpl(this.xs); };
-    done: boolean;
-
-    next() {
-        const value = this.move();
-        return { value, done: this.done };
-    }
+    hasNext: boolean;
 
     move() {
-        const index = ++this.index;
-        if (index < this.length) this.lastValue = this.xs[index];
-        else this.done = true;
+        ++this.index;
+        this.lastValue = this.xs[this.index];
+        this.hasNext = this.index < this.length - 1;
         return this.lastValue;
     }
 
     constructor(xs: ArrayLike<T>) {
         this.length = xs.length;
-        this.done = xs.length === 0;
+        this.hasNext = xs.length > 0;
         this.xs = xs;
         this.index = -1;
         // try to avoid deoptimization with undefined values
@@ -53,32 +45,23 @@ class ArrayIteratorImpl<T> implements Iterator<T> {
 class RangeIteratorImpl implements Iterator<number> {
     private value: number;
 
-    [Symbol.iterator]() { return new RangeIteratorImpl(this.min, this.max); };
-    done: boolean;
-
-    next() {
-        const value = this.move();
-        return { value, done: this.done }
-    }
+    hasNext: boolean;
 
     move() {
         ++this.value;
-        this.done = this.value > this.max;
+        this.hasNext = this.value < this.max;
         return this.value;
     }
 
-    constructor(private min: number, private max: number) {
+    constructor(min: number, private max: number) {
         this.value = min - 1;
-        this.done = max < min;
+        this.hasNext = max >= min;
     }
 }
 
 class ValueIterator<T> implements Iterator<T> {
-    private yielded = false;
-    [Symbol.iterator]() { return new ValueIterator(this.value); };
-    done = false;
-    next() { const value = this.move(); return { value, done: this.done } }
-    move() { this.done = this.yielded; this.yielded = true; return this.value; }
+    hasNext = true;
+    move() { this.hasNext = false; return this.value; }
     constructor(private value: T) { }
 }
 
diff --git a/src/mol-data/_spec/atom-set.spec.ts b/src/mol-data/_spec/atom-set.spec.ts
index 4239e2af8..f5c1d8e78 100644
--- a/src/mol-data/_spec/atom-set.spec.ts
+++ b/src/mol-data/_spec/atom-set.spec.ts
@@ -14,7 +14,9 @@ describe('atom set', () => {
     function setToPairs(set: AtomSet): ArrayLike<IntTuple> {
         const ret: IntTuple[] = [];
         const it = AtomSet.atoms(set);
-        for (let v = it.move(); !it.done; v = it.move()) ret[ret.length] = v;
+        while (it.hasNext) {
+            ret[ret.length] = it.move();
+        }
         return ret;
     }
 
diff --git a/src/mol-data/atom-set/base.ts b/src/mol-data/atom-set/base.ts
index 5df7aa753..eeec45449 100644
--- a/src/mol-data/atom-set/base.ts
+++ b/src/mol-data/atom-set/base.ts
@@ -142,23 +142,18 @@ class ElementsIterator implements Iterator<Tuple> {
     private currentSize = 0;
     private currentSet: OrderedSet = OrderedSet.Empty;
 
-    [Symbol.iterator]() { return new ElementsIterator(this.elements); };
-    done: boolean;
-    next() { const value = this.move(); return { value, done: this.done } }
+    hasNext: boolean = false;
 
     move() {
-        if (this.done) return Tuple.Zero;
-
-        if (this.currentIndex >= this.currentSize) {
-            if (!this.advance()) return Tuple.Zero;
-        }
-
-        return Tuple.create(this.unit, OrderedSet.getAt(this.currentSet, this.currentIndex++));
+        if (!this.hasNext) return Tuple.Zero;
+        const ret = Tuple.create(this.unit, OrderedSet.getAt(this.currentSet, this.currentIndex++));
+        if (this.currentIndex >= this.currentSize) this.advance();
+        return ret;
     }
 
     private advance() {
         if (++this.setIndex >= this.keyCount) {
-            this.done = true;
+            this.hasNext = false;
             return false;
         }
         this.unit = OrderedSet.getAt(this.elements.keys, this.setIndex);
@@ -170,7 +165,7 @@ class ElementsIterator implements Iterator<Tuple> {
 
     constructor(private elements: AtomSetElements) {
         this.keyCount = OrderedSet.size(elements.keys);
-        this.done = this.keyCount === 0;
+        this.hasNext = this.keyCount > 0;
         this.advance();
     }
 }
diff --git a/src/perf-tests/iterators.ts b/src/perf-tests/iterators.ts
index 78cfac0a3..b2f10b3fd 100644
--- a/src/perf-tests/iterators.ts
+++ b/src/perf-tests/iterators.ts
@@ -1,4 +1,5 @@
 import * as B from 'benchmark'
+import It from '../mol-base/collections/iterator'
 
 function createData(n: number) {
     const data = [];//new Int32Array(n);
@@ -10,7 +11,7 @@ function createData(n: number) {
     return data;
 }
 
-namespace Iterators {
+export namespace Iterators {
     const data = createData(100000);
 
     export function forLoop() {
@@ -31,13 +32,13 @@ namespace Iterators {
 
     export function forEach() {
         const ctx = { sum: 0 };
-        data.forEach(function(this: typeof ctx, v: number) { this.sum += v }, ctx);
+        data.forEach(function (this: typeof ctx, v: number) { this.sum += v }, ctx);
         return ctx.sum;
     }
 
     export function forEachAllParams() {
         const ctx = { sum: 0 };
-        data.forEach(function(this: typeof ctx, v: number, _: any, __: any) { this.sum += v }, ctx);
+        data.forEach(function (this: typeof ctx, v: number, _: any, __: any) { this.sum += v }, ctx);
         return ctx.sum;
     }
 
@@ -200,28 +201,34 @@ namespace Iterators {
         }
         return sum;
     }
-}
 
+    export function run() {
+        const suite = new B.Suite();
+
+        suite
+            .add('for', () => Iterators.forLoop())
+            .add('forOf', () => Iterators.forOf())
+            .add('forEach', () => Iterators.forEach())
+            .add('forEach all params', () => Iterators.forEachAllParams())
+            .add('forEachClosure', () => Iterators.forEachClosure())
+            .add('forEachClosure all', () => Iterators.forEachClosureAll())
+            .add('forEachClosure all function', () => Iterators.forEachClosureAllFunction())
+            .add('mutableIterator ES6', () => Iterators.mutableES6Iterator())
+            //.add('mutableIteratorOf ES6', () => Iterators.mutableES6IteratorOf())
+            .add('immutableIterator ES6', () => Iterators.immutableES6Iterator())
+            //.add('immutableIteratorOf ES6', () => Iterators.immutableES6IteratorOf())
+            .add('mutableIterator', () => Iterators.mutableIterator())
+            .on('cycle', (e: any) => {
+                console.log(String(e.target));
+            })
+            // .on('complete', function (this: any) {
+            //     console.log('Fastest is ' + this.filter('fastest').map('name'));
+            // })
+            .run();
+    }
+}
 
-const suite = new B.Suite();
-
-suite
-    .add('for', () => Iterators.forLoop())
-    .add('forOf', () => Iterators.forOf())
-    .add('forEach', () => Iterators.forEach())
-    .add('forEach all params', () => Iterators.forEachAllParams())
-    .add('forEachClosure', () => Iterators.forEachClosure())
-    .add('forEachClosure all', () => Iterators.forEachClosureAll())
-    .add('forEachClosure all function', () => Iterators.forEachClosureAllFunction())
-    .add('mutableIterator ES6', () => Iterators.mutableES6Iterator())
-    //.add('mutableIteratorOf ES6', () => Iterators.mutableES6IteratorOf())
-    .add('immutableIterator ES6', () => Iterators.immutableES6Iterator())
-    //.add('immutableIteratorOf ES6', () => Iterators.immutableES6IteratorOf())
-    .add('mutableIterator', () => Iterators.mutableIterator())
-    .on('cycle', (e: any) => {
-        console.log(String(e.target));
-    })
-    // .on('complete', function (this: any) {
-    //     console.log('Fastest is ' + this.filter('fastest').map('name'));
-    // })
-    .run();
\ No newline at end of file
+const it = It.Array([1, 2, 3]);
+while (it.hasNext) {
+    console.log(it.move());
+}
\ No newline at end of file
diff --git a/src/perf-tests/sets.ts b/src/perf-tests/sets.ts
index e5fc1e389..178a9d9fe 100644
--- a/src/perf-tests/sets.ts
+++ b/src/perf-tests/sets.ts
@@ -29,7 +29,10 @@ export namespace Iteration {
     export function iterators() {
         let s = 0;
         const it = AtomSet.atoms(ms);
-        for (let v = it.move(); !it.done; v = it.move()) s += Tuple.snd(v);
+        while (it.hasNext) {
+            const v = it.move();
+            s += Tuple.snd(v);
+        }
         return s;
     }
 
@@ -274,7 +277,8 @@ export function testSegments() {
     const segs = Segmentation.create(SortedArray.ofSortedArray([0, 4, 10, 12, 13, 15, 25]), []);
     const it = Segmentation.segments(segs, data);
 
-    for (let s = it.move(); !it.done; s = it.move()) {
+    while (it.hasNext) {
+        const s = it.move();
         for (let j = s.start; j < s.end; j++) {
             console.log(`${s.index}: ${OrdSet.getAt(data, j)}`);
         }
-- 
GitLab