export type Dictionary = { entries: Array<[K, V]>; indices: Map; isIterating: boolean; deleteQueue: Array; setQueue: Array<[K, V]>; }; export function createDictionary( iterable?: Iterable<[K, V]>, ): Dictionary { const entries = iterable ? [...iterable] : []; const indices = new Map(entries.map(([k], i) => [k, i])); return { entries, indices, isIterating: false, deleteQueue: [], setQueue: [], }; } export function deleteEntry(dict: Dictionary, key: K): void { const index = dict.indices.get(key); if (index === undefined) { return; } const last = dict.entries.length - 1; if (index !== last) { dict.entries[index] = dict.entries[last]; dict.indices.set(dict.entries[index][0], index); } dict.entries.pop(); dict.indices.delete(key); } export function deleteEntrySave(dict: Dictionary, key: K): void { if (dict.isIterating) { dict.deleteQueue.push(); } else { deleteEntry(dict, key); } } export function setEntry( dict: Dictionary, [key, value]: [K, V], ): void { const index = dict.indices.get(key); if (index === undefined) { dict.indices.set(key, dict.entries.length); dict.entries.push([key, value]); } else { dict.entries[index][1] = value; } } export function setEntrySave( dict: Dictionary, key: K, value: V, ): void { if (dict.isIterating) { dict.setQueue.push([key, value]); } else { setEntry(dict, [key, value]); } } export function getEntry(dict: Dictionary, key: K): V | undefined { const index = dict.indices.get(key); return index === undefined ? undefined : dict.entries[index][1]; } export function forEntry( dict: Dictionary, callback: (value: V, key: K, index: number) => void, ): void { dict.isIterating = true; for (let i = 0; i < dict.entries.length; i++) { callback(dict.entries[i][1], dict.entries[i][0], i); } dict.isIterating = false; while (dict.deleteQueue.length > 0) { deleteEntry(dict, dict.deleteQueue.pop()!); } while (dict.setQueue.length > 0) { setEntry(dict, dict.setQueue.pop()!); } }