UNPKG

prex-es5

Version:

Async coordination primitives and extensions on top of ES6 Promises

266 lines (263 loc) 8.78 kB
/*! ***************************************************************************** Copyright (c) Microsoft Corporation. Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for details. ***************************************************************************** */ import { isMissing, isIterable, isInstance, isFunction } from "./utils"; export class LinkedListNode { constructor(value) { /*@internal*/ this._list = undefined; /*@internal*/ this._previous = undefined; /*@internal*/ this._next = undefined; this.value = value; } get list() { return this._list; } get previous() { if (this._previous && this._list && this !== this._list.first) { return this._previous; } return undefined; } get next() { if (this._next && this._list && this._next !== this._list.first) { return this._next; } return undefined; } } export class LinkedList { constructor(iterable) { this._head = undefined; this._size = 0; if (!isIterable(iterable, /*optional*/ true)) throw new TypeError("Object not iterable: iterable."); if (!isMissing(iterable)) { for (const value of iterable) { this.push(value); } } } get first() { return this._head; } get last() { if (this._head) { return this._head._previous; } return undefined; } get size() { return this._size; } *values() { for (const node of this.nodes()) { yield node.value; } } *nodes() { let node; let next = this.first; while (next !== undefined) { node = next; next = node.next; yield node; } } *drain() { for (const node of this.nodes()) { this.deleteNode(node); yield node.value; } } find(value) { for (let node = this.first; node; node = node.next) { if (sameValue(node.value, value)) { return node; } } return undefined; } findLast(value) { for (let node = this.last; node; node = node.previous) { if (sameValue(node.value, value)) { return node; } } return undefined; } has(value) { return this.find(value) !== undefined; } insertBefore(node, value) { if (!isInstance(node, LinkedListNode, /*optional*/ true)) throw new TypeError("LinkedListNode expected: node"); if (!isMissing(node) && node.list !== this) throw new Error("Wrong list."); return this._insertNode(node, new LinkedListNode(value), 0 /* before */); } insertNodeBefore(node, newNode) { if (!isInstance(node, LinkedListNode, /*optional*/ true)) throw new TypeError("LinkedListNode expected: node"); if (!isInstance(newNode, LinkedListNode)) throw new TypeError("LinkedListNode expected: newNode"); if (!isMissing(node) && node.list !== this) throw new Error("Wrong list."); if (!isMissing(newNode.list)) throw new Error("Node is already attached to a list."); this._insertNode(node, newNode, 0 /* before */); } insertAfter(node, value) { if (!isInstance(node, LinkedListNode, /*optional*/ true)) throw new TypeError("LinkedListNode expected: node"); if (!isMissing(node) && node.list !== this) throw new Error("Wrong list."); return this._insertNode(node, new LinkedListNode(value), 1 /* after */); } insertNodeAfter(node, newNode) { if (!isInstance(node, LinkedListNode, /*optional*/ true)) throw new TypeError("LinkedListNode expected: node"); if (!isInstance(newNode, LinkedListNode)) throw new TypeError("LinkedListNode expected: newNode"); if (!isMissing(node) && node.list !== this) throw new Error("Wrong list."); if (!isMissing(newNode.list)) throw new Error("Node is already attached to a list."); this._insertNode(node, newNode, 1 /* after */); } push(value) { return this._insertNode(undefined, new LinkedListNode(value), 1 /* after */); } pushNode(newNode) { if (!isInstance(newNode, LinkedListNode)) throw new TypeError("LinkedListNode expected: newNode"); if (!isMissing(newNode.list)) throw new Error("Node is already attached to a list."); this._insertNode(undefined, newNode, 1 /* after */); } pop() { let node = this.popNode(); return node ? node.value : undefined; } popNode() { let node = this.last; if (this.deleteNode(node)) { return node; } } shift() { let node = this.shiftNode(); return node ? node.value : undefined; } shiftNode() { let node = this.first; if (this.deleteNode(node)) { return node; } } unshift(value) { return this._insertNode(undefined, new LinkedListNode(value), 0 /* before */); } unshiftNode(newNode) { if (!isInstance(newNode, LinkedListNode)) throw new TypeError("LinkedListNode expected: newNode"); if (!isMissing(newNode.list)) throw new Error("Node is already attached to a list."); this._insertNode(undefined, newNode, 0 /* before */); } delete(value) { return this.deleteNode(this.find(value)); } deleteNode(node) { if (isMissing(node) || node.list !== this) { return false; } return this._deleteNode(node); } deleteAll(predicate, thisArg) { if (!isFunction(predicate)) throw new TypeError("Function expected: predicate"); let count = 0; let node = this.first; while (node) { let next = node.next; if (predicate.call(thisArg, node.value, node, this) && node.list === this) { this._deleteNode(node); ++count; } node = next; } return count; } clear() { while (this.size > 0) { this.deleteNode(this.last); } } forEach(callback, thisArg) { if (!isFunction(callback)) throw new TypeError("Function expected: predicate"); for (const node of this.nodes()) { callback.call(thisArg, node.value, node, this); } } _deleteNode(node) { if (node._next === node) { this._head = undefined; } else { node._next._previous = node._previous; node._previous._next = node._next; if (this._head === node) { this._head = node._next; } } node._list = undefined; node._next = undefined; node._previous = undefined; this._size--; return true; } _insertNode(adjacentNode, newNode, position) { newNode._list = this; if (this._head === undefined) { newNode._next = newNode; newNode._previous = newNode; this._head = newNode; } else { switch (position) { case 0 /* before */: if (adjacentNode === undefined) { adjacentNode = this._head; this._head = newNode; } else if (adjacentNode === this._head) { this._head = newNode; } newNode._next = adjacentNode; newNode._previous = adjacentNode._previous; adjacentNode._previous._next = newNode; adjacentNode._previous = newNode; break; case 1 /* after */: if (adjacentNode === undefined) { adjacentNode = this._head._previous; } newNode._previous = adjacentNode; newNode._next = adjacentNode._next; adjacentNode._next._previous = newNode; adjacentNode._next = newNode; break; } } this._size++; return newNode; } } LinkedList.prototype[Symbol.iterator] = LinkedList.prototype.values; function sameValue(x, y) { return (x === y) ? (x !== 0 || 1 / x === 1 / y) : (x !== x && y !== y); } //# sourceMappingURL=list.js.map