UNPKG

@ndn/util

Version:
178 lines (177 loc) 4.36 kB
const emptySet = new Set(); /** * Map that transforms keys. * @typeParam K - Input key type. * @typeParam V - Value type. * @typeParam I - Indexable key type. * @typeParam L - Lookup key type. */ export class KeyMap { keyOf; /** * Constructor. * @param keyOf - Function to transform input key to indexable key. */ constructor(keyOf) { this.keyOf = keyOf; } m = new Map(); get size() { return this.m.size; } has(key) { return this.m.has(this.keyOf(key)); } get(key) { return this.m.get(this.keyOf(key))?.[1]; } set(key, value) { this.m.set(this.keyOf(key), [key, value]); return this; } delete(key) { return this.m.delete(this.keyOf(key)); } [Symbol.iterator]() { return this.m.values(); } } /** * MultiMap that transforms keys. * @typeParam K - Input key type. * @typeParam V - Value type. * @typeParam I - Indexable key type. * @typeParam L - Lookup key type. */ export class KeyMultiMap { /** * Constructor. * @param keyOf - Function to transform input key to indexable key. */ constructor(keyOf) { this.m = new KeyMap(keyOf); } m; size_ = 0; /** Number of distinct keys. */ get dimension() { return this.m.size; } /** Number of values. */ get size() { return this.size_; } /** Count values associated with a key. */ count(key) { return this.m.get(key)?.size ?? 0; } /** List values associated with a key. */ list(key) { return this.m.get(key) ?? emptySet; } /** * Add a key-value pair. * Values are stored in a Set, so duplicates are skipped. * @returns count(key) after the operation. */ add(key, value) { let c = this.m.get(key); if (!c) { c = new Set(); this.m.set(key, c); } const n = c.size; c.add(value); this.size_ += c.size - n; return c.size; } /** * Remove a key-value pair. * No-op if key-value does not exist. * @returns `count(key)` after the operation. */ remove(key, value) { const c = this.m.get(key); if (!c) { return 0; } const n = c.size; c.delete(value); this.size_ += c.size - n; if (c.size === 0) { this.m.delete(key); } return c.size; } /** Iterate over key and associated values. */ associations() { return this.m[Symbol.iterator](); } /** Iterate over key-value pairs. */ *[Symbol.iterator]() { for (const [key, values] of this.associations()) { for (const value of values) { yield [key, value]; } } } } /** Container that associates a key with multiple distinct values. */ export class MultiMap extends KeyMultiMap { constructor() { super((k) => k); } } /** * MultiSet that transforms keys. * @typeParam K - Input key type. * @typeParam I - Indexable key type. * @typeParam L - Lookup key type. */ export class KeyMultiSet { /** * Constructor. * @param keyOf - Function to transform input key to indexable key. */ constructor(keyOf) { this.m = new KeyMap(keyOf); } m; size_ = 0; /** Number of distinct keys. */ get dimension() { return this.m.size; } /** Number of values. */ get size() { return this.size_; } /** Count occurrences of a key. */ count(key) { return this.m.get(key) ?? 0; } /** * Add a key. * @returns Number of occurrences after the operation. */ add(key) { const n = this.count(key) + 1; this.m.set(key, n); ++this.size_; return n; } /** * Remove a key. * No-op if key does not exist. * @returns Number of occurrences after the operation. */ remove(key) { let n = this.count(key); if (n === 0) { return n; } --this.size_; --n; if (n === 0) { this.m.delete(key); } else { this.m.set(key, n); } return n; } /** Iterate over key and number of occurrences. */ multiplicities() { return this.m[Symbol.iterator](); } }