57 lines
1.5 KiB
TypeScript
57 lines
1.5 KiB
TypeScript
/// SPDX-License-Identifier: GPL-3.0-or-later
|
|
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
|
|
|
export interface List<T, C> extends Iterable<T> {
|
|
item: T | null;
|
|
next: List<T, C> | null;
|
|
context: C;
|
|
|
|
toArray(): Array<T>;
|
|
}
|
|
|
|
export function atEnd<T, C>(xs: List<T, C>): xs is (List<T, C> & { item: null, next: null }) {
|
|
return xs.item === null;
|
|
}
|
|
|
|
export function notAtEnd<T, C>(xs: List<T, C>): xs is (List<T, C> & { item: T, next: List<T, C> }) {
|
|
return xs.item !== null;
|
|
}
|
|
|
|
export class ArrayList<T, C> implements List<T, C> {
|
|
readonly items: Array<T>;
|
|
readonly index: number = 0;
|
|
|
|
constructor(items: Array<T>, public context: C, index = 0) {
|
|
this.items = items;
|
|
this.index = index;
|
|
}
|
|
|
|
get item(): T | null {
|
|
return this.items[this.index] ?? null;
|
|
}
|
|
|
|
get next(): List<T, C> | null {
|
|
if (this.index >= this.items.length) return null;
|
|
return new ArrayList(this.items, this.context, this.index + 1);
|
|
}
|
|
|
|
toArray(): Array<T> {
|
|
return this.items.slice(this.index);
|
|
}
|
|
|
|
[Symbol.iterator](): Iterator<T> {
|
|
let i: List<T, C> = this;
|
|
return {
|
|
next(): IteratorResult<T> {
|
|
if (notAtEnd(i)) {
|
|
const value = i.item;
|
|
i = i.next;
|
|
return { done: false, value };
|
|
} else {
|
|
return { done: true, value: null };
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|