Home Manual Reference Source

src/DoublyLinkedList.js

import {
	Node,
	_concat,
	_erase,
	_extend,
	_remove,
	_insertAfter,
	_insertBefore,
} from '@data-structure-algebra/doubly-linked-list';

import Iterator from './Iterator.js';
import ReverseIterator from './ReverseIterator.js';

/**
 * Doubly linked list implementation
 * making use of dummy nodes for the
 * sake of simplicity.
 */
export default function DoublyLinkedList() {
	this.front = new Node(null, null, null);
	this.back = new Node(null, this.front, null);
	this.front.next = this.back;
	this.length = 0;
}

DoublyLinkedList.prototype.insertAfter = function (iterator, value) {
	const prev = iterator.current;

	const node = _insertAfter(prev, value);

	++this.length;
	return this.iterator(node);
};

DoublyLinkedList.prototype.insertBefore = function (iterator, value) {
	const next = iterator.current;

	const node = _insertBefore(next, value);

	++this.length;
	return this.iterator(node);
};

DoublyLinkedList.prototype.unshift = function (value) {
	return this.insertAfter(this.begin(), value);
};

DoublyLinkedList.prototype.push = function (value) {
	return this.insertBefore(this.end(), value);
};

DoublyLinkedList.prototype.erase = function (iterator) {
	const node = iterator.current;

	_remove(node);

	--this.length;
	return this.iterator(node.next);
};

DoublyLinkedList.prototype.rerase = function (iterator) {
	const node = iterator.current;

	_remove(node);

	--this.length;
	return this.iterator(node.prev);
};

DoublyLinkedList.prototype.eraserange = function (first, last) {
	const firstnode = first.current;
	const lastnode = last.current;

	_erase(firstnode, lastnode);

	let x = first.current;

	while (x !== lastnode) {
		--this.length;
		x = x.next;
	}

	return last.copy();
};

DoublyLinkedList.prototype.reraserange = function (first, last) {
	const firstnode = first.current;
	const lastnode = last.current;

	_concat(lastnode, firstnode.next);

	let x = first.current;

	while (x !== lastnode) {
		--this.length;
		x = x.prev;
	}

	return last.copy();
};

DoublyLinkedList.prototype.shift = function () {
	if (this.length === 0) return null;

	const node = this.front.next;
	_remove(node);

	--this.length;

	return node.value;
};

DoublyLinkedList.prototype.pop = function () {
	if (this.length === 0) return null;

	const node = this.back.prev;
	_remove(node);

	--this.length;

	return node.value;
};

DoublyLinkedList.prototype.clear = function () {
	_concat(this.front, this.back);
	this.length = 0;
	return this;
};

DoublyLinkedList.prototype.iterator = function (node) {
	return new Iterator(this.front, this.back, node);
};

DoublyLinkedList.prototype.riterator = function (node) {
	return new ReverseIterator(this.front, this.back, node);
};

DoublyLinkedList.prototype.begin = function () {
	return this.iterator(this.front);
};

DoublyLinkedList.prototype.end = function () {
	return this.iterator(this.back);
};

DoublyLinkedList.prototype.rbegin = function () {
	return this.riterator(this.back);
};

DoublyLinkedList.prototype.rend = function () {
	return this.riterator(this.front);
};

const from = (iterable) => {
	const list = new DoublyLinkedList();
	const last = _extend(list.front, iterable);
	_concat(last, list.back);
	return list;
};

DoublyLinkedList.prototype[Symbol.iterator] = DoublyLinkedList.prototype.begin;
DoublyLinkedList.Node = Node;
DoublyLinkedList.Iterator = Iterator;
DoublyLinkedList.ReverseIterator = ReverseIterator;
DoublyLinkedList.from = from;