doubly
Version:
Doubly linked list in TypeScript
313 lines • 9.44 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const Node_1 = __importStar(require("./Node"));
const baseerr_1 = __importDefault(require("baseerr"));
var Node_2 = require("./Node");
Object.defineProperty(exports, "DoublyNode", { enumerable: true, get: function () { return Node_2.default; } });
class DoublyError extends baseerr_1.default {
}
class Doubly {
constructor(opts) {
this.head = null;
this.tail = null;
this.size = 0;
if ((opts === null || opts === void 0 ? void 0 : opts.head) == null)
return;
this.head = opts.head;
let cursor = opts.head;
let tail = null;
while (cursor) {
tail = cursor;
cursor = cursor.next;
}
this.tail = tail;
}
[Symbol.iterator]() {
return Node_1.nodeTraverseNextValues(this.head);
}
nodes() {
return Node_1.nodeTraverseNextNodes(this.head);
}
at(index) {
var _a;
DoublyError.assert(index >= 0, '"at" negative index not supported', {
index,
});
return (_a = this.node(index)) === null || _a === void 0 ? void 0 : _a.value;
}
node(index) {
DoublyError.assert(index >= 0, '"node" negative index not supported', {
index,
});
let i = 0;
for (let node of this.nodes()) {
if (i === index)
return node;
i++;
}
}
concat(list) {
const result = new Doubly();
for (let value of this) {
result.push(value);
}
for (let value of list) {
result.push(value);
}
return result;
}
delete(index) {
DoublyError.assert(index >= 0, '"delete" negative index not supported', {
index,
});
const node = this.node(index);
if (node == null)
return false;
this.deleteNode(node);
return true;
}
deleteNode(node) {
if (node === this.head)
this.shift();
else if (node === this.tail)
this.pop();
else if (node.unlink())
this.size--;
}
every(cb) {
let i = 0;
for (let value of this) {
if (!cb(value, i, this))
return false;
i++;
}
return true;
}
forEach(cb) {
let i = 0;
for (let value of this) {
cb(value, i, this);
i++;
}
}
forEachRight(cb) {
let i = 0;
for (let value of Node_1.nodeTraversePrevValues(this.tail)) {
cb(value, i, this);
i++;
}
}
filter(cb) {
const result = new Doubly();
let i = 0;
for (let value of this) {
const keep = cb(value, i, this);
if (keep)
result.push(value);
i++;
}
return result;
}
find(cb) {
let i = 0;
for (let value of this) {
const found = cb(value, i, this);
if (found)
return value;
i++;
}
}
findIndex(cb) {
let i = 0;
for (let value of this) {
const found = cb(value, i, this);
if (found)
return i;
i++;
}
return -1;
}
includes(compare) {
if (this.head != null && compare === this.head.value)
return true;
if (this.tail != null && compare === this.tail.value)
return true;
return this.some((value, i, list) => compare === value);
}
indexOf(compare) {
return this.findIndex((value, i, list) => compare === value);
}
map(cb) {
const mapped = new Doubly();
let i = 0;
for (let value of this) {
mapped.push(cb(value, i, this));
i++;
}
return mapped;
}
pop() {
const node = this.popNode();
return node === null || node === void 0 ? void 0 : node.value;
}
popNode() {
var _a, _b, _c;
const prevTail = this.tail;
if (prevTail == null)
return;
this.size--;
const nextTail = (_b = (_a = this.tail) === null || _a === void 0 ? void 0 : _a.prev) !== null && _b !== void 0 ? _b : null;
this.tail = nextTail;
(_c = this.tail) === null || _c === void 0 ? void 0 : _c.linkNext(null);
if (this.tail == null)
this.head = null;
prevTail.unlink();
return prevTail;
}
push(val) {
const node = new Node_1.default(val);
this.pushNode(node);
}
pushNode(node) {
this.size++;
if (this.tail == null) {
// this.head == null
this.head = node;
this.tail = node;
return;
}
this.tail = this.tail.linkNext(node);
this.tail.next = null;
}
reduce(cb, initialValue) {
let node = this.head;
let i = 0;
let memo;
if (arguments.length === 1) {
DoublyError.assert(node != null, 'cannot "reduce" empty list with no initial value');
memo = node.value;
node = node.next;
i = 1;
}
else {
memo = initialValue;
}
while (node) {
memo = cb(memo, node.value, i, this);
node = node.next;
i++;
}
return memo;
}
shift() {
const node = this.shiftNode();
return node === null || node === void 0 ? void 0 : node.value;
}
shiftNode() {
var _a, _b;
const prevHead = this.head;
if (prevHead == null)
return;
this.size--;
const nextHead = (_b = (_a = this.head) === null || _a === void 0 ? void 0 : _a.next) !== null && _b !== void 0 ? _b : null;
this.head = nextHead;
if (this.head == null)
this.tail = null;
prevHead.unlink();
return prevHead;
}
unshift(val) {
const node = new Node_1.default(val);
this.unshiftNode(node);
}
unshiftNode(node) {
this.size++;
if (this.head == null) {
// this.head == null
this.head = node;
this.tail = node;
return;
}
node.linkNext(this.head);
this.head = node;
this.head.prev = null;
}
some(cb) {
let node = this.head;
let i = 0;
while (node) {
const result = cb(node.value, i, this);
if (Boolean(result))
return true;
node = node.next;
i++;
}
return false;
}
splice(index, removeCount, ...items) {
var _a, _b;
const removed = new Doubly();
const start = this.node(index);
const prev = (_a = start === null || start === void 0 ? void 0 : start.prev) !== null && _a !== void 0 ? _a : null;
if (start == null) {
items.forEach((item) => this.push(item));
return removed;
}
// remove items
let count = 0;
let restHead = (_b = prev === null || prev === void 0 ? void 0 : prev.next) !== null && _b !== void 0 ? _b : null;
for (let next of Node_1.nodeTraverseNextNodes(start)) {
if (count >= removeCount)
break;
count++;
restHead = next === null || next === void 0 ? void 0 : next.next;
this.deleteNode(next);
removed.pushNode(next);
}
// insert items
if (index === 0) {
// insert items at the head
items.reverse().forEach((item) => this.unshift(item));
}
else if (start === this.tail) {
// insert items at the tail
items.forEach((item) => this.push(item));
}
else {
// insert items in the middle
// this.head ... prev ... inserted ... this.tail
const inserted = new Doubly();
items.forEach((item) => inserted.push(item));
if (inserted.head)
inserted.head.linkPrev(prev);
if (inserted.tail)
inserted.tail.linkNext(restHead);
this.size += inserted.size;
}
return removed;
}
}
exports.default = Doubly;
//# sourceMappingURL=index.js.map