-
-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(wasm-api): major update ObjectIndex
- add ObjectIndexOpts ctor options - add IDGen for internal ID generation/recycling - add iterators - rename existing methods
- Loading branch information
1 parent
bd7905a
commit 4547f1f
Showing
3 changed files
with
190 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,92 +1,95 @@ | ||
{ | ||
"name": "@thi.ng/wasm-api", | ||
"version": "0.1.0", | ||
"description": "Modular, extensible API bridge and generic glue code between JS & WebAssembly", | ||
"type": "module", | ||
"module": "./index.js", | ||
"typings": "./index.d.ts", | ||
"sideEffects": false, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/thi-ng/umbrella.git" | ||
}, | ||
"homepage": "https://github.com/thi-ng/umbrella/tree/master/packages/wasm-api#readme", | ||
"funding": [ | ||
{ | ||
"type": "github", | ||
"url": "https://github.com/sponsors/postspectacular" | ||
}, | ||
{ | ||
"type": "patreon", | ||
"url": "https://patreon.com/thing_umbrella" | ||
} | ||
], | ||
"author": "Karsten Schmidt <k+npm@thi.ng>", | ||
"license": "Apache-2.0", | ||
"scripts": { | ||
"build": "yarn clean && tsc --declaration", | ||
"clean": "rimraf '*.js' '*.d.ts' '*.map' doc", | ||
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts", | ||
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose", | ||
"doc:readme": "yarn doc:stats && tools:readme", | ||
"doc:stats": "tools:module-stats", | ||
"pub": "yarn npm publish --access public", | ||
"test": "testament test" | ||
}, | ||
"dependencies": { | ||
"@thi.ng/api": "^8.3.9", | ||
"@thi.ng/errors": "^2.1.9", | ||
"@thi.ng/hex": "^2.1.9", | ||
"@thi.ng/logger": "^1.1.9" | ||
}, | ||
"devDependencies": { | ||
"@microsoft/api-extractor": "^7.25.0", | ||
"@thi.ng/testament": "^0.2.10", | ||
"rimraf": "^3.0.2", | ||
"tools": "workspace:^", | ||
"typedoc": "^0.22.17", | ||
"typescript": "^4.7.4" | ||
}, | ||
"keywords": [ | ||
"api", | ||
"memory", | ||
"typescript", | ||
"wasm", | ||
"webassembly", | ||
"wrapper", | ||
"ziglang" | ||
], | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"browser": { | ||
"process": false, | ||
"setTimeout": false | ||
}, | ||
"engines": { | ||
"node": ">=14" | ||
}, | ||
"files": [ | ||
"*.js", | ||
"*.d.ts", | ||
"*.zig" | ||
], | ||
"exports": { | ||
".": { | ||
"default": "./index.js" | ||
}, | ||
"./api": { | ||
"default": "./api.js" | ||
}, | ||
"./bridge": { | ||
"default": "./bridge.js" | ||
}, | ||
"./object-index": { | ||
"default": "./object-index.js" | ||
} | ||
}, | ||
"thi.ng": { | ||
"status": "alpha", | ||
"year": 2022 | ||
} | ||
"name": "@thi.ng/wasm-api", | ||
"version": "0.1.0", | ||
"description": "Modular, extensible API bridge and generic glue code between JS & WebAssembly", | ||
"type": "module", | ||
"module": "./index.js", | ||
"typings": "./index.d.ts", | ||
"sideEffects": false, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/thi-ng/umbrella.git" | ||
}, | ||
"homepage": "https://github.com/thi-ng/umbrella/tree/master/packages/wasm-api#readme", | ||
"funding": [ | ||
{ | ||
"type": "github", | ||
"url": "https://github.com/sponsors/postspectacular" | ||
}, | ||
{ | ||
"type": "patreon", | ||
"url": "https://patreon.com/thing_umbrella" | ||
} | ||
], | ||
"author": "Karsten Schmidt <k+npm@thi.ng>", | ||
"license": "Apache-2.0", | ||
"scripts": { | ||
"build": "yarn clean && tsc --declaration", | ||
"clean": "rimraf '*.js' '*.d.ts' '*.map' doc", | ||
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts", | ||
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose", | ||
"doc:readme": "yarn doc:stats && tools:readme", | ||
"doc:stats": "tools:module-stats", | ||
"pub": "yarn npm publish --access public", | ||
"test": "testament test" | ||
}, | ||
"dependencies": { | ||
"@thi.ng/api": "^8.3.9", | ||
"@thi.ng/errors": "^2.1.9", | ||
"@thi.ng/hex": "^2.1.9", | ||
"@thi.ng/idgen": "^2.1.9", | ||
"@thi.ng/logger": "^1.1.9" | ||
}, | ||
"devDependencies": { | ||
"@microsoft/api-extractor": "^7.25.0", | ||
"@thi.ng/testament": "^0.2.10", | ||
"rimraf": "^3.0.2", | ||
"tools": "workspace:^", | ||
"typedoc": "^0.22.17", | ||
"typescript": "^4.7.4" | ||
}, | ||
"keywords": [ | ||
"api", | ||
"id", | ||
"logger", | ||
"memory", | ||
"typescript", | ||
"wasm", | ||
"webassembly", | ||
"wrapper", | ||
"ziglang" | ||
], | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"browser": { | ||
"process": false, | ||
"setTimeout": false | ||
}, | ||
"engines": { | ||
"node": ">=14" | ||
}, | ||
"files": [ | ||
"*.js", | ||
"*.d.ts", | ||
"*.zig" | ||
], | ||
"exports": { | ||
".": { | ||
"default": "./index.js" | ||
}, | ||
"./api": { | ||
"default": "./api.js" | ||
}, | ||
"./bridge": { | ||
"default": "./bridge.js" | ||
}, | ||
"./object-index": { | ||
"default": "./object-index.js" | ||
} | ||
}, | ||
"thi.ng": { | ||
"status": "alpha", | ||
"year": 2022 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,116 @@ | ||
import type { Predicate } from "@thi.ng/api"; | ||
import type { Predicate, Range1_32 } from "@thi.ng/api"; | ||
import { assert } from "@thi.ng/errors/assert"; | ||
import { IDGen } from "@thi.ng/idgen"; | ||
import type { ILogger } from "@thi.ng/logger"; | ||
|
||
export interface ObjectIndexOpts { | ||
/** | ||
* Human-readable name for index (used for logging, if any) | ||
*/ | ||
name: string; | ||
/** | ||
* Optional logger instance | ||
*/ | ||
logger?: ILogger; | ||
/** | ||
* Number of bits for IDs, [1..32] range. | ||
* | ||
* @defaultValue 32 | ||
*/ | ||
bits?: Range1_32; | ||
} | ||
|
||
export class ObjectIndex<T> { | ||
constructor( | ||
public name: string, | ||
public items: T[] = [], | ||
public logger?: ILogger | ||
) {} | ||
|
||
add(x: T): number { | ||
const id = this.items.length - 1; | ||
public readonly name: string; | ||
public logger?: ILogger; | ||
protected idgen: IDGen; | ||
protected items: T[] = []; | ||
|
||
constructor(opts: ObjectIndexOpts) { | ||
this.name = opts.name; | ||
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: T): number { | ||
const id = this.idgen.next(); | ||
this.logger && this.logger.debug(`adding ${this.name} ID: ${id}`); | ||
this.items[id] = x; | ||
this.items[id] = item; | ||
return id; | ||
} | ||
|
||
removeID(id: number) { | ||
if (this.items[id] !== undefined) { | ||
/** | ||
* Returns true if the given `id` is valid/active. | ||
* | ||
* @param id | ||
*/ | ||
has(id: number) { | ||
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: number, ensure = true) { | ||
if (this.idgen.has(id)) { | ||
this.logger && 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; | ||
} | ||
|
||
getID(id: number): T; | ||
getID(id: number, ensure: true): T; | ||
getID(id: number, ensure: false): T | undefined; | ||
getID(id: number, ensure = true) { | ||
const obj = this.items[id]; | ||
/** | ||
* First checks if given `id` is valid and if so returns corresponding item. | ||
* If `ensure` is true (default), throws an error if the ID is invalid | ||
* (otherwise returns undefined for invalid IDs) | ||
* | ||
* @param id | ||
*/ | ||
get(id: number): T; | ||
get(id: number, ensure: true): T; | ||
get(id: number, ensure: false): T | undefined; | ||
get(id: number, ensure = true) { | ||
ensure && | ||
assert(obj !== undefined, `missing ${this.name} for ID: ${id}`); | ||
return obj; | ||
assert(this.idgen.has(id), `missing ${this.name} for ID: ${id}`); | ||
return this.items[id]; | ||
} | ||
|
||
findID(pred: Predicate<T>, ensure = true) { | ||
const id = this.items.findIndex(pred); | ||
ensure && assert(id >= 0, `can't find ${this.name}`); | ||
return 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: Predicate<T>, ensure = true) { | ||
for (let id of this.idgen) { | ||
if (pred(this.items[id])) return id; | ||
} | ||
assert(!ensure, `given predicate matched no ${this.name}`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters