@thi.ng/wasm-api
Version:
Generic, modular, extensible API bridge and infrastructure for hybrid JS & WebAssembly projects
98 lines (97 loc) • 2.6 kB
JavaScript
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 (let 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 (let id of this.idgen) {
if (pred(this.items[id])) return id;
}
assert(!ensure, `given predicate matched no ${this.name}`);
}
}
export {
ObjectIndex
};