UNPKG

@thi.ng/bidir-index

Version:

Bi-directional index mapping arbitrary keys to numeric IDs & vice versa

228 lines (227 loc) 5.14 kB
class BidirIndex { fwd; rev; nextID; constructor(keys, opts = {}) { this.nextID = opts.start || 0; this.fwd = opts.map || /* @__PURE__ */ new Map(); this.rev = /* @__PURE__ */ new Map(); keys && this.addAll(keys); } get size() { return this.fwd.size; } /** * Yields same result as {@link BidirIndex.entries}. */ [Symbol.iterator]() { return this.entries(); } /** * Returns iterator of `[key,id]` pairs. */ entries() { return this.fwd.entries(); } /** * Returns iterator of all indexed keys. */ keys() { return this.fwd.keys(); } /** * Returns iterator of all indexed IDs. */ values() { return this.fwd.values(); } /** * Returns true if given `key` is known/indexed. * * @param key */ has(key) { return this.fwd.has(key); } /** * Returns true if given `id` has a corresponding known/indexed key. * * @param id */ hasID(id) { return this.rev.has(id); } /** * Reverse lookup of {@link BidirIndex.getID}. Returns the matching ID for * given `key` or undefined if the key is not known. * * @param key */ get(key) { return this.fwd.get(key); } /** * Reverse lookup of {@link BidirIndex.get}. Returns the matching key for * given `id` or undefined if the ID is not known. * * @param id */ getID(id) { return this.rev.get(id); } /** * Indexes given `key` and assigns & returns a new ID. If `key` is already * known/indexed, returns its existing ID. * * @param key */ add(key) { let id = this.fwd.get(key); if (id === void 0) { this.fwd.set(key, this.nextID); this.rev.set(this.nextID, key); id = this.nextID++; } return id; } /** * Batch version of {@link BidirIndex.add}. Indexes all given keys and * returns array of their corresponding IDs. * * @param keys */ addAll(keys) { const res = []; for (let k of keys) { res.push(this.add(k)); } return res; } /** * Similar to {@link BidirIndex.addAll}, but returns indexed key IDs as ES6 * Set, thereby removing any duplicates present in `keys`. * * @param keys */ addAllUnique(keys) { const res = /* @__PURE__ */ new Set(); for (let k of keys) { res.add(this.add(k)); } return res; } /** * Removes bi-directional mapping for given `key` from the index. Returns * true if successful. * * @param key */ delete(key) { return __delete(this.fwd, this.rev, key); } /** * Removes bi-directional mapping for given `id` from the index. Returns * true if successful. * * @param id */ deleteID(id) { return __delete(this.rev, this.fwd, id); } /** * Batch version of {@link BidirIndex.delete}. * * @param keys */ deleteAll(keys) { for (let k of keys) this.delete(k); } /** * Batch version of {@link BidirIndex.deleteID}. * * @param ids */ deleteAllIDs(ids) { for (let id of ids) this.deleteID(id); } /** * Returns array of IDs for all given keys. If `fail` is true (default: * false), throws error if any of the given keys is unknown/unindexed (use * {@link BidirIndex.add} or {@link BidirIndex.addAll} first). * * @param keys * @param fail */ getAll(keys, fail = false) { return __iterate(this.fwd, keys, fail); } /** * Similar to {@link BidirIndex.getAll}, but returns result as ES6 Set, * thereby removing any duplicates in `keys`. * * @param keys * @param fail */ getAllUnique(keys, fail = false) { return new Set(__iterate(this.fwd, keys, fail)); } /** * Returns array of matching keys for all given IDs. If `fail` is true * (default: false), throws error if any of the given IDs is * unknown/unindexed (use {@link BidirIndex.add} or * {@link BidirIndex.addAll} first). * * @param ids * @param fail */ getAllIDs(ids, fail = false) { return __iterate(this.rev, ids, fail); } /** * Returns a compact JSON serializable version of the index. Use * {@link bidirIndexFromJSON} to instantiate an index from such a JSON * serialization. */ toJSON() { return { pairs: [...this.entries()], nextID: this.nextID }; } } const __delete = (fwd, rev, key) => { const val = fwd.get(key); if (val !== void 0) { fwd.delete(key); rev.delete(val); return true; } return false; }; const __iterate = (index, keys, fail) => { const res = []; for (let k of keys) { const val = index.get(k); if (val === void 0) { if (fail) throw new Error(`unknwon key/ID: ${k}`); } else { res.push(val); } } return res; }; const defBidirIndex = (keys, opts) => new BidirIndex(keys, opts); const bidirIndexFromJSON = (src, map) => { const $src = typeof src === "string" ? JSON.parse(src) : src; const res = new BidirIndex(null, { map, start: $src.nextID }); $src.pairs.forEach(([k, id]) => { res.fwd.set(k, id); res.rev.set(id, k); }); return res; }; export { BidirIndex, bidirIndexFromJSON, defBidirIndex };