UNPKG

@thi.ng/wasm-api

Version:

Generic, modular, extensible API bridge and infrastructure for hybrid JS & WebAssembly projects

98 lines (97 loc) 2.6 kB
import { assert } from "@thi.ng/errors/assert"; import { IDGen } from "@thi.ng/idgen"; let __nextID = 0; class ObjectIndex { name; logger; idgen; items = []; constructor(opts) { this.name = opts?.name ?? `idx-${__nextID++}`; this.logger = opts?.logger; this.idgen = new IDGen(opts?.bits ?? 32, 0); } keys() { return this.idgen[Symbol.iterator](); } *values() { for (const id of this.idgen) { yield this.items[id]; } } /** * Indexes given `item` and assigns it to the next available ID (which might * be a previously freed ID) and returns it. * * @param item */ add(item) { const id = this.idgen.next(); this.logger?.debug(`adding ${this.name} ID: ${id}`); this.items[id] = item; return id; } /** * Similar to {@link ObjectIndex.add}, but first checks if `item` has * already been indexed and if so returns the ID of already indexed item * without adding `item` to the index again. Uses `equiv` for checking item * equality (by default: `===`). * * @remarks * Currently an O(n) implementation. * * @param item * @param equiv */ addUnique(item, equiv = (x) => x === item) { const id = this.find(equiv, false); return id === void 0 ? this.add(item) : id; } /** * Returns true if the given `id` is valid/active. * * @param id */ has(id) { return this.idgen.has(id); } /** * First checks if given `id` is valid and if so frees it (for recycling) * and deletes its corresponding item. If `ensure` is true (default), throws * an error if the ID is invalid (otherwise returns false for invalid IDs). * * @param id * @param ensure */ delete(id, ensure = true) { if (this.idgen.has(id)) { this.logger?.debug(`deleting ${this.name} ID: ${id}`); this.idgen.free(id); delete this.items[id]; return true; } assert(!ensure, `can't delete missing ${this.name} ID: ${id}`); return false; } get(id, ensure = true) { ensure && assert(this.idgen.has(id), `missing ${this.name} for ID: ${id}`); return this.items[id]; } /** * Applies given predicate to all active items and returns ID of first * matching. If `ensure` is true (default), throws an error if the `pred` * didn't match anything (otherwise returns undefined). * * @param pred * @param ensure */ find(pred, ensure = true) { for (const id of this.idgen) { if (pred(this.items[id])) return id; } assert(!ensure, `given predicate matched no ${this.name}`); } } export { ObjectIndex };