import { FilterConditionally } from "./types"; interface PriorityTagged { object: T, priority: number, // Higher takes priority addedIndex: number, // Lower takes priority } export class PriorityList { private source: Array> = []; private cachedSorted: Array | undefined; push(item: T, priority: number = 0) { this.source.push({ object: item, priority, addedIndex: this.source.length, }); this.cachedSorted = undefined; } pop(index: number = 0) { this.cachedSorted = undefined; return this.source.splice(index, 1)[0]; } values() { if (this.cachedSorted !== undefined) { return this.cachedSorted; } const sorted = this.source.sort((a, b) => { if (a.priority == a.priority) { return a.addedIndex - b.addedIndex; } return b.priority - a.priority; }).map((e) => e.object); this.cachedSorted = sorted; return this.cachedSorted; } find(predicate: (value: T, index: number, obj: T[]) => boolean) { return this.source.map((e) => e.object).find(predicate); } } type IndexableProperty = keyof FilterConditionally string) | string>; export class PriorityListIndexed extends PriorityList { private indexName: IndexableProperty; private indexMap: { [key: string]: T } = {}; constructor(indexName: IndexableProperty) { super(); this.indexName = indexName; } private getIndex(object: T): string { const index = object[this.indexName]; if (typeof index === 'function') { return index(); } return index as string; } push(item: T, priority?: number): void { const index = this.getIndex(item); this.indexMap[index] = item; super.push(item, priority); } pop(position?: number): PriorityTagged { const value = super.pop(position); const index = this.getIndex(value.object); delete this.indexMap[index]; return value; } get(index: string) { return this.indexMap[index]; } }