paco_sako/js/iterator.js

200 lines
4.2 KiB
JavaScript

'use strict';
function identity(x) {
return x;
}
export class Iterator {
constructor(from) {
let next;
if (Symbol.iterator in from.__proto__) {
const iter = from.__proto__[Symbol.iterator].call(from);
next = iter.next.bind(iter);
} else if (typeof from === 'function') {
next = from;
} else {
throw new TypeError('Iterator class needs iterable input');
}
Object.defineProperty(this, 'next', {
value: next,
writable: false,
enumerable: true,
configurable: false,
});
}
[Symbol.iterator]() {
return this;
}
map(f) {
const next = this.next;
return new Iterator(function() {
const y = next();
if (y.done) {
return y;
} else {
return { value: f(y.value), done: false };
}
});
}
filter(f) {
const next = this.next;
return new Iterator(function() {
let y;
while (!(y = next()).done && !f(y.value)) {
continue;
}
return y;
});
}
take(limit) {
let remaining = Number(limit) & -1;
const next = this.next;
return new Iterator(function() {
if (remaining > 0) {
remaining -= 1;
return next();
} else {
return { value: undefined, done: true };
}
});
}
drop(limit) {
let remaining = Number(limit) & -1;
const next = this.next;
return new Iterator(function() {
while (remaining > 0 && !next().done) {
remaining -= 1;
}
return next();
});
}
asIndexedPairs() {
const next = this.next;
let index = 0;
return new Iterator(function() {
const y = next();
if (y.done) {
return y;
} else {
return { value: [index++, y.value], done: false };
}
});
}
flatMap(f) {
const next = this.next;
let innerNext;
return new Iterator(function() {
for (;;) {
if (innerNext) {
let y = innerNext();
if (!y.done) {
return y;
}
}
let z = next();
if (z.done) {
innerNext = undefined;
return z;
}
const iter = y.value.__proto__[Symbol.iterator].call(y.value);
innerNext = iter.next.bind(iter);
}
});
}
reduce(f, state) {
if (typeof state === 'undefined') {
const first = this.next();
if (first.done) {
throw new TypeError('reduce: empty iterator');
}
state = first.value;
}
let y;
while (!(y = this.next()).done) {
state = f(state, y.value);
}
return state;
}
toArray() {
return [...this];
}
forEach(f) {
let y;
while (!(y = this.next()).done) {
f(y.value);
}
/* extension: return final value from underlying iterator */
return y.value;
}
some(f) {
/* extension: if f is undefined, assume identity function */
if (typeof f === 'undefined') {
f = identity;
}
let y;
while (!(y = this.next()).done) {
if (f(y.value)) {
return true;
}
}
return false;
}
every(f) {
/* extension: if f is undefined, assume identity function */
if (typeof f === 'undefined') {
f = identity;
}
let y;
while (!(y = this.next()).done) {
if (!f(y.value)) {
return false;
}
}
return true;
}
find(f) {
/* extension: if f is undefined, return the first 'truthy' value */
if (typeof f === undefined) {
f = identity;
}
let y;
while (!(y = this.next()).done) {
if (f(y.value)) {
return y.value;
}
}
}
/* extension */
includes(x) {
return this.some(function matches(y) { return y == x; });
}
/* extension */
strictlyIncludes(x) {
return this.some(function matches(y) { return y === x; });
}
};
export default Iterator;