iteragain
Version:
Javascript Iterable/Iterator/Generator-function utilities.
90 lines • 3.29 kB
JavaScript
/**
* Wraps `iterator` to allow for seeking backwards and forwards. An internal cache of length `maxLength` is kept and
* progressively added to when iterating forwards.
*/
var SeekableIterator = /** @class */ (function () {
function SeekableIterator(iterator, maxLength) {
if (maxLength === void 0) { maxLength = Infinity; }
this.iterator = iterator;
this.maxLength = maxLength;
this.cache = [];
/** Absolute index of the next value `next()` will return. */
this.i = 0;
/** Absolute index of `cache[0]`. Increments when the cache evicts its oldest entry. */
this.base = 0;
this.iteratorDone = false;
}
Object.defineProperty(SeekableIterator.prototype, "elements", {
get: function () {
return this.cache;
},
enumerable: false,
configurable: true
});
Object.defineProperty(SeekableIterator.prototype, "done", {
get: function () {
return this.iteratorDone ? !this.cache.length || this.i >= this.base + this.cache.length : false;
},
enumerable: false,
configurable: true
});
SeekableIterator.prototype[Symbol.iterator] = function () {
return this;
};
SeekableIterator.prototype.next = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (this.done)
return { done: true, value: undefined };
if (this.i < this.base + this.cache.length) {
return { done: false, value: this.cache[this.i++ - this.base] };
}
var next = (_a = this.iterator).next.apply(_a, args);
if (next.done) {
this.iteratorDone = true;
return next;
}
this.add(next.value);
return { done: false, value: this.cache[this.i++ - this.base] };
};
/**
* Seeks forward/backwards to the index `i`. `i` may be any positive or negative number. Negative numbers seek
* starting from the end of the internal cache (e.g. -1 is the last element).
*/
SeekableIterator.prototype.seek = function (i) {
if (i < 0)
i = this.base + this.cache.length + i;
if (i > this.i)
while (this.i < i && !this.done)
this.next();
else if (i < this.i)
this.i = Math.max(i, this.base);
};
/**
* Peek ahead of where the current iteration is. This doesn't consume any values of the iterator.
* @param ahead optional, the number of elements to peek ahead.
*/
SeekableIterator.prototype.peek = function (ahead) {
if (ahead === void 0) { ahead = 1; }
var result = [];
for (var i = 0; i < ahead; i++)
result.push(this.next().value);
this.i -= ahead;
return result;
};
/** Add `value` to the `cache`. */
SeekableIterator.prototype.add = function (value) {
this.cache.push(value);
if (this.cache.length > this.maxLength) {
this.cache.shift();
this.base++;
}
};
return SeekableIterator;
}());
export { SeekableIterator };
export default SeekableIterator;
//# sourceMappingURL=SeekableIterator.js.map