import { asAsyncEqualityComparer } from "../equality-comparer/async.js"; import { asEqualityComparer } from "../equality-comparer/sync.js"; import { AsyncEqualityComparer, EqualityComparer, EqualityComparisonOrComparer, MaybeAsyncEqualityComparisonOrComparer } from "../equality-comparer/types.js"; import { MaybeAsyncIterable } from "../types.js"; import { AsyncEqualityMap, EqualityMap, EqualityMapEntry } from "./types.js"; export class NativeEqualityMap implements EqualityMap { readonly #map = new Map(); get size() { return this.#map.size; } get(key: K) { return this.#map.get(key); } set(key: K, value: V) { const existing = this.get(key); this.#map.set(key, value); return existing; } setAll(entries: Iterable>) { for (const [key, value] of entries) { this.set(key, value); } } contains(key: K) { return this.#map.has(key); } remove(key: K) { const existing = this.get(key); this.#map.delete(key); return existing; } clear() { this.#map.clear(); } keys() { return this.#map.keys(); } values() { return this.#map.values(); } entries() { return this.#map.entries(); } [Symbol.iterator]() { return this.#map[Symbol.iterator](); } } export class CustomEqualityMap implements EqualityMap { readonly #list: EqualityMapEntry[] = []; readonly #keyComparer: EqualityComparer; constructor(keyComparer: EqualityComparisonOrComparer) { this.#keyComparer = asEqualityComparer(keyComparer); } get size() { return this.#list.length; } get(key: K) { for (const entry of this.#list) { if (this.#keyComparer.equals(key, entry[0])) { return entry[1]; } } return undefined; } set(key: K, value: V) { for (const entry of this.#list) { if (this.#keyComparer.equals(key, entry[0])) { const previous = entry[1]; entry[1] = value; return previous; } } this.#list.push([key, value]); return undefined; } setAll(entries: Iterable>) { for (const [key, value] of entries) { this.set(key, value); } } contains(key: K) { for (const entry of this.#list) { if (this.#keyComparer.equals(key, entry[0])) { return true; } } return false; } remove(key: K) { for (let i = 0; i < this.#list.length; i++) { if (this.#keyComparer.equals(key, this.#list[i][0])) { const removed = this.#list.splice(i, 1); return removed[0][1]; } } return undefined; } clear() { this.#list.length = 0; } *keys() { for (const entry of this.#list) { yield entry[0]; } } *values() { for (const entry of this.#list) { yield entry[1]; } } entries() { return this[Symbol.iterator](); } *[Symbol.iterator]() { for (const entry of this.#list) { yield entry.slice() as EqualityMapEntry; // no entry mutation allowed! } } } export class NativeAsyncEqualityMap implements AsyncEqualityMap { readonly #map = new Map(); get size() { return this.#map.size; } async get(key: K) { return this.#map.get(key); } async set(key: K, value: V) { const existing = await this.get(key); this.#map.set(key, value); return existing; } async setAll(entries: MaybeAsyncIterable>) { for await (const [key, value] of entries) { await this.set(key, value); } } async contains(key: K) { return this.#map.has(key); } async remove(key: K) { const existing = await this.get(key); this.#map.delete(key); return existing; } clear() { this.#map.clear(); } keys() { return this.#map.keys(); } values() { return this.#map.values(); } entries() { return this.#map.entries(); } [Symbol.iterator]() { return this.#map[Symbol.iterator](); } } export class CustomAsyncEqualityMap implements AsyncEqualityMap { readonly #list: EqualityMapEntry[] = []; readonly #keyComparer: AsyncEqualityComparer; constructor(keyComparer: MaybeAsyncEqualityComparisonOrComparer) { this.#keyComparer = asAsyncEqualityComparer(keyComparer); } get size() { return this.#list.length; } async get(key: K) { for (const entry of this.#list) { if (await this.#keyComparer.equals(key, entry[0])) { return entry[1]; } } return undefined; } async set(key: K, value: V) { for (const entry of this.#list) { if (await this.#keyComparer.equals(key, entry[0])) { const previous = entry[1]; entry[1] = value; return previous; } } this.#list.push([key, value]); return undefined; } async setAll(entries: MaybeAsyncIterable>) { for await (const [key, value] of entries) { await this.set(key, value); } } async contains(key: K) { for (const entry of this.#list) { if (await this.#keyComparer.equals(key, entry[0])) { return true; } } return false; } async remove(key: K) { for (let i = 0; i < this.#list.length; i++) { if (await this.#keyComparer.equals(key, this.#list[i][0])) { const removed = this.#list.splice(i, 1); return removed[0][1]; } } return undefined; } clear() { this.#list.length = 0; } *keys() { for (const entry of this.#list) { yield entry[0]; } } *values() { for (const entry of this.#list) { yield entry[1]; } } entries() { return this[Symbol.iterator](); } *[Symbol.iterator]() { for (const entry of this.#list) { yield entry.slice() as EqualityMapEntry; // no entry mutation allowed! } } }