@daneren2005/shared-memory-objects 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -56
- package/dist/{src/allocated-memory.d.ts → allocated-memory.d.ts} +6 -4
- package/dist/allocated-memory.js +47 -37
- package/dist/allocated-memory.js.map +1 -1
- package/dist/{src/cached-item-list.d.ts → cached-item-list.d.ts} +5 -4
- package/dist/cached-item-list.js +75 -75
- package/dist/cached-item-list.js.map +1 -1
- package/dist/constant-string.d.ts +15 -0
- package/dist/constant-string.js +67 -0
- package/dist/constant-string.js.map +1 -0
- package/dist/interfaces/pow2.js +0 -2
- package/dist/interfaces/typed-array-constructor.js +0 -2
- package/dist/interfaces/typed-array.js +0 -2
- package/dist/{src/local-pool.d.ts → local-pool.d.ts} +2 -2
- package/dist/local-pool.js +89 -94
- package/dist/local-pool.js.map +1 -1
- package/dist/lock/read-write-lock.js +15 -21
- package/dist/lock/read-write-lock.js.map +1 -1
- package/dist/lock/simple-lock.js +9 -12
- package/dist/lock/simple-lock.js.map +1 -1
- package/dist/{src/memory-buffer.d.ts → memory-buffer.d.ts} +8 -5
- package/dist/memory-buffer.js +269 -326
- package/dist/memory-buffer.js.map +1 -1
- package/dist/{src/memory-heap.d.ts → memory-heap.d.ts} +4 -2
- package/dist/memory-heap.js +105 -115
- package/dist/memory-heap.js.map +1 -1
- package/dist/{src/serialize-object.d.ts → serialize-object.d.ts} +2 -2
- package/dist/serialize-object.js +43 -55
- package/dist/serialize-object.js.map +1 -1
- package/dist/{src/shared-list.d.ts → shared-list.d.ts} +11 -5
- package/dist/shared-list.js +162 -164
- package/dist/shared-list.js.map +1 -1
- package/dist/{src/shared-map.d.ts → shared-map.d.ts} +2 -2
- package/dist/shared-map.js +105 -138
- package/dist/shared-map.js.map +1 -1
- package/dist/{src/shared-pointer-list.d.ts → shared-pointer-list.d.ts} +4 -3
- package/dist/shared-pointer-list.js +49 -48
- package/dist/shared-pointer-list.js.map +1 -1
- package/dist/{src/shared-pool.d.ts → shared-pool.d.ts} +15 -8
- package/dist/shared-pool.js +151 -164
- package/dist/shared-pool.js.map +1 -1
- package/dist/shared-stack.d.ts +59 -0
- package/dist/shared-stack.js +221 -0
- package/dist/shared-stack.js.map +1 -0
- package/dist/{src/shared-string.d.ts → shared-string.d.ts} +2 -2
- package/dist/shared-string.js +72 -78
- package/dist/shared-string.js.map +1 -1
- package/dist/{src/shared-vector.d.ts → shared-vector.d.ts} +5 -4
- package/dist/shared-vector.js +150 -164
- package/dist/shared-vector.js.map +1 -1
- package/dist/utils/16-from-32-array.js +14 -16
- package/dist/utils/16-from-32-array.js.map +1 -1
- package/dist/utils/16-from-64-array.js +15 -10
- package/dist/utils/16-from-64-array.js.map +1 -1
- package/dist/utils/atomic-math.js +30 -32
- package/dist/utils/atomic-math.js.map +1 -1
- package/dist/utils/float32-atomics.js +18 -22
- package/dist/utils/float32-atomics.js.map +1 -1
- package/dist/utils/float64-atomics.js +18 -22
- package/dist/utils/float64-atomics.js.map +1 -1
- package/dist/utils/pointer.js +34 -44
- package/dist/utils/pointer.js.map +1 -1
- package/dist/{src/utils → utils}/typedarray.d.ts +47 -47
- package/dist/utils/typedarray.js +36 -43
- package/dist/utils/typedarray.js.map +1 -1
- package/package.json +23 -22
- package/dist/interfaces/pow2.js.map +0 -1
- package/dist/interfaces/typed-array-constructor.js.map +0 -1
- package/dist/interfaces/typed-array.js.map +0 -1
- /package/dist/{src/interfaces → interfaces}/pow2.d.ts +0 -0
- /package/dist/{src/interfaces → interfaces}/typed-array-constructor.d.ts +0 -0
- /package/dist/{src/interfaces → interfaces}/typed-array.d.ts +0 -0
- /package/dist/{src/lock → lock}/read-write-lock.d.ts +0 -0
- /package/dist/{src/lock → lock}/simple-lock.d.ts +0 -0
- /package/dist/{src/utils → utils}/16-from-32-array.d.ts +0 -0
- /package/dist/{src/utils → utils}/16-from-64-array.d.ts +0 -0
- /package/dist/{src/utils → utils}/atomic-math.d.ts +0 -0
- /package/dist/{src/utils → utils}/float32-atomics.d.ts +0 -0
- /package/dist/{src/utils → utils}/float64-atomics.d.ts +0 -0
- /package/dist/{src/utils → utils}/pointer.d.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-buffer.js","sources":["../src/memory-buffer.ts"],"sourcesContent":["// Just disabling this rule instead of re-writing for now to keep asa close to original in case we want to pull updates later\n// Doing `block && block.fill(fill)` instead of `if(block) { block.fill(fill); }` is valid code even if it is hard to parse\n/* eslint-disable @typescript-eslint/no-unused-expressions */\n\nimport type { Pow2 } from './interfaces/pow2';\nimport type { TypedArray } from './interfaces/typed-array';\nimport { lock, unlock } from './lock/simple-lock';\nimport { typedArray } from './utils/typedarray';\n\nconst STATE_FREE = 0;\nconst STATE_USED = 1;\nconst STATE_TOP = 2;\nconst STATE_END = 3;\nconst STATE_ALIGN = 4;\nconst STATE_FLAGS = 5;\nconst STATE_MIN_SPLIT = 6;\n\nconst MASK_COMPACT = 1;\nconst MASK_SPLIT = 2;\n\nconst SIZEOF_STATE = 8 * 4;\n\nconst MEM_BLOCK_SIZE = 0;\nconst MEM_BLOCK_NEXT = 1;\n\nconst SIZEOF_MEM_BLOCK = 2 * 4;\n\n// Copied from https://github.com/thi-ng/umbrella/blob/develop/packages/malloc/src/pool.ts\n// Changes: Atomic.load/store on state, simple lock on malloc/free\n// Added bytesFor/lengthOf to be able to grab expected length of a block\nexport default class MemoryBuffer {\n\tbuf: ArrayBufferLike;\n\n\tprotected readonly start: number;\n\tprotected u8: Uint8Array;\n\tprotected u32: Uint32Array;\n\tprotected state: Uint32Array;\n\tprotected lock: Int32Array;\n\n\tconstructor(opts: Partial<MemoryBufferConfig> = {}) {\n\t\tthis.buf = opts.buf ? opts.buf : new ArrayBuffer(opts.size || 0x1000);\n\t\tthis.start = opts.start != null ? align(Math.max(opts.start, 0), 4) : 0;\n\t\tthis.u8 = new Uint8Array(this.buf);\n\t\tthis.u32 = new Uint32Array(this.buf);\n\t\tthis.state = new Uint32Array(this.buf, this.start, SIZEOF_STATE / 4);\n\t\tthis.lock = new Int32Array(this.buf, this.start + this.state.byteLength - 4, 1);\n\n\t\tif(!opts.skipInitialization) {\n\t\t\tconst _align = opts.align || 8;\n\t\t\tif(_align < 8) {\n\t\t\t\tthrow new Error(`invalid alignment: ${_align}, must be a pow2 and >= 8`);\n\t\t\t}\n\t\t\tconst top = this.initialTop(_align);\n\t\t\tconst resolvedEnd =\n\t\t\t\topts.end != null\n\t\t\t\t\t? Math.min(opts.end, this.buf.byteLength)\n\t\t\t\t\t: this.buf.byteLength;\n\n\t\t\tif(top >= resolvedEnd) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`insufficient address range (0x${this.start.toString(\n\t\t\t\t\t\t16\n\t\t\t\t\t)} - 0x${resolvedEnd.toString(16)})`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.align = _align;\n\t\t\tthis.doCompact = opts.compact !== false;\n\t\t\tthis.doSplit = opts.split !== false;\n\t\t\tthis.minSplit = opts.minSplit || 16;\n\t\t\tthis.end = resolvedEnd;\n\t\t\tthis.top = top;\n\t\t\tthis._free = 0;\n\t\t\tthis._used = 0;\n\t\t}\n\t}\n\n\tstats(): Readonly<MemoryBufferStats> {\n\t\tconst listStats = (block: number) => {\n\t\t\tlet count = 0;\n\t\t\tlet size = 0;\n\t\t\twhile(block) {\n\t\t\t\tcount++;\n\t\t\t\tsize += this.blockSize(block);\n\t\t\t\tblock = this.blockNext(block);\n\n\t\t\t\tif(block > this.end) {\n\t\t\t\t\tconsole.error(`Trying to get stats for block past end of buffer: ${block} > ${this.end}`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { count, size };\n\t\t};\n\t\tconst free = listStats(this._free);\n\t\treturn {\n\t\t\tfree,\n\t\t\tused: listStats(this._used),\n\t\t\ttop: this.top,\n\t\t\tavailable: this.end - this.top + free.size,\n\t\t\ttotal: this.buf.byteLength\n\t\t};\n\t}\n\n\tcallocAs<T extends Type>(type: T, num: number, fill = 0) {\n\t\tconst block = this.mallocAs(type, num);\n\t\tblock && block.fill(fill);\n\t\treturn block;\n\t}\n\n\tmallocAs<T extends Type>(type: T, num: number) {\n\t\tconst addr = this.malloc(num * SIZEOF[type]);\n\t\treturn addr ? typedArray(type, this.buf, addr, num) : undefined;\n\t}\n\n\tcalloc(bytes: number, fill = 0) {\n\t\tconst addr = this.malloc(bytes);\n\t\taddr && this.u8.fill(fill, addr, addr + bytes);\n\t\treturn addr;\n\t}\n\n\tmalloc(bytes: number) {\n\t\tif(bytes <= 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tlock(this.lock);\n\t\tconst paddedSize = align(bytes + SIZEOF_MEM_BLOCK, this.align);\n\t\tconst end = this.end;\n\t\tlet top = this.top;\n\t\tlet block = this._free;\n\t\tlet prev = 0;\n\t\twhile(block) {\n\t\t\tconst blockSize = this.blockSize(block);\n\t\t\tconst isTop = block + blockSize >= top;\n\t\t\tif(isTop || blockSize >= paddedSize) {\n\t\t\t\tlet result = this.mallocTop(\n\t\t\t\t\tblock,\n\t\t\t\t\tprev,\n\t\t\t\t\tblockSize,\n\t\t\t\t\tpaddedSize,\n\t\t\t\t\tisTop\n\t\t\t\t);\n\n\t\t\t\tunlock(this.lock);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tprev = block;\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\t\tblock = top;\n\t\ttop = block + paddedSize;\n\t\tif(top <= end) {\n\t\t\tthis.initBlock(block, paddedSize, this._used);\n\t\t\tthis._used = block;\n\t\t\tthis.top = top;\n\t\t\tlet result = blockDataAddress(block);\n\t\t\tunlock(this.lock);\n\n\t\t\treturn result;\n\t\t}\n\t\tunlock(this.lock);\n\t\treturn 0;\n\t}\n\n\tprivate mallocTop(\n\t\tblock: number,\n\t\tprev: number,\n\t\tblockSize: number,\n\t\tpaddedSize: number,\n\t\tisTop: boolean\n\t) {\n\t\tif(isTop && block + paddedSize > this.end) return 0;\n\t\tif(prev) {\n\t\t\tthis.unlinkBlock(prev, block);\n\t\t} else {\n\t\t\tthis._free = this.blockNext(block);\n\t\t}\n\t\tthis.setBlockNext(block, this._used);\n\t\tthis._used = block;\n\t\tif(isTop) {\n\t\t\tthis.top = block + this.setBlockSize(block, paddedSize);\n\t\t} else if(this.doSplit) {\n\t\t\tconst excess = blockSize - paddedSize;\n\t\t\texcess >= this.minSplit &&\n\t\t\t\tthis.splitBlock(block, paddedSize, excess);\n\t\t}\n\t\treturn blockDataAddress(block);\n\t}\n\n\trealloc(ptr: number, bytes: number) {\n\t\tif(bytes <= 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst oldAddr = blockSelfAddress(ptr);\n\t\tlet newAddr = 0;\n\t\tlet block = this._used;\n\t\tlet blockEnd = 0;\n\t\twhile(block) {\n\t\t\tif(block === oldAddr) {\n\t\t\t\t[newAddr, blockEnd] = this.reallocBlock(block, bytes);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\t\t// copy old block contents to new addr\n\t\tif(newAddr && newAddr !== oldAddr) {\n\t\t\tthis.u8.copyWithin(\n\t\t\t\tblockDataAddress(newAddr),\n\t\t\t\tblockDataAddress(oldAddr),\n\t\t\t\tblockEnd\n\t\t\t);\n\t\t}\n\t\treturn blockDataAddress(newAddr);\n\t}\n\n\tprivate reallocBlock(block: number, bytes: number) {\n\t\tconst blockSize = this.blockSize(block);\n\t\tconst blockEnd = block + blockSize;\n\t\tconst isTop = blockEnd >= this.top;\n\t\tconst paddedSize = align(bytes + SIZEOF_MEM_BLOCK, this.align);\n\t\t// shrink & possibly split existing block\n\t\tif(paddedSize <= blockSize) {\n\t\t\tif(this.doSplit) {\n\t\t\t\tconst excess = blockSize - paddedSize;\n\t\t\t\tif(excess >= this.minSplit) {\n\t\t\t\t\tthis.splitBlock(block, paddedSize, excess);\n\t\t\t\t} else if(isTop) {\n\t\t\t\t\tthis.top = block + paddedSize;\n\t\t\t\t}\n\t\t\t} else if(isTop) {\n\t\t\t\tthis.top = block + paddedSize;\n\t\t\t}\n\t\t\treturn [block, blockEnd];\n\t\t}\n\t\t// try to enlarge block if current top\n\t\tif(isTop && block + paddedSize < this.end) {\n\t\t\tthis.top = block + this.setBlockSize(block, paddedSize);\n\t\t\treturn [block, blockEnd];\n\t\t}\n\t\t// fallback to free & malloc\n\t\tthis.free(block);\n\t\treturn [blockSelfAddress(this.malloc(bytes)), blockEnd];\n\t}\n\n\treallocArray<T extends TypedArray>(array: T, num: number): T | undefined {\n\t\tif(array.buffer !== this.buf) {\n\t\t\treturn;\n\t\t}\n\t\tconst addr = this.realloc(\n\t\t\tarray.byteOffset,\n\t\t\tnum * array.BYTES_PER_ELEMENT\n\t\t);\n\t\treturn addr\n\t\t\t? new (<any>array.constructor)(this.buf, addr, num)\n\t\t\t: undefined;\n\t}\n\n\tbytesFor(ptrOrArray: number | TypedArray): number | undefined {\n\t\tlet addr: number;\n\t\tif(typeof ptrOrArray !== 'number') {\n\t\t\tif(ptrOrArray.buffer !== this.buf) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\taddr = ptrOrArray.byteOffset;\n\t\t} else {\n\t\t\taddr = ptrOrArray;\n\t\t}\n\n\t\taddr = blockSelfAddress(addr);\n\t\tlet block = this._used;\n\t\twhile(block) {\n\t\t\tif(block === addr) {\n\t\t\t\treturn this.blockSize(addr) - SIZEOF_MEM_BLOCK;\n\t\t\t}\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\tlengthOf(ptrOrArray: number | TypedArray): number | undefined {\n\t\tlet bytes = this.bytesFor(ptrOrArray);\n\t\tif(bytes) {\n\t\t\treturn bytes / this.u32.BYTES_PER_ELEMENT;\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tfree(ptrOrArray: number | TypedArray) {\n\t\tlet addr: number;\n\t\tif(typeof ptrOrArray !== 'number') {\n\t\t\tif(ptrOrArray.buffer !== this.buf) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\taddr = ptrOrArray.byteOffset;\n\t\t} else {\n\t\t\taddr = ptrOrArray;\n\t\t}\n\t\tlock(this.lock);\n\t\taddr = blockSelfAddress(addr);\n\t\tlet block = this._used;\n\t\tlet prev = 0;\n\t\twhile(block) {\n\t\t\tif(block === addr) {\n\t\t\t\tif(prev) {\n\t\t\t\t\tthis.unlinkBlock(prev, block);\n\t\t\t\t} else {\n\t\t\t\t\tthis._used = this.blockNext(block);\n\t\t\t\t}\n\t\t\t\tthis.insert(block);\n\t\t\t\tthis.doCompact && this.compact();\n\n\t\t\t\tunlock(this.lock);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tprev = block;\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\n\t\tunlock(this.lock);\n\t\treturn false;\n\t}\n\n\tfreeAll() {\n\t\tthis._free = 0;\n\t\tthis._used = 0;\n\t\tthis.top = this.initialTop();\n\t}\n\n\trelease() {\n\t\tdelete (<any> this).u8;\n\t\tdelete (<any> this).u32;\n\t\tdelete (<any> this).state;\n\t\tdelete (<any> this).buf;\n\t\treturn true;\n\t}\n\n\tprotected get align() {\n\t\treturn <Pow2> this.state[STATE_ALIGN];\n\t}\n\n\tprotected set align(x: Pow2) {\n\t\tthis.state[STATE_ALIGN] = x;\n\t}\n\n\tget end() {\n\t\treturn this.state[STATE_END];\n\t}\n\n\tprotected set end(x: number) {\n\t\tthis.state[STATE_END] = x;\n\t}\n\n\tget top() {\n\t\treturn Atomics.load(this.state, STATE_TOP);\n\t}\n\n\tprotected set top(x: number) {\n\t\tAtomics.store(this.state, STATE_TOP, x);\n\t}\n\n\tprotected get _free() {\n\t\treturn Atomics.load(this.state, STATE_FREE);\n\t}\n\n\tprotected set _free(block: number) {\n\t\tAtomics.store(this.state, STATE_FREE, block);\n\t}\n\n\tprotected get _used() {\n\t\treturn Atomics.load(this.state, STATE_USED);\n\t}\n\n\tprotected set _used(block: number) {\n\t\tAtomics.store(this.state, STATE_USED, block);\n\t}\n\n\tprotected get doCompact() {\n\t\treturn !!(this.state[STATE_FLAGS] & MASK_COMPACT);\n\t}\n\n\tprotected set doCompact(flag: boolean) {\n\t\tflag\n\t\t\t? (this.state[STATE_FLAGS] |= 1 << (MASK_COMPACT - 1))\n\t\t\t: (this.state[STATE_FLAGS] &= ~MASK_COMPACT);\n\t}\n\n\tprotected get doSplit() {\n\t\treturn !!(this.state[STATE_FLAGS] & MASK_SPLIT);\n\t}\n\n\tprotected set doSplit(flag: boolean) {\n\t\tflag\n\t\t\t? (this.state[STATE_FLAGS] |= 1 << (MASK_SPLIT - 1))\n\t\t\t: (this.state[STATE_FLAGS] &= ~MASK_SPLIT);\n\t}\n\n\tprotected get minSplit() {\n\t\treturn this.state[STATE_MIN_SPLIT];\n\t}\n\n\tprotected set minSplit(x: number) {\n\t\tif(x <= SIZEOF_MEM_BLOCK) {\n\t\t\tthrow new Error(`illegal min split threshold: ${x}, require at least ${\n\t\t\t\tSIZEOF_MEM_BLOCK + 1\n\t\t\t}`);\n\t\t}\n\t\tthis.state[STATE_MIN_SPLIT] = x;\n\t}\n\n\tprotected blockSize(block: number) {\n\t\treturn Atomics.load(this.u32, (block >> 2) + MEM_BLOCK_SIZE);\n\t}\n\n\t/**\n\t * Sets & returns given block size.\n\t *\n\t * @param block -\n\t * @param size -\n\t */\n\tprotected setBlockSize(block: number, size: number) {\n\t\tAtomics.store(this.u32, (block >> 2) + MEM_BLOCK_SIZE, size);\n\t\treturn size;\n\t}\n\n\tprotected blockNext(block: number) {\n\t\treturn Atomics.load(this.u32, (block >> 2) + MEM_BLOCK_NEXT);\n\t}\n\n\t/**\n\t * Sets block next pointer to `next`. Use zero to indicate list end.\n\t *\n\t * @param block -\n\t */\n\tprotected setBlockNext(block: number, next: number) {\n\t\tAtomics.store(this.u32, (block >> 2) + MEM_BLOCK_NEXT, next);\n\t}\n\n\t/**\n\t * Initializes block header with given `size` and `next` pointer. Returns `block`.\n\t *\n\t * @param block -\n\t * @param size -\n\t * @param next -\n\t */\n\tprotected initBlock(block: number, size: number, next: number) {\n\t\tconst idx = block >>> 2;\n\t\tAtomics.store(this.u32, idx + MEM_BLOCK_SIZE, size);\n\t\tAtomics.store(this.u32, idx + MEM_BLOCK_NEXT, next);\n\t\treturn block;\n\t}\n\n\tprotected unlinkBlock(prev: number, block: number) {\n\t\tthis.setBlockNext(prev, this.blockNext(block));\n\t}\n\n\tprotected splitBlock(block: number, blockSize: number, excess: number) {\n\t\tthis.insert(\n\t\t\tthis.initBlock(\n\t\t\t\tblock + this.setBlockSize(block, blockSize),\n\t\t\t\texcess,\n\t\t\t\t0\n\t\t\t)\n\t\t);\n\t\tthis.doCompact && this.compact();\n\t}\n\n\tprotected initialTop(_align = this.align) {\n\t\treturn (\n\t\t\talign(this.start + SIZEOF_STATE + SIZEOF_MEM_BLOCK, _align) -\n\t\t\tSIZEOF_MEM_BLOCK\n\t\t);\n\t}\n\n\t/**\n\t * Traverses free list and attempts to recursively merge blocks\n\t * occupying consecutive memory regions. Returns true if any blocks\n\t * have been merged. Only called if `compact` option is enabled.\n\t */\n\tprotected compact() {\n\t\tlet block = this._free;\n\t\tlet prev = 0;\n\t\tlet scan = 0;\n\t\tlet scanPrev: number;\n\t\tlet res = false;\n\t\twhile(block) {\n\t\t\tscanPrev = block;\n\t\t\tscan = this.blockNext(block);\n\t\t\twhile(scan && scanPrev + this.blockSize(scanPrev) === scan) {\n\t\t\t\t// console.log(\"merge:\", scan.addr, scan.size);\n\t\t\t\tscanPrev = scan;\n\t\t\t\tscan = this.blockNext(scan);\n\t\t\t}\n\t\t\tif(scanPrev !== block) {\n\t\t\t\tconst newSize = scanPrev - block + this.blockSize(scanPrev);\n\t\t\t\t// console.log(\"merged size:\", newSize);\n\t\t\t\tthis.setBlockSize(block, newSize);\n\t\t\t\tconst next = this.blockNext(scanPrev);\n\t\t\t\tlet tmp = this.blockNext(block);\n\t\t\t\twhile(tmp && tmp !== next) {\n\t\t\t\t\t// console.log(\"release:\", tmp.addr);\n\t\t\t\t\tconst tn = this.blockNext(tmp);\n\t\t\t\t\tthis.setBlockNext(tmp, 0);\n\t\t\t\t\ttmp = tn;\n\t\t\t\t}\n\t\t\t\tthis.setBlockNext(block, next);\n\t\t\t\tres = true;\n\t\t\t}\n\t\t\t// re-adjust top if poss\n\t\t\tif(block + this.blockSize(block) >= this.top) {\n\t\t\t\tthis.top = block;\n\t\t\t\tprev\n\t\t\t\t\t? this.unlinkBlock(prev, block)\n\t\t\t\t\t: (this._free = this.blockNext(block));\n\t\t\t}\n\t\t\tprev = block;\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\t\treturn res;\n\t}\n\n\t/**\n\t * Inserts given block into list of free blocks, sorted by address.\n\t *\n\t * @param block -\n\t */\n\tprotected insert(block: number) {\n\t\tlet ptr = this._free;\n\t\tlet prev = 0;\n\t\twhile(ptr) {\n\t\t\tif(block <= ptr) break;\n\t\t\tprev = ptr;\n\t\t\tptr = this.blockNext(ptr);\n\t\t}\n\t\tif(prev) {\n\t\t\tthis.setBlockNext(prev, block);\n\t\t} else {\n\t\t\tthis._free = block;\n\t\t}\n\t\tthis.setBlockNext(block, ptr);\n\t}\n}\n\n/**\n * Returns a block's data address, based on given alignment.\n *\n * @param blockAddress -\n */\nconst blockDataAddress = (blockAddress: number) => blockAddress > 0 ? blockAddress + SIZEOF_MEM_BLOCK : 0;\n\n/**\n * Returns block start address for given data address and alignment.\n *\n * @param dataAddress -\n */\nconst blockSelfAddress = (dataAddress: number) => dataAddress > 0 ? dataAddress - SIZEOF_MEM_BLOCK : 0;\n\nconst align = (addr: number, size: number) => (size--, addr + size & ~size);\nconst SIZEOF = {\n\tu8: 1,\n\tu8c: 1,\n\ti8: 1,\n\tu16: 2,\n\ti16: 2,\n\tu32: 4,\n\ti32: 4,\n\ti64: 8,\n\tu64: 8,\n\tf32: 4,\n\tf64: 8\n};\ntype Type = 'u8' | 'u8c' | 'i8' | 'u16' | 'i16' | 'u32' | 'i32' | 'f32' | 'f64';\n\ninterface MemoryBufferConfig {\n\t/**\n\t * Backing ArrayBuffer (or SharedArrayBuffer). If not given, a new\n\t * one will be created with given `size`.\n\t */\n\tbuf: ArrayBufferLike;\n\t/**\n\t * Byte size for newly created ArrayBuffers (if `buf` is not given).\n\t *\n\t * @defaultValue 0x1000 (4KB)\n\t */\n\tsize: number;\n\t/**\n\t * Anchor index (byte address) inside the array buffer. The MemPool\n\t * stores its internal state from the given address and heap space\n\t * starts at least 32 bytes later (depending on chosen `align`\n\t * value). Unlike allocator state variables, `start`` cannot be\n\t * saved inside the array buffer itself. If the ArrayBuffer is\n\t * passed to other consumers they must use the same start value.\n\t * MUST be multiple of 4.\n\t *\n\t * @defaultValue 0\n\t */\n\tstart: number;\n\t/**\n\t * Byte address (+1) of the end of the memory region managed by the\n\t * {@link MemPool}.\n\t *\n\t * @defaultValue end of the backing ArrayBuffer\n\t */\n\tend: number;\n\t/**\n\t * Number of bytes to align memory blocks to. MUST be a power of 2\n\t * and >= 8. Use 16 if the pool is being used for allocating memory\n\t * used in SIMD operations.\n\t *\n\t * @defaultValue 8\n\t */\n\talign: Pow2;\n\t/**\n\t * Flag to configure memory block compaction. If true,\n\t * adjoining free blocks (in terms of address space) will be merged\n\t * to minimize fragementation.\n\t *\n\t * @defaultValue true\n\t */\n\tcompact: boolean;\n\t/**\n\t * Flag to configure memory block splitting. If true, and when the\n\t * allocator is re-using a previously freed block larger than the\n\t * requested size, the block will be split to minimize wasted/unused\n\t * memory. The splitting behavior can further customized via the\n\t * `minSplit` option.\n\t *\n\t * @defaultValue true\n\t */\n\tsplit: boolean;\n\t/**\n\t * Only used if `split` behavior is enabled. Defines min number of\n\t * excess bytes available in a block for memory block splitting to\n\t * occur.\n\t *\n\t * @defaultValue 16, MUST be > 8\n\t */\n\tminSplit: number;\n\t/**\n\t * Only needed when sharing the underlying ArrayBuffer. If true, the\n\t * {@link MemPool} constructor will NOT initialize its internal state and\n\t * assume the underlying ArrayBuffer has already been initialized by\n\t * another {@link MemPool} instance. If this option is used, `buf` MUST be\n\t * given.\n\t *\n\t * @defaultValue false\n\t */\n\tskipInitialization: boolean;\n}\ninterface MemoryBufferStats {\n\t/**\n\t * Free block stats.\n\t */\n\tfree: { count: number; size: number };\n\t/**\n\t * Used block stats.\n\t */\n\tused: { count: number; size: number };\n\t/**\n\t * Current top address.\n\t */\n\ttop: number;\n\t/**\n\t * Bytes available\n\t */\n\tavailable: number;\n\t/**\n\t * Total pool size.\n\t */\n\ttotal: number;\n}"],"names":["STATE_FREE","STATE_USED","STATE_TOP","STATE_END","STATE_ALIGN","STATE_FLAGS","STATE_MIN_SPLIT","MASK_COMPACT","MASK_SPLIT","SIZEOF_STATE","MEM_BLOCK_SIZE","MEM_BLOCK_NEXT","SIZEOF_MEM_BLOCK","MemoryBuffer","opts","align","_align","top","resolvedEnd","listStats","block","count","size","free","type","num","fill","addr","SIZEOF","typedArray","bytes","lock","paddedSize","end","prev","blockSize","isTop","result","unlock","blockDataAddress","excess","ptr","oldAddr","blockSelfAddress","newAddr","blockEnd","array","ptrOrArray","x","flag","next","idx","scan","scanPrev","res","newSize","tmp","tn","blockAddress","dataAddress"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory-buffer.js","names":[],"sources":["../src/memory-buffer.ts"],"sourcesContent":["// Just disabling this rule instead of re-writing for now to keep asa close to original in case we want to pull updates later\n// Doing `block && block.fill(fill)` instead of `if(block) { block.fill(fill); }` is valid code even if it is hard to parse\n/* eslint-disable @typescript-eslint/no-unused-expressions */\n\nimport type { Pow2 } from './interfaces/pow2';\nimport type { TypedArray } from './interfaces/typed-array';\nimport { lock, unlock } from './lock/simple-lock';\nimport { typedArray } from './utils/typedarray';\n\nconst STATE_FREE = 0;\nconst STATE_USED = 1;\nconst STATE_TOP = 2;\nconst STATE_END = 3;\nconst STATE_ALIGN = 4;\nconst STATE_FLAGS = 5;\nconst STATE_MIN_SPLIT = 6;\n\nconst MASK_COMPACT = 1;\nconst MASK_SPLIT = 2;\n\nconst SIZEOF = {\n\tu8: 1,\n\tu8c: 1,\n\ti8: 1,\n\tu16: 2,\n\ti16: 2,\n\tu32: 4,\n\ti32: 4,\n\ti64: 8,\n\tu64: 8,\n\tf32: 4,\n\tf64: 8,\n};\n\nconst SIZEOF_STATE = 8 * 4;\n\nconst MEM_BLOCK_SIZE = 0;\nconst MEM_BLOCK_NEXT = 1;\n\nconst SIZEOF_MEM_BLOCK = 2 * 4;\n\n// Copied from https://github.com/thi-ng/umbrella/blob/develop/packages/malloc/src/pool.ts\n// Changes: Atomic.load/store on state, simple lock on malloc/free\n// Added bytesFor/lengthOf to be able to grab expected length of a block\nexport default class MemoryBuffer {\n\tbuf: ArrayBufferLike;\n\n\tprotected readonly start: number;\n\tprotected u8: Uint8Array;\n\tprotected u32: Uint32Array;\n\tprotected state: Uint32Array;\n\tprotected lock: Int32Array;\n\n\tconstructor(opts: Partial<MemoryBufferConfig> = {}) {\n\t\tthis.buf = opts.buf ? opts.buf : new ArrayBuffer(opts.size || 0x1000);\n\t\tthis.start = opts.start != null ? align(Math.max(opts.start, 0), 4) : 0;\n\t\tthis.u8 = new Uint8Array(this.buf);\n\t\tthis.u32 = new Uint32Array(this.buf);\n\t\tthis.state = new Uint32Array(this.buf, this.start, SIZEOF_STATE / 4);\n\t\tthis.lock = new Int32Array(this.buf, this.start + this.state.byteLength - 4, 1);\n\n\t\tif(!opts.skipInitialization) {\n\t\t\tconst _align = opts.align || 8;\n\t\t\tif(_align < 8) {\n\t\t\t\tthrow new Error(`invalid alignment: ${_align}, must be a pow2 and >= 8`);\n\t\t\t}\n\t\t\tconst top = this.initialTop(_align);\n\t\t\tconst resolvedEnd =\n\t\t\t\topts.end != null\n\t\t\t\t\t? Math.min(opts.end, this.buf.byteLength)\n\t\t\t\t\t: this.buf.byteLength;\n\n\t\t\tif(top >= resolvedEnd) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`insufficient address range (0x${this.start.toString(\n\t\t\t\t\t\t16,\n\t\t\t\t\t)} - 0x${resolvedEnd.toString(16)})`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.align = _align;\n\t\t\tthis.doCompact = opts.compact !== false;\n\t\t\tthis.doSplit = opts.split !== false;\n\t\t\tthis.minSplit = opts.minSplit || 16;\n\t\t\tthis.end = resolvedEnd;\n\t\t\tthis.top = top;\n\t\t\tthis._free = 0;\n\t\t\tthis._used = 0;\n\t\t}\n\t}\n\n\tstats(): Readonly<MemoryBufferStats> {\n\t\tconst listStats = (block: number) => {\n\t\t\tlet count = 0;\n\t\t\tlet size = 0;\n\t\t\twhile(block) {\n\t\t\t\tcount++;\n\t\t\t\tsize += this.blockSize(block);\n\t\t\t\tblock = this.blockNext(block);\n\n\t\t\t\tif(block > this.end) {\n\t\t\t\t\tconsole.error(`Trying to get stats for block past end of buffer: ${block} > ${this.end}`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { count, size };\n\t\t};\n\t\tconst free = listStats(this._free);\n\t\treturn {\n\t\t\tfree,\n\t\t\tused: listStats(this._used),\n\t\t\ttop: this.top,\n\t\t\tavailable: this.end - this.top + free.size,\n\t\t\ttotal: this.buf.byteLength,\n\t\t};\n\t}\n\n\tcallocAs<T extends Type>(type: T, num: number, fill = 0) {\n\t\tconst block = this.mallocAs(type, num);\n\t\tblock && block.fill(fill);\n\t\treturn block;\n\t}\n\n\tmallocAs<T extends Type>(type: T, num: number) {\n\t\tconst addr = this.malloc(num * SIZEOF[type]);\n\t\treturn addr ? typedArray(type, this.buf, addr, num) : undefined;\n\t}\n\n\tcalloc(bytes: number, fill = 0) {\n\t\tconst addr = this.malloc(bytes);\n\t\taddr && this.u8.fill(fill, addr, addr + bytes);\n\t\treturn addr;\n\t}\n\n\tmalloc(bytes: number) {\n\t\tif(bytes <= 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tlock(this.lock);\n\t\tconst paddedSize = align(bytes + SIZEOF_MEM_BLOCK, this.align);\n\t\tconst end = this.end;\n\t\tlet top = this.top;\n\t\tlet block = this._free;\n\t\tlet prev = 0;\n\t\twhile(block) {\n\t\t\tconst blockSize = this.blockSize(block);\n\t\t\tconst isTop = block + blockSize >= top;\n\t\t\tif(isTop || blockSize >= paddedSize) {\n\t\t\t\tlet result = this.mallocTop(\n\t\t\t\t\tblock,\n\t\t\t\t\tprev,\n\t\t\t\t\tblockSize,\n\t\t\t\t\tpaddedSize,\n\t\t\t\t\tisTop,\n\t\t\t\t);\n\n\t\t\t\tunlock(this.lock);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tprev = block;\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\t\tblock = top;\n\t\ttop = block + paddedSize;\n\t\tif(top <= end) {\n\t\t\tthis.initBlock(block, paddedSize, this._used);\n\t\t\tthis._used = block;\n\t\t\tthis.top = top;\n\t\t\tlet result = blockDataAddress(block);\n\t\t\tunlock(this.lock);\n\n\t\t\treturn result;\n\t\t}\n\t\tunlock(this.lock);\n\t\treturn 0;\n\t}\n\n\tprivate mallocTop(\n\t\tblock: number,\n\t\tprev: number,\n\t\tblockSize: number,\n\t\tpaddedSize: number,\n\t\tisTop: boolean,\n\t) {\n\t\tif(isTop && block + paddedSize > this.end) return 0;\n\t\tif(prev) {\n\t\t\tthis.unlinkBlock(prev, block);\n\t\t} else {\n\t\t\tthis._free = this.blockNext(block);\n\t\t}\n\t\tthis.setBlockNext(block, this._used);\n\t\tthis._used = block;\n\t\tif(isTop) {\n\t\t\tthis.top = block + this.setBlockSize(block, paddedSize);\n\t\t} else if(this.doSplit) {\n\t\t\tconst excess = blockSize - paddedSize;\n\t\t\texcess >= this.minSplit &&\n\t\t\tthis.splitBlock(block, paddedSize, excess);\n\t\t}\n\t\treturn blockDataAddress(block);\n\t}\n\n\trealloc(ptr: number, bytes: number) {\n\t\tif(bytes <= 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst oldAddr = blockSelfAddress(ptr);\n\t\tlet newAddr = 0;\n\t\tlet block = this._used;\n\t\tlet blockEnd = 0;\n\t\twhile(block) {\n\t\t\tif(block === oldAddr) {\n\t\t\t\t[newAddr, blockEnd] = this.reallocBlock(block, bytes);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\t\t// copy old block contents to new addr\n\t\tif(newAddr && newAddr !== oldAddr) {\n\t\t\tthis.u8.copyWithin(\n\t\t\t\tblockDataAddress(newAddr),\n\t\t\t\tblockDataAddress(oldAddr),\n\t\t\t\tblockEnd,\n\t\t\t);\n\t\t}\n\t\treturn blockDataAddress(newAddr);\n\t}\n\n\tprivate reallocBlock(block: number, bytes: number) {\n\t\tconst blockSize = this.blockSize(block);\n\t\tconst blockEnd = block + blockSize;\n\t\tconst isTop = blockEnd >= this.top;\n\t\tconst paddedSize = align(bytes + SIZEOF_MEM_BLOCK, this.align);\n\t\t// shrink & possibly split existing block\n\t\tif(paddedSize <= blockSize) {\n\t\t\tif(this.doSplit) {\n\t\t\t\tconst excess = blockSize - paddedSize;\n\t\t\t\tif(excess >= this.minSplit) {\n\t\t\t\t\tthis.splitBlock(block, paddedSize, excess);\n\t\t\t\t} else if(isTop) {\n\t\t\t\t\tthis.top = block + paddedSize;\n\t\t\t\t}\n\t\t\t} else if(isTop) {\n\t\t\t\tthis.top = block + paddedSize;\n\t\t\t}\n\t\t\treturn [block, blockEnd];\n\t\t}\n\t\t// try to enlarge block if current top\n\t\tif(isTop && block + paddedSize < this.end) {\n\t\t\tthis.top = block + this.setBlockSize(block, paddedSize);\n\t\t\treturn [block, blockEnd];\n\t\t}\n\t\t// fallback to free & malloc\n\t\tthis.free(block);\n\t\treturn [blockSelfAddress(this.malloc(bytes)), blockEnd];\n\t}\n\n\treallocArray<T extends TypedArray>(array: T, num: number): T | undefined {\n\t\tif(array.buffer !== this.buf) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst addr = this.realloc(\n\t\t\tarray.byteOffset,\n\t\t\tnum * array.BYTES_PER_ELEMENT,\n\t\t);\n\t\treturn addr\n\t\t\t? new (<any>array.constructor)(this.buf, addr, num)\n\t\t\t: undefined;\n\t}\n\n\tbytesFor(ptrOrArray: number | TypedArray): number | undefined {\n\t\tlet addr: number;\n\t\tif(typeof ptrOrArray !== 'number') {\n\t\t\tif(ptrOrArray.buffer !== this.buf) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\taddr = ptrOrArray.byteOffset;\n\t\t} else {\n\t\t\taddr = ptrOrArray;\n\t\t}\n\n\t\taddr = blockSelfAddress(addr);\n\t\tlet block = this._used;\n\t\twhile(block) {\n\t\t\tif(block === addr) {\n\t\t\t\treturn this.blockSize(addr) - SIZEOF_MEM_BLOCK;\n\t\t\t}\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\tlengthOf(ptrOrArray: number | TypedArray): number | undefined {\n\t\tlet bytes = this.bytesFor(ptrOrArray);\n\t\tif(bytes) {\n\t\t\treturn bytes / this.u32.BYTES_PER_ELEMENT;\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tfree(ptrOrArray: number | TypedArray) {\n\t\tlet addr: number;\n\t\tif(typeof ptrOrArray !== 'number') {\n\t\t\tif(ptrOrArray.buffer !== this.buf) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\taddr = ptrOrArray.byteOffset;\n\t\t} else {\n\t\t\taddr = ptrOrArray;\n\t\t}\n\t\tlock(this.lock);\n\t\taddr = blockSelfAddress(addr);\n\t\tlet block = this._used;\n\t\tlet prev = 0;\n\t\twhile(block) {\n\t\t\tif(block === addr) {\n\t\t\t\tif(prev) {\n\t\t\t\t\tthis.unlinkBlock(prev, block);\n\t\t\t\t} else {\n\t\t\t\t\tthis._used = this.blockNext(block);\n\t\t\t\t}\n\t\t\t\tthis.insert(block);\n\t\t\t\tthis.doCompact && this.compact();\n\n\t\t\t\tunlock(this.lock);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tprev = block;\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\n\t\tunlock(this.lock);\n\t\treturn false;\n\t}\n\n\tfreeAll() {\n\t\tthis._free = 0;\n\t\tthis._used = 0;\n\t\tthis.top = this.initialTop();\n\t}\n\n\trelease() {\n\t\tdelete (<any> this).u8;\n\t\tdelete (<any> this).u32;\n\t\tdelete (<any> this).state;\n\t\tdelete (<any> this).buf;\n\t\treturn true;\n\t}\n\n\tprotected get align() {\n\t\treturn <Pow2> this.state[STATE_ALIGN];\n\t}\n\n\tprotected set align(x: Pow2) {\n\t\tthis.state[STATE_ALIGN] = x;\n\t}\n\n\tget end() {\n\t\treturn this.state[STATE_END];\n\t}\n\n\tprotected set end(x: number) {\n\t\tthis.state[STATE_END] = x;\n\t}\n\n\tget top() {\n\t\treturn Atomics.load(this.state, STATE_TOP);\n\t}\n\n\tprotected set top(x: number) {\n\t\tAtomics.store(this.state, STATE_TOP, x);\n\t}\n\n\t// No live allocations. O(1) (the head of the used list, not a walk like stats()), so it is cheap to poll each\n\t// frame when checking whether a spare buffer is still available.\n\tget isEmpty(): boolean {\n\t\treturn this._used === 0;\n\t}\n\n\tprotected get _free() {\n\t\treturn Atomics.load(this.state, STATE_FREE);\n\t}\n\n\tprotected set _free(block: number) {\n\t\tAtomics.store(this.state, STATE_FREE, block);\n\t}\n\n\tprotected get _used() {\n\t\treturn Atomics.load(this.state, STATE_USED);\n\t}\n\n\tprotected set _used(block: number) {\n\t\tAtomics.store(this.state, STATE_USED, block);\n\t}\n\n\tprotected get doCompact() {\n\t\treturn !!(this.state[STATE_FLAGS] & MASK_COMPACT);\n\t}\n\n\tprotected set doCompact(flag: boolean) {\n\t\tflag\n\t\t\t? (this.state[STATE_FLAGS] |= 1 << (MASK_COMPACT - 1))\n\t\t\t: (this.state[STATE_FLAGS] &= ~MASK_COMPACT);\n\t}\n\n\tprotected get doSplit() {\n\t\treturn !!(this.state[STATE_FLAGS] & MASK_SPLIT);\n\t}\n\n\tprotected set doSplit(flag: boolean) {\n\t\tflag\n\t\t\t? (this.state[STATE_FLAGS] |= 1 << (MASK_SPLIT - 1))\n\t\t\t: (this.state[STATE_FLAGS] &= ~MASK_SPLIT);\n\t}\n\n\tprotected get minSplit() {\n\t\treturn this.state[STATE_MIN_SPLIT];\n\t}\n\n\tprotected set minSplit(x: number) {\n\t\tif(x <= SIZEOF_MEM_BLOCK) {\n\t\t\tthrow new Error(`illegal min split threshold: ${x}, require at least ${\n\t\t\t\tSIZEOF_MEM_BLOCK + 1\n\t\t\t}`);\n\t\t}\n\t\tthis.state[STATE_MIN_SPLIT] = x;\n\t}\n\n\tprotected blockSize(block: number) {\n\t\treturn Atomics.load(this.u32, (block >> 2) + MEM_BLOCK_SIZE);\n\t}\n\n\t/**\n\t * Sets & returns given block size.\n\t *\n\t * @param block -\n\t * @param size -\n\t */\n\tprotected setBlockSize(block: number, size: number) {\n\t\tAtomics.store(this.u32, (block >> 2) + MEM_BLOCK_SIZE, size);\n\t\treturn size;\n\t}\n\n\tprotected blockNext(block: number) {\n\t\treturn Atomics.load(this.u32, (block >> 2) + MEM_BLOCK_NEXT);\n\t}\n\n\t/**\n\t * Sets block next pointer to `next`. Use zero to indicate list end.\n\t *\n\t * @param block -\n\t */\n\tprotected setBlockNext(block: number, next: number) {\n\t\tAtomics.store(this.u32, (block >> 2) + MEM_BLOCK_NEXT, next);\n\t}\n\n\t/**\n\t * Initializes block header with given `size` and `next` pointer. Returns `block`.\n\t *\n\t * @param block -\n\t * @param size -\n\t * @param next -\n\t */\n\tprotected initBlock(block: number, size: number, next: number) {\n\t\tconst idx = block >>> 2;\n\t\tAtomics.store(this.u32, idx + MEM_BLOCK_SIZE, size);\n\t\tAtomics.store(this.u32, idx + MEM_BLOCK_NEXT, next);\n\t\treturn block;\n\t}\n\n\tprotected unlinkBlock(prev: number, block: number) {\n\t\tthis.setBlockNext(prev, this.blockNext(block));\n\t}\n\n\tprotected splitBlock(block: number, blockSize: number, excess: number) {\n\t\tthis.insert(\n\t\t\tthis.initBlock(\n\t\t\t\tblock + this.setBlockSize(block, blockSize),\n\t\t\t\texcess,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.doCompact && this.compact();\n\t}\n\n\tprotected initialTop(_align = this.align) {\n\t\treturn (\n\t\t\talign(this.start + SIZEOF_STATE + SIZEOF_MEM_BLOCK, _align) -\n\t\t\tSIZEOF_MEM_BLOCK\n\t\t);\n\t}\n\n\t/**\n\t * Traverses free list and attempts to recursively merge blocks\n\t * occupying consecutive memory regions. Returns true if any blocks\n\t * have been merged. Only called if `compact` option is enabled.\n\t */\n\tprotected compact() {\n\t\tlet block = this._free;\n\t\tlet prev = 0;\n\t\tlet scan = 0;\n\t\tlet scanPrev: number;\n\t\tlet res = false;\n\t\twhile(block) {\n\t\t\tscanPrev = block;\n\t\t\tscan = this.blockNext(block);\n\t\t\twhile(scan && scanPrev + this.blockSize(scanPrev) === scan) {\n\t\t\t\t// console.log(\"merge:\", scan.addr, scan.size);\n\t\t\t\tscanPrev = scan;\n\t\t\t\tscan = this.blockNext(scan);\n\t\t\t}\n\t\t\tif(scanPrev !== block) {\n\t\t\t\tconst newSize = scanPrev - block + this.blockSize(scanPrev);\n\t\t\t\t// console.log(\"merged size:\", newSize);\n\t\t\t\tthis.setBlockSize(block, newSize);\n\t\t\t\tconst next = this.blockNext(scanPrev);\n\t\t\t\tlet tmp = this.blockNext(block);\n\t\t\t\twhile(tmp && tmp !== next) {\n\t\t\t\t\t// console.log(\"release:\", tmp.addr);\n\t\t\t\t\tconst tn = this.blockNext(tmp);\n\t\t\t\t\tthis.setBlockNext(tmp, 0);\n\t\t\t\t\ttmp = tn;\n\t\t\t\t}\n\t\t\t\tthis.setBlockNext(block, next);\n\t\t\t\tres = true;\n\t\t\t}\n\t\t\t// re-adjust top if poss\n\t\t\tif(block + this.blockSize(block) >= this.top) {\n\t\t\t\tthis.top = block;\n\t\t\t\tprev\n\t\t\t\t\t? this.unlinkBlock(prev, block)\n\t\t\t\t\t: (this._free = this.blockNext(block));\n\t\t\t}\n\t\t\tprev = block;\n\t\t\tblock = this.blockNext(block);\n\t\t}\n\t\treturn res;\n\t}\n\n\t/**\n\t * Inserts given block into list of free blocks, sorted by address.\n\t *\n\t * @param block -\n\t */\n\tprotected insert(block: number) {\n\t\tlet ptr = this._free;\n\t\tlet prev = 0;\n\t\twhile(ptr) {\n\t\t\tif(block <= ptr) break;\n\t\t\tprev = ptr;\n\t\t\tptr = this.blockNext(ptr);\n\t\t}\n\t\tif(prev) {\n\t\t\tthis.setBlockNext(prev, block);\n\t\t} else {\n\t\t\tthis._free = block;\n\t\t}\n\t\tthis.setBlockNext(block, ptr);\n\t}\n}\n\n/**\n * Returns a block's data address, based on given alignment.\n *\n * @param blockAddress -\n */\nfunction blockDataAddress(blockAddress: number) {\n\treturn blockAddress > 0 ? blockAddress + SIZEOF_MEM_BLOCK : 0;\n}\n\n/**\n * Returns block start address for given data address and alignment.\n *\n * @param dataAddress -\n */\nfunction blockSelfAddress(dataAddress: number) {\n\treturn dataAddress > 0 ? dataAddress - SIZEOF_MEM_BLOCK : 0;\n}\n\nfunction align(addr: number, size: number) {\n\tsize--;\n\treturn addr + size & ~size;\n}\n\n// Bytes reserved before usable heap space (allocator state) and the per-allocation block header. Exported so callers can\n// size an allocation against what a single buffer can actually hold.\nexport { SIZEOF_STATE, SIZEOF_MEM_BLOCK };\n\ntype Type = 'u8' | 'u8c' | 'i8' | 'u16' | 'i16' | 'u32' | 'i32' | 'f32' | 'f64';\n\ninterface MemoryBufferConfig {\n\t/**\n\t * Backing ArrayBuffer (or SharedArrayBuffer). If not given, a new\n\t * one will be created with given `size`.\n\t */\n\tbuf: ArrayBufferLike\n\t/**\n\t * Byte size for newly created ArrayBuffers (if `buf` is not given).\n\t *\n\t * @defaultValue 0x1000 (4KB)\n\t */\n\tsize: number\n\t/**\n\t * Anchor index (byte address) inside the array buffer. The MemPool\n\t * stores its internal state from the given address and heap space\n\t * starts at least 32 bytes later (depending on chosen `align`\n\t * value). Unlike allocator state variables, `start`` cannot be\n\t * saved inside the array buffer itself. If the ArrayBuffer is\n\t * passed to other consumers they must use the same start value.\n\t * MUST be multiple of 4.\n\t *\n\t * @defaultValue 0\n\t */\n\tstart: number\n\t/**\n\t * Byte address (+1) of the end of the memory region managed by the\n\t * {@link MemPool}.\n\t *\n\t * @defaultValue end of the backing ArrayBuffer\n\t */\n\tend: number\n\t/**\n\t * Number of bytes to align memory blocks to. MUST be a power of 2\n\t * and >= 8. Use 16 if the pool is being used for allocating memory\n\t * used in SIMD operations.\n\t *\n\t * @defaultValue 8\n\t */\n\talign: Pow2\n\t/**\n\t * Flag to configure memory block compaction. If true,\n\t * adjoining free blocks (in terms of address space) will be merged\n\t * to minimize fragementation.\n\t *\n\t * @defaultValue true\n\t */\n\tcompact: boolean\n\t/**\n\t * Flag to configure memory block splitting. If true, and when the\n\t * allocator is re-using a previously freed block larger than the\n\t * requested size, the block will be split to minimize wasted/unused\n\t * memory. The splitting behavior can further customized via the\n\t * `minSplit` option.\n\t *\n\t * @defaultValue true\n\t */\n\tsplit: boolean\n\t/**\n\t * Only used if `split` behavior is enabled. Defines min number of\n\t * excess bytes available in a block for memory block splitting to\n\t * occur.\n\t *\n\t * @defaultValue 16, MUST be > 8\n\t */\n\tminSplit: number\n\t/**\n\t * Only needed when sharing the underlying ArrayBuffer. If true, the\n\t * {@link MemPool} constructor will NOT initialize its internal state and\n\t * assume the underlying ArrayBuffer has already been initialized by\n\t * another {@link MemPool} instance. If this option is used, `buf` MUST be\n\t * given.\n\t *\n\t * @defaultValue false\n\t */\n\tskipInitialization: boolean\n}\ninterface MemoryBufferStats {\n\t/**\n\t * Free block stats.\n\t */\n\tfree: { count: number, size: number }\n\t/**\n\t * Used block stats.\n\t */\n\tused: { count: number, size: number }\n\t/**\n\t * Current top address.\n\t */\n\ttop: number\n\t/**\n\t * Bytes available\n\t */\n\tavailable: number\n\t/**\n\t * Total pool size.\n\t */\n\ttotal: number\n}"],"mappings":"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"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import AllocatedMemory, { type SharedAllocatedMemory } from './allocated-memory';
|
|
2
|
+
import MemoryBuffer from './memory-buffer';
|
|
3
3
|
export default class MemoryHeap {
|
|
4
4
|
buffers: Array<MemoryBuffer>;
|
|
5
5
|
private onGrowBufferHandlers;
|
|
6
6
|
isClone: boolean;
|
|
7
7
|
private memory;
|
|
8
8
|
get bufferSize(): number;
|
|
9
|
+
get maxAllocationLength(): number;
|
|
9
10
|
constructor(config?: MemoryHeapConfig | MemoryHeapMemory);
|
|
10
11
|
addSharedBuffer(data: GrowBufferData): void;
|
|
11
12
|
private growBuffer;
|
|
12
13
|
private createBuffer;
|
|
13
14
|
addOnGrowBufferHandlers(handler: OnGrowBuffer): void;
|
|
15
|
+
ensureSpareBuffer(): boolean;
|
|
14
16
|
allocUI32(count: number): AllocatedMemory;
|
|
15
17
|
getSharedAlloc(shared: SharedAllocatedMemory): AllocatedMemory | undefined;
|
|
16
18
|
get currentUsed(): number;
|
package/dist/memory-heap.js
CHANGED
|
@@ -1,116 +1,106 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
class
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return this.totalAllocated - this.buffers.reduce((e, r) => e + r.stats().available, 0);
|
|
103
|
-
}
|
|
104
|
-
get totalAllocated() {
|
|
105
|
-
return this.buffers[0].buf.byteLength * this.buffers.length;
|
|
106
|
-
}
|
|
107
|
-
getSharedMemory() {
|
|
108
|
-
return {
|
|
109
|
-
buffers: this.buffers.map((e) => e.buf)
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
export {
|
|
114
|
-
A as default
|
|
1
|
+
import { MAX_BYTE_OFFSET_LENGTH as e, MAX_POSITION_LENGTH as t } from "./utils/pointer.js";
|
|
2
|
+
import n from "./allocated-memory.js";
|
|
3
|
+
import r from "./memory-buffer.js";
|
|
4
|
+
//#region src/memory-heap.ts
|
|
5
|
+
var i = e, a = 0, o = 1, s = 2, c = class {
|
|
6
|
+
buffers;
|
|
7
|
+
onGrowBufferHandlers = [];
|
|
8
|
+
isClone;
|
|
9
|
+
memory;
|
|
10
|
+
get bufferSize() {
|
|
11
|
+
return this.memory.data[a];
|
|
12
|
+
}
|
|
13
|
+
get maxAllocationLength() {
|
|
14
|
+
return Math.floor((this.bufferSize - 32 - 8) / Uint32Array.BYTES_PER_ELEMENT);
|
|
15
|
+
}
|
|
16
|
+
constructor(t) {
|
|
17
|
+
if (t && "buffers" in t) this.buffers = t.buffers.map((e) => new r({
|
|
18
|
+
buf: e,
|
|
19
|
+
skipInitialization: !0
|
|
20
|
+
})), this.memory = new n(this, {
|
|
21
|
+
bufferPosition: 0,
|
|
22
|
+
bufferByteOffset: 40
|
|
23
|
+
}), this.isClone = !0;
|
|
24
|
+
else {
|
|
25
|
+
"SharedArrayBuffer" in globalThis || console.warn("SharedArrayBuffer is not working: falling back to ArrayBuffer");
|
|
26
|
+
let r = t?.bufferSize ?? i;
|
|
27
|
+
if (r > e) throw Error(`Buffer size ${r} is greater than max ${e} that we can reference with pointers`);
|
|
28
|
+
let c = this.createBuffer(r);
|
|
29
|
+
this.buffers = [c];
|
|
30
|
+
let l = c.callocAs("u32", 3);
|
|
31
|
+
if (l) this.memory = new n(this, {
|
|
32
|
+
bufferPosition: 0,
|
|
33
|
+
bufferByteOffset: l.byteOffset
|
|
34
|
+
});
|
|
35
|
+
else throw Error("Failed to initialize first byte from buffer");
|
|
36
|
+
this.memory.data[a] = r, this.memory.data[o] = 1, this.memory.data[s] = t?.autoGrowSize ?? 100, this.isClone = !1;
|
|
37
|
+
for (let e = 1; e < (t?.initialBuffers ?? 1); e++) this.buffers.push(this.createBuffer(r));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
addSharedBuffer(e) {
|
|
41
|
+
this.buffers[e.bufferPosition] = new r({
|
|
42
|
+
buf: e.buffer,
|
|
43
|
+
skipInitialization: !0
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
growBuffer() {
|
|
47
|
+
let e = this.createBuffer(), t = Atomics.add(this.memory.data, o, 1);
|
|
48
|
+
return this.buffers[t] = e, this.onGrowBufferHandlers.forEach((n) => n({
|
|
49
|
+
bufferPosition: t,
|
|
50
|
+
buffer: e.buf
|
|
51
|
+
})), e;
|
|
52
|
+
}
|
|
53
|
+
createBuffer(e) {
|
|
54
|
+
let t = e ?? this.bufferSize, n;
|
|
55
|
+
return n = "SharedArrayBuffer" in globalThis ? new SharedArrayBuffer(t) : new ArrayBuffer(t), new r({
|
|
56
|
+
buf: n,
|
|
57
|
+
compact: !1,
|
|
58
|
+
split: !1
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
addOnGrowBufferHandlers(e) {
|
|
62
|
+
this.onGrowBufferHandlers.push(e);
|
|
63
|
+
}
|
|
64
|
+
ensureSpareBuffer() {
|
|
65
|
+
for (let e = 0; e < this.buffers.length; e++) {
|
|
66
|
+
let t = this.buffers[e];
|
|
67
|
+
if (t && t.isEmpty) return !1;
|
|
68
|
+
}
|
|
69
|
+
return this.growBuffer(), !0;
|
|
70
|
+
}
|
|
71
|
+
allocUI32(e) {
|
|
72
|
+
e = Math.ceil(e);
|
|
73
|
+
for (let t = 0; t < this.buffers.length; t++) {
|
|
74
|
+
let r = this.buffers[t];
|
|
75
|
+
if (!r) continue;
|
|
76
|
+
let i = r.callocAs("u32", e);
|
|
77
|
+
if (i) return t === this.buffers.length - 1 && Atomics.load(this.memory.data, o) === this.buffers.length && this.memory.data[s] < 100 && this.memory.data[s] > 0 && r.top / r.end > this.memory.data[s] / 100 && this.growBuffer(), new n(this, {
|
|
78
|
+
data: i,
|
|
79
|
+
buffer: r
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (this.buffers.length >= t) throw Error(`Can't initialize a new buffer since it would have a position greater than the max of ${t}`);
|
|
83
|
+
let r = this.growBuffer(), i = r.callocAs("u32", e);
|
|
84
|
+
if (i) return new n(this, {
|
|
85
|
+
data: i,
|
|
86
|
+
buffer: r
|
|
87
|
+
});
|
|
88
|
+
throw Error(`Unable to allocate ${e} numbers even after adding a new buffer`);
|
|
89
|
+
}
|
|
90
|
+
getSharedAlloc(e) {
|
|
91
|
+
if (this.buffers[e.bufferPosition] !== void 0) return new n(this, e);
|
|
92
|
+
}
|
|
93
|
+
get currentUsed() {
|
|
94
|
+
return this.totalAllocated - this.buffers.reduce((e, t) => e + t.stats().available, 0);
|
|
95
|
+
}
|
|
96
|
+
get totalAllocated() {
|
|
97
|
+
return this.buffers[0].buf.byteLength * this.buffers.length;
|
|
98
|
+
}
|
|
99
|
+
getSharedMemory() {
|
|
100
|
+
return { buffers: this.buffers.map((e) => e.buf) };
|
|
101
|
+
}
|
|
115
102
|
};
|
|
116
|
-
//#
|
|
103
|
+
//#endregion
|
|
104
|
+
export { c as default };
|
|
105
|
+
|
|
106
|
+
//# sourceMappingURL=memory-heap.js.map
|
package/dist/memory-heap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-heap.js","sources":["../src/memory-heap.ts"],"sourcesContent":["import AllocatedMemory, { type SharedAllocatedMemory } from './allocated-memory';\nimport { MAX_BYTE_OFFSET_LENGTH, MAX_POSITION_LENGTH } from './utils/pointer';\nimport MemoryBuffer from './memory-buffer';\n\nconst DEFAULT_BUFFER_SIZE = 8_192;\nconst BUFFER_SIZE_INDEX = 0;\nconst BUFFER_COUNT_INDEX = 1;\nconst BUFFER_AUTO_GROW_INDEX = 2;\nexport default class MemoryHeap {\n\tbuffers: Array<MemoryBuffer>;\n\tprivate onGrowBufferHandlers: Array<OnGrowBuffer> = [];\n\tisClone: boolean;\n\tprivate memory: AllocatedMemory;\n\n\tget bufferSize() {\n\t\treturn this.memory.data[BUFFER_SIZE_INDEX];\n\t}\n\n\tconstructor(config?: MemoryHeapConfig | MemoryHeapMemory) {\n\t\tif(config && 'buffers' in config) {\n\t\t\tthis.buffers = config.buffers.map(buffer => {\n\t\t\t\treturn new MemoryBuffer({\n\t\t\t\t\tbuf: buffer,\n\t\t\t\t\tskipInitialization: true\n\t\t\t\t});\n\t\t\t});\n\n\t\t\t// TODO: This should be programic instead of hoping the first allocation is always byte 40\n\t\t\tthis.memory = new AllocatedMemory(this, {\n\t\t\t\tbufferPosition: 0,\n\t\t\t\tbufferByteOffset: 40\n\t\t\t});\n\t\t\tthis.isClone = true;\n\t\t} else {\n\t\t\tif(!('SharedArrayBuffer' in globalThis)) {\n\t\t\t\tconsole.warn('SharedArrayBuffer is not working: falling back to ArrayBuffer');\n\t\t\t}\n\n\t\t\tconst bufferSize = config?.bufferSize ?? DEFAULT_BUFFER_SIZE;\n\t\t\tif(bufferSize > MAX_BYTE_OFFSET_LENGTH) {\n\t\t\t\tthrow new Error(`Buffer size ${bufferSize} is greater than max ${MAX_BYTE_OFFSET_LENGTH} that we can reference with pointers`);\n\t\t\t}\n\t\t\t\n\t\t\tlet startBuffer = this.createBuffer(bufferSize);\n\t\t\tthis.buffers = [\n\t\t\t\tstartBuffer\n\t\t\t];\n\t\t\tconst data = startBuffer.callocAs('u32', 3);\n\t\t\tif(data) {\n\t\t\t\tthis.memory = new AllocatedMemory(this, {\n\t\t\t\t\tbufferPosition: 0,\n\t\t\t\t\tbufferByteOffset: data.byteOffset\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthrow new Error('Failed to initialize first byte from buffer');\n\t\t\t}\n\t\t\tthis.memory.data[BUFFER_SIZE_INDEX] = bufferSize;\n\t\t\tthis.memory.data[BUFFER_COUNT_INDEX] = 1;\n\t\t\tthis.memory.data[BUFFER_AUTO_GROW_INDEX] = config?.autoGrowSize ?? 100;\n\t\t\tthis.isClone = false;\n\n\t\t\tfor(let i = 1; i < (config?.initialBuffers ?? 1); i++) {\n\t\t\t\tthis.buffers.push(this.createBuffer(bufferSize));\n\t\t\t}\n\t\t}\n\t}\n\n\taddSharedBuffer(data: GrowBufferData) {\n\t\tthis.buffers[data.bufferPosition] = new MemoryBuffer({\n\t\t\tbuf: data.buffer,\n\t\t\tskipInitialization: true\n\t\t});\n\t}\n\n\tprivate growBuffer() {\n\t\tconst buffer = this.createBuffer();\n\t\tlet nextBufferPosition = Atomics.add(this.memory.data, BUFFER_COUNT_INDEX, 1);\n\t\t// Setting index set by internal Atomic count so we can create new buffers from multiple threads and keep position consistent\n\t\tthis.buffers[nextBufferPosition] = buffer;\n\t\tthis.onGrowBufferHandlers.forEach(handler => handler({\n\t\t\tbufferPosition: nextBufferPosition,\n\t\t\tbuffer: buffer.buf as SharedArrayBuffer\n\t\t}));\n\n\t\treturn buffer;\n\t}\n\tprivate createBuffer(bufferSize?: number): MemoryBuffer {\n\t\tconst usedBufferSize = bufferSize ?? this.bufferSize;\n\t\tlet buf: ArrayBuffer | SharedArrayBuffer;\n\t\tif('SharedArrayBuffer' in globalThis) {\n\t\t\tbuf = new SharedArrayBuffer(usedBufferSize);\n\t\t} else {\n\t\t\tbuf = new ArrayBuffer(usedBufferSize);\n\t\t}\n\n\t\treturn new MemoryBuffer({\n\t\t\tbuf,\n\n\t\t\t// We can't use this unless we can 100% guarantee that every thread will stop using memory the instant it is freed\n\t\t\t// ex: Allocate 16 bytes. Thread A frees that allocation and then allocates 12 bytes and 4 bytes, but Thread B is mid-execution on the old allocation can changes the internal state of the 4-byte allocation breaking everything\n\t\t\t// After the internal state is wrong MemoryBuffer will loose track of which blocks are where and how big they are\n\t\t\tcompact: false,\n\t\t\tsplit: false\n\t\t});\n\t}\n\n\taddOnGrowBufferHandlers(handler: OnGrowBuffer) {\n\t\tthis.onGrowBufferHandlers.push(handler);\n\t}\n\n\tallocUI32(count: number): AllocatedMemory {\n\t\tcount = Math.ceil(count);\n\t\tfor(let i = 0; i < this.buffers.length; i++) {\n\t\t\tconst buffer = this.buffers[i];\n\t\t\t// Should just mean we haven't synced this buffer from another thread yet\n\t\t\tif(!buffer) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Should be fine to initialize all values as 0s since unsigned/signed ints and floats all store 0 as all 0s\n\t\t\tconst data = buffer.callocAs('u32', count);\n\t\t\tif(data) {\n\t\t\t\t// Auto grow when nearly full when we need buffer to already be sync'd between threads BEFORE we try to use it\n\t\t\t\tif(i === (this.buffers.length - 1) && Atomics.load(this.memory.data, BUFFER_COUNT_INDEX) === this.buffers.length && this.memory.data[BUFFER_AUTO_GROW_INDEX] < 100 && this.memory.data[BUFFER_AUTO_GROW_INDEX] > 0) {\n\t\t\t\t\tconst percentFull = buffer.top / buffer.end;\n\t\t\t\t\tif(percentFull > (this.memory.data[BUFFER_AUTO_GROW_INDEX] / 100)) {\n\t\t\t\t\t\tthis.growBuffer();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn new AllocatedMemory(this, {\n\t\t\t\t\tdata,\n\t\t\t\t\tbuffer\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif(this.buffers.length >= MAX_POSITION_LENGTH) {\n\t\t\tthrow new Error(`Can't initialize a new buffer since it would have a position greater than the max of ${MAX_POSITION_LENGTH}`);\n\t\t}\n\n\t\t// If we get here we need to grow another buffer to continue allocating new memory\n\t\tlet buffer = this.growBuffer();\n\t\tconst data = buffer.callocAs('u32', count);\n\t\tif(data) {\n\t\t\treturn new AllocatedMemory(this, {\n\t\t\t\tdata,\n\t\t\t\tbuffer\n\t\t\t});\n\t\t} else {\n\t\t\tthrow new Error(`Unable to allocate ${count} numbers even after adding a new buffer`);\n\t\t}\n\t}\n\n\tgetSharedAlloc(shared: SharedAllocatedMemory): AllocatedMemory | undefined {\n\t\t// Should just mean it hasn't synced to this thread yet\n\t\tif(this.buffers[shared.bufferPosition] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn new AllocatedMemory(this, shared);\n\t}\n\n\tget currentUsed() {\n\t\treturn this.totalAllocated - this.buffers.reduce((total, memPool) => total + memPool.stats().available, 0);\n\t}\n\tget totalAllocated() {\n\t\treturn this.buffers[0].buf.byteLength * this.buffers.length;\n\t}\n\n\tgetSharedMemory(): MemoryHeapMemory {\n\t\treturn {\n\t\t\tbuffers: this.buffers.map(buffer => buffer.buf as SharedArrayBuffer)\n\t\t};\n\t}\n}\n\ntype OnGrowBuffer = (newBuffer: GrowBufferData) => void;\ninterface GrowBufferData {\n\tbufferPosition: number\n\tbuffer: SharedArrayBuffer\n}\n\ninterface MemoryHeapConfig {\n\tbufferSize?: number\n\tinitialBuffers?: number\n\tautoGrowSize?: number\n}\ninterface MemoryHeapMemory {\n\tbuffers: Array<SharedArrayBuffer>\n}\n\nexport type { MemoryHeapConfig, MemoryHeapMemory, GrowBufferData };"],"names":["DEFAULT_BUFFER_SIZE","BUFFER_SIZE_INDEX","BUFFER_COUNT_INDEX","BUFFER_AUTO_GROW_INDEX","MemoryHeap","config","buffer","MemoryBuffer","AllocatedMemory","bufferSize","MAX_BYTE_OFFSET_LENGTH","startBuffer","data","i","nextBufferPosition","handler","usedBufferSize","buf","count","MAX_POSITION_LENGTH","shared","total","memPool"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory-heap.js","names":[],"sources":["../src/memory-heap.ts"],"sourcesContent":["import AllocatedMemory, { type SharedAllocatedMemory } from './allocated-memory';\nimport { MAX_BYTE_OFFSET_LENGTH, MAX_POSITION_LENGTH } from './utils/pointer';\nimport MemoryBuffer, { SIZEOF_MEM_BLOCK, SIZEOF_STATE } from './memory-buffer';\n\nconst DEFAULT_BUFFER_SIZE = MAX_BYTE_OFFSET_LENGTH;\nconst BUFFER_SIZE_INDEX = 0;\nconst BUFFER_COUNT_INDEX = 1;\nconst BUFFER_AUTO_GROW_INDEX = 2;\nexport default class MemoryHeap {\n\tbuffers: Array<MemoryBuffer>;\n\tprivate onGrowBufferHandlers: Array<OnGrowBuffer> = [];\n\tisClone: boolean;\n\tprivate memory: AllocatedMemory;\n\n\tget bufferSize() {\n\t\treturn this.memory.data[BUFFER_SIZE_INDEX];\n\t}\n\n\t// Largest u32 count a single fresh buffer can hand out in one allocation: the buffer minus the allocator state and the\n\t// block header. A structure that grows in segments must keep each segment within this or the allocation can never fit.\n\tget maxAllocationLength() {\n\t\treturn Math.floor((this.bufferSize - SIZEOF_STATE - SIZEOF_MEM_BLOCK) / Uint32Array.BYTES_PER_ELEMENT);\n\t}\n\n\tconstructor(config?: MemoryHeapConfig | MemoryHeapMemory) {\n\t\tif(config && 'buffers' in config) {\n\t\t\tthis.buffers = config.buffers.map(buffer => {\n\t\t\t\treturn new MemoryBuffer({\n\t\t\t\t\tbuf: buffer,\n\t\t\t\t\tskipInitialization: true,\n\t\t\t\t});\n\t\t\t});\n\n\t\t\t// TODO: This should be programic instead of hoping the first allocation is always byte 40\n\t\t\tthis.memory = new AllocatedMemory(this, {\n\t\t\t\tbufferPosition: 0,\n\t\t\t\tbufferByteOffset: 40,\n\t\t\t});\n\t\t\tthis.isClone = true;\n\t\t} else {\n\t\t\tif(!('SharedArrayBuffer' in globalThis)) {\n\t\t\t\tconsole.warn('SharedArrayBuffer is not working: falling back to ArrayBuffer');\n\t\t\t}\n\n\t\t\tconst bufferSize = config?.bufferSize ?? DEFAULT_BUFFER_SIZE;\n\t\t\tif(bufferSize > MAX_BYTE_OFFSET_LENGTH) {\n\t\t\t\tthrow new Error(`Buffer size ${bufferSize} is greater than max ${MAX_BYTE_OFFSET_LENGTH} that we can reference with pointers`);\n\t\t\t}\n\t\t\t\n\t\t\tlet startBuffer = this.createBuffer(bufferSize);\n\t\t\tthis.buffers = [\n\t\t\t\tstartBuffer,\n\t\t\t];\n\t\t\tconst data = startBuffer.callocAs('u32', 3);\n\t\t\tif(data) {\n\t\t\t\tthis.memory = new AllocatedMemory(this, {\n\t\t\t\t\tbufferPosition: 0,\n\t\t\t\t\tbufferByteOffset: data.byteOffset,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthrow new Error('Failed to initialize first byte from buffer');\n\t\t\t}\n\t\t\tthis.memory.data[BUFFER_SIZE_INDEX] = bufferSize;\n\t\t\tthis.memory.data[BUFFER_COUNT_INDEX] = 1;\n\t\t\tthis.memory.data[BUFFER_AUTO_GROW_INDEX] = config?.autoGrowSize ?? 100;\n\t\t\tthis.isClone = false;\n\n\t\t\tfor(let i = 1; i < (config?.initialBuffers ?? 1); i++) {\n\t\t\t\tthis.buffers.push(this.createBuffer(bufferSize));\n\t\t\t}\n\t\t}\n\t}\n\n\taddSharedBuffer(data: GrowBufferData) {\n\t\tthis.buffers[data.bufferPosition] = new MemoryBuffer({\n\t\t\tbuf: data.buffer,\n\t\t\tskipInitialization: true,\n\t\t});\n\t}\n\n\tprivate growBuffer() {\n\t\tconst buffer = this.createBuffer();\n\t\tlet nextBufferPosition = Atomics.add(this.memory.data, BUFFER_COUNT_INDEX, 1);\n\t\t// Setting index set by internal Atomic count so we can create new buffers from multiple threads and keep position consistent\n\t\tthis.buffers[nextBufferPosition] = buffer;\n\t\tthis.onGrowBufferHandlers.forEach(handler => handler({\n\t\t\tbufferPosition: nextBufferPosition,\n\t\t\tbuffer: buffer.buf as SharedArrayBuffer,\n\t\t}));\n\n\t\treturn buffer;\n\t}\n\tprivate createBuffer(bufferSize?: number): MemoryBuffer {\n\t\tconst usedBufferSize = bufferSize ?? this.bufferSize;\n\t\tlet buf: ArrayBuffer | SharedArrayBuffer;\n\t\tif('SharedArrayBuffer' in globalThis) {\n\t\t\tbuf = new SharedArrayBuffer(usedBufferSize);\n\t\t} else {\n\t\t\tbuf = new ArrayBuffer(usedBufferSize);\n\t\t}\n\n\t\treturn new MemoryBuffer({\n\t\t\tbuf,\n\n\t\t\t// We can't use this unless we can 100% guarantee that every thread will stop using memory the instant it is freed\n\t\t\t// ex: Allocate 16 bytes. Thread A frees that allocation and then allocates 12 bytes and 4 bytes, but Thread B is mid-execution\n\t\t\t// on the old allocation can changes the internal state of the 4-byte allocation breaking everything\n\t\t\t// After the internal state is wrong MemoryBuffer will loose track of which blocks are where and how big they are\n\t\t\tcompact: false,\n\t\t\tsplit: false,\n\t\t});\n\t}\n\n\taddOnGrowBufferHandlers(handler: OnGrowBuffer) {\n\t\tthis.onGrowBufferHandlers.push(handler);\n\t}\n\n\t// Guarantees at least one completely-empty buffer exists and (via the grow handlers) has been fanned out to every\n\t// thread. Call this on the owning thread before dispatching work that allocates on another thread (a worker): that\n\t// allocation then lands in a buffer everyone already holds instead of forcing growBuffer on the worker, which would\n\t// create a buffer only the worker can see and leave every other thread unable to resolve pointers into it. Returns\n\t// true if it had to grow one.\n\tensureSpareBuffer(): boolean {\n\t\tfor(let i = 0; i < this.buffers.length; i++) {\n\t\t\tconst buffer = this.buffers[i];\n\t\t\tif(buffer && buffer.isEmpty) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tthis.growBuffer();\n\t\treturn true;\n\t}\n\n\tallocUI32(count: number): AllocatedMemory {\n\t\tcount = Math.ceil(count);\n\t\tfor(let i = 0; i < this.buffers.length; i++) {\n\t\t\tconst buffer = this.buffers[i];\n\t\t\t// Should just mean we haven't synced this buffer from another thread yet\n\t\t\tif(!buffer) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Should be fine to initialize all values as 0s since unsigned/signed ints and floats all store 0 as all 0s\n\t\t\tconst data = buffer.callocAs('u32', count);\n\t\t\tif(data) {\n\t\t\t\t// Auto grow when nearly full when we need buffer to already be sync'd between threads BEFORE we try to use it\n\t\t\t\tif(\n\t\t\t\t\ti === (this.buffers.length - 1)\n\t\t\t\t\t&& Atomics.load(this.memory.data, BUFFER_COUNT_INDEX) === this.buffers.length\n\t\t\t\t\t&& this.memory.data[BUFFER_AUTO_GROW_INDEX] < 100\n\t\t\t\t\t&& this.memory.data[BUFFER_AUTO_GROW_INDEX] > 0\n\t\t\t\t) {\n\t\t\t\t\tconst percentFull = buffer.top / buffer.end;\n\t\t\t\t\tif(percentFull > (this.memory.data[BUFFER_AUTO_GROW_INDEX] / 100)) {\n\t\t\t\t\t\tthis.growBuffer();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn new AllocatedMemory(this, {\n\t\t\t\t\tdata,\n\t\t\t\t\tbuffer,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif(this.buffers.length >= MAX_POSITION_LENGTH) {\n\t\t\tthrow new Error(`Can't initialize a new buffer since it would have a position greater than the max of ${MAX_POSITION_LENGTH}`);\n\t\t}\n\n\t\t// If we get here we need to grow another buffer to continue allocating new memory\n\t\tlet buffer = this.growBuffer();\n\t\tconst data = buffer.callocAs('u32', count);\n\t\tif(data) {\n\t\t\treturn new AllocatedMemory(this, {\n\t\t\t\tdata,\n\t\t\t\tbuffer,\n\t\t\t});\n\t\t} else {\n\t\t\tthrow new Error(`Unable to allocate ${count} numbers even after adding a new buffer`);\n\t\t}\n\t}\n\n\tgetSharedAlloc(shared: SharedAllocatedMemory): AllocatedMemory | undefined {\n\t\t// Should just mean it hasn't synced to this thread yet\n\t\tif(this.buffers[shared.bufferPosition] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn new AllocatedMemory(this, shared);\n\t}\n\n\tget currentUsed() {\n\t\treturn this.totalAllocated - this.buffers.reduce((total, memPool) => total + memPool.stats().available, 0);\n\t}\n\tget totalAllocated() {\n\t\treturn this.buffers[0].buf.byteLength * this.buffers.length;\n\t}\n\n\tgetSharedMemory(): MemoryHeapMemory {\n\t\treturn {\n\t\t\tbuffers: this.buffers.map(buffer => buffer.buf as SharedArrayBuffer),\n\t\t};\n\t}\n}\n\ntype OnGrowBuffer = (newBuffer: GrowBufferData) => void;\ninterface GrowBufferData {\n\tbufferPosition: number\n\tbuffer: SharedArrayBuffer\n}\n\ninterface MemoryHeapConfig {\n\tbufferSize?: number\n\tinitialBuffers?: number\n\tautoGrowSize?: number\n}\ninterface MemoryHeapMemory {\n\tbuffers: Array<SharedArrayBuffer>\n}\n\nexport type { MemoryHeapConfig, MemoryHeapMemory, GrowBufferData };"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import AllocatedMemory from './allocated-memory';
|
|
2
|
+
import type MemoryHeap from './memory-heap';
|
|
3
3
|
export declare function serializeObjectToMemory<T extends object>(heap: MemoryHeap, object: T): AllocatedMemory;
|
|
4
4
|
export declare function createObjectFromPointer<T extends object>(heap: MemoryHeap, pointer: number): T;
|
|
5
5
|
export declare function createObjectFromMemory<T extends object>(memory: AllocatedMemory): T;
|
package/dist/serialize-object.js
CHANGED
|
@@ -1,59 +1,47 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/* STRING */
|
|
18
|
-
), e.push(a.length), u(e, a));
|
|
19
|
-
});
|
|
20
|
-
let f = r.allocUI32(e.length);
|
|
21
|
-
return f.getArray(Float32Array, 0, e.length).set(e), f;
|
|
1
|
+
import { getPointer as e } from "./utils/pointer.js";
|
|
2
|
+
import t from "./allocated-memory.js";
|
|
3
|
+
//#region src/serialize-object.ts
|
|
4
|
+
var n = 52361700;
|
|
5
|
+
function r(e, t) {
|
|
6
|
+
let r = [], i = Object.keys(t);
|
|
7
|
+
r.push(n), r.push(i.length);
|
|
8
|
+
let a = {};
|
|
9
|
+
i.forEach((e) => {
|
|
10
|
+
r.push(e.length), o(r, e), a[e] = r.length, r.push(0);
|
|
11
|
+
}), i.forEach((e) => {
|
|
12
|
+
let n = a[e], i = t[e];
|
|
13
|
+
Number.isFinite(i) ? (r[n] = r.length, r.push(1), r.push(i)) : typeof i == "string" && (r[n] = r.length, r.push(2), r.push(i.length), o(r, i));
|
|
14
|
+
});
|
|
15
|
+
let s = e.allocUI32(r.length);
|
|
16
|
+
return s.getArray(Float32Array, 0, r.length).set(r), s;
|
|
22
17
|
}
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
return g(e);
|
|
18
|
+
function i(n, r) {
|
|
19
|
+
return a(new t(n, e(r)));
|
|
26
20
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
n += 2 + h;
|
|
47
|
-
}
|
|
48
|
-
return e;
|
|
21
|
+
function a(e) {
|
|
22
|
+
let t = new Float32Array(e.data.buffer, e.bufferByteOffset);
|
|
23
|
+
if (t[0] !== n) throw Error("Trying to create object from invalid memory location");
|
|
24
|
+
let r = {}, i = t[1], a = 2;
|
|
25
|
+
for (let n = 0; n < i; n++) {
|
|
26
|
+
let n = t[a], i = new Float32Array(e.data.buffer, e.bufferByteOffset + (a + 1) * t.BYTES_PER_ELEMENT, n), o = String.fromCharCode.apply(null, [...i]), s = t[a + n + 1];
|
|
27
|
+
switch (t[s]) {
|
|
28
|
+
case 1:
|
|
29
|
+
r[o] = t[s + 1];
|
|
30
|
+
break;
|
|
31
|
+
case 2: {
|
|
32
|
+
let n = t[s + 1], i = new Float32Array(e.data.buffer, e.bufferByteOffset + (s + 2) * t.BYTES_PER_ELEMENT, n);
|
|
33
|
+
r[o] = String.fromCharCode.apply(null, [...i]);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
a += 2 + n;
|
|
38
|
+
}
|
|
39
|
+
return r;
|
|
49
40
|
}
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
r.push(t.charCodeAt(e));
|
|
41
|
+
function o(e, t) {
|
|
42
|
+
for (let n = 0; n < t.length; n++) e.push(t.charCodeAt(n));
|
|
53
43
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
};
|
|
59
|
-
//# sourceMappingURL=serialize-object.js.map
|
|
44
|
+
//#endregion
|
|
45
|
+
export { a as createObjectFromMemory, i as createObjectFromPointer, r as serializeObjectToMemory };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=serialize-object.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serialize-object.js","sources":["../src/serialize-object.ts"],"sourcesContent":["import AllocatedMemory from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer } from './utils/pointer';\n\nenum VALUE_TYPE {\n\tUNDEFINED,\n\tNUMBER,\n\tSTRING
|
|
1
|
+
{"version":3,"file":"serialize-object.js","names":[],"sources":["../src/serialize-object.ts"],"sourcesContent":["import AllocatedMemory from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer } from './utils/pointer';\n\nenum VALUE_TYPE {\n\tUNDEFINED,\n\tNUMBER,\n\tSTRING,\n}\n\n// Be able to serialize a simple object into memory and re-create the object in another thread\n// This does NOT support updating objects across threads\nconst MAGIC_NUMBER = 52361700;\nexport function serializeObjectToMemory<T extends object>(heap: MemoryHeap, object: T): AllocatedMemory {\n\tconst data: Array<number> = [];\n\tconst keys = Object.keys(object);\n\tdata.push(MAGIC_NUMBER);\n\tdata.push(keys.length);\n\n\t// Create index first so we can quickly construct index\n\tlet keyIndexes: { [key:string]:number } = {};\n\tkeys.forEach(key => {\n\t\tdata.push(key.length);\n\t\taddCharCodes(data, key);\n\n\t\tkeyIndexes[key] = data.length;\n\t\tdata.push(0);\n\t});\n\n\tkeys.forEach(key => {\n\t\tlet keyIndex = keyIndexes[key];\n\t\t// @ts-expect-error\n\t\tlet value = object[key];\n\t\tif(Number.isFinite(value)) {\n\t\t\tdata[keyIndex] = data.length;\n\t\t\tdata.push(VALUE_TYPE.NUMBER);\n\t\t\tdata.push(value);\n\t\t} else if(typeof value === 'string') {\n\t\t\tdata[keyIndex] = data.length;\n\t\t\tdata.push(VALUE_TYPE.STRING);\n\t\t\tdata.push(value.length);\n\t\t\taddCharCodes(data, value);\n\t\t}\n\t});\n\t\n\tlet memory = heap.allocUI32(data.length);\n\tlet sharedData = memory.getArray(Float32Array, 0, data.length);\n\tsharedData.set(data);\n\n\treturn memory;\n}\n\nexport function createObjectFromPointer<T extends object>(heap: MemoryHeap, pointer: number) {\n\tlet memory = new AllocatedMemory(heap, getPointer(pointer));\n\treturn createObjectFromMemory<T>(memory);\n}\nexport function createObjectFromMemory<T extends object>(memory: AllocatedMemory): T {\n\tlet sharedData = new Float32Array(memory.data.buffer, memory.bufferByteOffset);\n\tif(sharedData[0] !== MAGIC_NUMBER) {\n\t\tthrow new Error('Trying to create object from invalid memory location');\n\t}\n\n\tconst sharedObject: { [key:string]:any } = {};\n\tconst keyCount = sharedData[1];\n\tlet keyStartIndex = 2;\n\tfor(let i = 0; i < keyCount; i++) {\n\t\tlet keyLength = sharedData[keyStartIndex];\n\t\tlet keyData = new Float32Array(memory.data.buffer, memory.bufferByteOffset + (keyStartIndex + 1) * sharedData.BYTES_PER_ELEMENT, keyLength);\n\t\tlet key = String.fromCharCode.apply(null, [...keyData]);\n\t\tlet valueIndex = sharedData[keyStartIndex + keyLength + 1];\n\t\tlet valueType = sharedData[valueIndex];\n\t\tswitch(valueType) {\n\t\t\tcase VALUE_TYPE.NUMBER: {\n\t\t\t\tsharedObject[key] = sharedData[valueIndex + 1];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase VALUE_TYPE.STRING: {\n\t\t\t\tlet length = sharedData[valueIndex + 1];\n\t\t\t\tlet valueData = new Float32Array(memory.data.buffer, memory.bufferByteOffset + (valueIndex + 2) * sharedData.BYTES_PER_ELEMENT, length);\n\t\t\t\tsharedObject[key] = String.fromCharCode.apply(null, [...valueData]);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tkeyStartIndex += 2 + keyLength;\n\t}\n\n\treturn sharedObject as T;\n}\n\nfunction addCharCodes(data: Array<number>, value: string) {\n\tfor(let i = 0; i < value.length; i++) {\n\t\tdata.push(value.charCodeAt(i));\n\t}\n}"],"mappings":";;;AAYA,IAAM,IAAe;AACrB,SAAgB,EAA0C,GAAkB,GAA4B;CACvG,IAAM,IAAsB,CAAC,GACvB,IAAO,OAAO,KAAK,CAAM;CAE/B,AADA,EAAK,KAAK,CAAY,GACtB,EAAK,KAAK,EAAK,MAAM;CAGrB,IAAI,IAAsC,CAAC;CAS3C,AARA,EAAK,SAAQ,MAAO;EAKnB,AAJA,EAAK,KAAK,EAAI,MAAM,GACpB,EAAa,GAAM,CAAG,GAEtB,EAAW,KAAO,EAAK,QACvB,EAAK,KAAK,CAAC;CACZ,CAAC,GAED,EAAK,SAAQ,MAAO;EACnB,IAAI,IAAW,EAAW,IAEtB,IAAQ,EAAO;EACnB,AAAG,OAAO,SAAS,CAAK,KACvB,EAAK,KAAY,EAAK,QACtB,EAAK,KAAA,CAAsB,GAC3B,EAAK,KAAK,CAAK,KACN,OAAO,KAAU,aAC1B,EAAK,KAAY,EAAK,QACtB,EAAK,KAAA,CAAsB,GAC3B,EAAK,KAAK,EAAM,MAAM,GACtB,EAAa,GAAM,CAAK;CAE1B,CAAC;CAED,IAAI,IAAS,EAAK,UAAU,EAAK,MAAM;CAIvC,OAFA,EADwB,SAAS,cAAc,GAAG,EAAK,MACvD,CAAA,CAAW,IAAI,CAAI,GAEZ;AACR;AAEA,SAAgB,EAA0C,GAAkB,GAAiB;CAE5F,OAAO,EAA0B,IADhB,EAAgB,GAAM,EAAW,CAAO,CACxB,CAAM;AACxC;AACA,SAAgB,EAAyC,GAA4B;CACpF,IAAI,IAAa,IAAI,aAAa,EAAO,KAAK,QAAQ,EAAO,gBAAgB;CAC7E,IAAG,EAAW,OAAO,GACpB,MAAU,MAAM,sDAAsD;CAGvE,IAAM,IAAqC,CAAC,GACtC,IAAW,EAAW,IACxB,IAAgB;CACpB,KAAI,IAAI,IAAI,GAAG,IAAI,GAAU,KAAK;EACjC,IAAI,IAAY,EAAW,IACvB,IAAU,IAAI,aAAa,EAAO,KAAK,QAAQ,EAAO,oBAAoB,IAAgB,KAAK,EAAW,mBAAmB,CAAS,GACtI,IAAM,OAAO,aAAa,MAAM,MAAM,CAAC,GAAG,CAAO,CAAC,GAClD,IAAa,EAAW,IAAgB,IAAY;EAExD,QADgB,EAAW,IAC3B;GACC,KAAA;IACC,EAAa,KAAO,EAAW,IAAa;IAC5C;GAED,KAAA,GAAwB;IACvB,IAAI,IAAS,EAAW,IAAa,IACjC,IAAY,IAAI,aAAa,EAAO,KAAK,QAAQ,EAAO,oBAAoB,IAAa,KAAK,EAAW,mBAAmB,CAAM;IACtI,EAAa,KAAO,OAAO,aAAa,MAAM,MAAM,CAAC,GAAG,CAAS,CAAC;IAClE;GACD;EACD;EAEA,KAAiB,IAAI;CACtB;CAEA,OAAO;AACR;AAEA,SAAS,EAAa,GAAqB,GAAe;CACzD,KAAI,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAChC,EAAK,KAAK,EAAM,WAAW,CAAC,CAAC;AAE/B"}
|