UNPKG

@thi.ng/dcons

Version:

Double-linked lists with comprehensive set of operations (incl. optional self-organizing behaviors)

126 lines (125 loc) 2.72 kB
import { AList } from "./alist.js"; class DRing extends AList { constructor(src) { super(); src && this.into(src); } get tail() { return this._head ? this._head.prev : void 0; } append(value) { if (!this._head) return this.prepend(value); const prev = this._head.prev; const cell = { value, prev, next: this._head }; prev.next = cell; this._head.prev = cell; this._length++; return cell; } copy() { return new DRing(this); } drop() { if (this._head) { const res = this._head.value; this.remove(this._head); return res; } } empty() { return new DRing(); } insertBefore(cell, value) { const newCell = { value, prev: cell.prev, next: cell }; cell.prev.next = newCell; cell.prev = newCell; if (cell === this._head) { this._head = newCell; } this._length++; return newCell; } insertAfter(cell, value) { const newCell = { value, prev: cell, next: cell.next }; cell.next.prev = newCell; cell.next = newCell; this._length++; return newCell; } map(fn) { return this._map(new DRing(), fn); } nth(n, notFound) { const cell = this.nthCell(n); return cell ? cell.value : notFound; } nthCell(n) { const len = this._length; return len ? this.nthCellUnsafe(n - Math.floor(n / len) * len) : void 0; } prepend(value) { let cell; if (this._head) { const tail = this.tail; cell = { value, prev: tail, next: this._head }; tail.next = cell; this._head.prev = cell; this._head = cell; } else { cell = { value }; cell.prev = cell; cell.next = cell; this._head = cell; } this._length++; return cell; } remove(v) { if (this._head === v) { if (this._length === 1) { this._head = void 0; this._length = 0; return; } this._head = v.next; } v.prev.next = v.next; v.next.prev = v.prev; this._length--; } rotateLeft() { this._head && (this._head = this._head.next); return this; } rotateRight() { this._head && (this._head = this._head.prev); return this; } /** * Implementation of * [ISeqable.seq](https://docs.thi.ng/umbrella/api/interfaces/ISeqable.html#seq.seq-1) */ seq() { const $seq = (cell) => ({ first() { return cell.value; }, next() { return $seq(cell.next); } }); return this._head ? $seq(this._head) : void 0; } traverse(fn, start = this._head, end = start) { return super.traverse(fn, start, end); } } const defDRing = (src) => new DRing(src); export { DRing, defDRing };