Skip to content

Instantly share code, notes, and snippets.

@BenoitZugmeyer
Created February 23, 2016 18:59
Show Gist options
  • Save BenoitZugmeyer/c3bbd2239b817df88240 to your computer and use it in GitHub Desktop.
Save BenoitZugmeyer/c3bbd2239b817df88240 to your computer and use it in GitHub Desktop.
Iterator utils
var It = (function () {
var STOP = {};
function Iterator(next) {
this._next = next;
this._item = {};
this._index = -1;
}
Iterator.prototype = {
constructor: Iterator,
[Symbol.iterator]() { return this },
next() {
if (this._item.done) return this._item;
this._index += 1;
var result = this._next(this._index);
this._item.done = result === STOP;
if (!this._item.done) this._item.value = result;
return this._item;
}
};
function create(next) {
return new Iterator(next);
}
var empty = create(function () { return STOP });
function single(value) {
return create(function (i) { return i === 0 ? value : STOP });
}
function getIterator(value) {
return value && value[Symbol.iterator]();
}
function isIterable(value) {
return value && typeof value[Symbol.iterator] === "function";
}
function from(iterable) {
if (iterable === undefined) return empty;
if (iterable instanceof Iterator) return iterable;
if (isIterable(iterable)) return getIterator(iterable);
if (typeof iterable.length === "number") {
return create(function (index) {
return index < iterable.length ? iterable[index] : STOP;
});
}
return single(iterable);
}
function splat(iterator) {
iterator = from(iterator);
var currentItemIterator;
return create(function () {
if (!currentItemIterator) currentItemIterator = iterator.next();
while (!currentItemIterator.done) {
var item = currentItemIterator.value.next();
if (!item.done) return item.value;
currentItemIterator = iterator.next();
}
return STOP;
});
}
function chain() {
return splat(from(arguments));
}
function map(iterator, fn) {
iterator = from(iterator);
return create(function (index) {
var item = iterator.next();
return item.done ? STOP : fn(item.value, index);
});
}
function filter(iterator, fn) {
iterator = from(iterator);
return create(function (index) {
while (true) {
var item = iterator.next();
if (item.done) return STOP;
if (fn(item.value, index)) return item.value;
}
});
}
function takeWhile(iterator, fn) {
iterator = from(iterator);
return create(function (index) {
var item = iterator.next();
return item.done || !fn(item.value, index) ? STOP : item.value;
});
}
function skipWhile(iterator, fn) {
iterator = from(iterator);
var started = false;
return create(function () {
while (true) {
var item = iterator.next();
if (item.done) return STOP;
if (!started) started = !fn(item.value);
if (started) return item.value;
}
});
}
function skip(iterator, n) {
return skipWhile(iterator, function () { n--; return n >= 0 });
}
function fold(iterator, fn, init) {
var previousSet = init !== undefined;
var previous = init;
for (var value of from(iterator)) {
if (!previousSet) {
previous = value;
previousSet = true;
}
else previous = fn(previous, value);
}
if (!previousSet) throw new Error("Fold on an empty iterator without initial value");
return previous;
}
var exports = {
create: create,
empty: empty,
single: single,
isIterable: isIterable,
from: from,
splat: splat,
chain: chain,
map: map,
filter: filter,
takeWhile: takeWhile,
skipWhile: skipWhile,
skip: skip,
fold: fold
}
;["splat", "skip", "skipWhile", "takeWhile", "chain", "fold", "map", "filter"].forEach(function (name) {
var fn = exports[name];
Iterator.prototype[name] = function (a, b, c) {
switch (arguments.length) {
case 0: return fn(this)
case 1: return fn(this, a)
case 2: return fn(this, a, b)
case 3: return fn(this, a, b, c)
}
var args = Array.from(arguments);
args.unshift(this);
return fn.apply(null, args);
};
})
return exports;
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment