@wroud/navigation
Version:
A flexible, pattern-matching navigation system for JavaScript applications with built-in routing, browser integration, and navigation state management
213 lines • 5.28 kB
JavaScript
export class LinkedList {
get size() {
return this.length;
}
get first() {
return this.head?.value;
}
get last() {
return this.tail?.value;
}
head = null;
tail = null;
length = 0;
constructor(elements = []) {
for (const element of elements) {
this.push(element);
}
}
setHead(head) {
this.head = head;
if (this.head) {
this.head.back = null;
}
this.length = 0;
this.tail = head;
while (this.tail?.next) {
this.tail.next.back = this.tail;
this.tail = this.tail.next;
this.length += 1;
}
}
get(index) {
if (index < 0 || index >= this.length) {
return null;
}
let current = this.head;
let i = 0;
while (current && i < index) {
current = current.next;
i += 1;
}
return current?.value;
}
set(index, value) {
this.assertIndexInBounds(index);
let current = this.head;
let i = 0;
while (current && i < index) {
current = current.next;
i += 1;
}
if (current) {
current.value = value;
}
}
add(index, value) {
this.assertIndexInBounds(index);
if (index === 0) {
this.head = { value, next: this.head, back: null };
if (this.head.next) {
this.head.next.back = this.head;
}
this.length += 1;
return;
}
if (index === this.length) {
this.push(value);
return;
}
let current = this.head;
let i = 0;
while (current && i < index - 1) {
current = current.next;
i += 1;
}
if (!current) {
return;
}
const node = {
value,
next: current.next,
back: current,
};
current.next = node;
if (node.next) {
node.next.back = node;
}
this.length += 1;
}
push(value) {
const node = { value, next: null, back: this.tail };
if (!this.head) {
this.head = node;
this.tail = node;
}
else {
this.tail.next = node;
this.tail = node;
}
this.length += 1;
}
remove(value) {
let current = this.head;
let previous = null;
while (current) {
if (current.value === value) {
if (previous) {
previous.next = current.next;
}
else {
this.head = current.next;
}
if (current.next) {
current.next.back = previous;
}
if (current === this.tail) {
this.tail = previous;
}
this.length -= 1;
return;
}
previous = current;
current = current.next;
}
}
removeFrom(index) {
this.assertIndexInBounds(index);
if (index === 0) {
this.head = null;
this.tail = null;
this.length = 0;
return;
}
let current = this.head;
let i = 0;
while (current && i < index - 1) {
current = current.next;
i += 1;
}
if (current) {
current.next = null;
this.tail = current;
this.length = index;
}
}
removeFirst() {
if (!this.head) {
return;
}
const value = this.head.value;
this.head = this.head.next;
if (this.head) {
this.head.back = null;
}
else {
this.tail = null;
}
this.length -= 1;
return value;
}
removeLast() {
if (!this.tail) {
return;
}
const value = this.tail.value;
this.tail = this.tail.back;
if (this.tail) {
this.tail.next = null;
}
else {
this.head = null;
}
this.length -= 1;
return value;
}
forEach(callback) {
let current = this.head;
while (current) {
callback(current.value);
current = current.next;
}
}
/**
* Serialize the linked list into a plain object.
*/
toJSON() {
const head = this.head;
if (!head) {
return null;
}
let current = { ...head, back: null };
while (current.next) {
current.next = { ...current.next, back: null };
current = current.next;
}
return head;
}
toArray() {
const array = [];
let current = this.head;
while (current) {
array.push(current.value);
current = current.next;
}
return array;
}
assertIndexInBounds(index) {
if (index < 0 || index >= this.length) {
throw new Error("Index out of bounds");
}
}
}
//# sourceMappingURL=LinkedList.js.map