function assert(b) { if (!b) throw new Error("Bad"); } class Numbers { constructor(limit = 100) { this.limit = limit; this.item = 0; } next() { if (this.item >= this.limit) throw "done"; return this.item++; } } function transpose(I, f) { return class Transpose { constructor(...args) { this.iterator = new I(...args); } next() { return f(this.iterator.next()); } }; } let EvenNumbers = transpose(Numbers, (x)=>x*2); function verifyEven(prev, cur) { assert(cur.value % 2 === 0); assert(!prev.value || prev.value+2 === cur.value); } let StringNumbers = transpose(Numbers, (x)=>`${x}`); function verifyString(_, cur) { assert(cur.value === `${cur.value}`); } let iterators = [ [Numbers, function() {}], [Numbers, function() {}], [StringNumbers, verifyString], [EvenNumbers, verifyEven], [EvenNumbers, verifyEven], ]; function foo(i) {} noInline(foo); function runIterators() { for (let [iterator, verify] of iterators) { let i = new iterator; let prev = {}; while (true) { let cur = {}; try { cur.value = i.next(); verify(prev, cur); } catch(e) { if (e !== "done") throw new Error("Bad: " + e); break; } prev = cur; } } } { let start = Date.now(); for (let i = 0; i < 5000; ++i) runIterators(); if (false) print(Date.now() - start); }