@daneren2005/shared-memory-objects 1.5.0 → 1.5.2
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/dist/allocated-memory.d.ts +7 -2
- package/dist/allocated-memory.js +10 -3
- package/dist/allocated-memory.js.map +1 -1
- package/dist/cached-item-list.d.ts +1 -1
- package/dist/lock/read-write-lock.d.ts +1 -0
- package/dist/lock/read-write-lock.js +6 -3
- package/dist/lock/read-write-lock.js.map +1 -1
- package/dist/memory-buffer.d.ts +11 -5
- package/dist/memory-buffer.js +70 -74
- package/dist/memory-buffer.js.map +1 -1
- package/dist/memory-heap.d.ts +1 -0
- package/dist/memory-heap.js +28 -25
- package/dist/memory-heap.js.map +1 -1
- package/dist/shared-list.d.ts +5 -1
- package/dist/shared-list.js +91 -47
- package/dist/shared-list.js.map +1 -1
- package/dist/shared-map.js +4 -1
- package/dist/shared-map.js.map +1 -1
- package/dist/shared-pool.js +4 -1
- package/dist/shared-pool.js.map +1 -1
- package/dist/shared-stack.js +11 -2
- package/dist/shared-stack.js.map +1 -1
- package/dist/shared-vector.js +4 -1
- package/dist/shared-vector.js.map +1 -1
- package/dist/spatial/shared-spatial-map.js +134 -134
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ export default class AllocatedMemory {
|
|
|
10
10
|
private buffer;
|
|
11
11
|
data: Uint32Array;
|
|
12
12
|
get usedMemory(): number;
|
|
13
|
-
constructor(memory: MemoryHeap, config: AllocatedMemoryConfig | SharedAllocatedMemory);
|
|
13
|
+
constructor(memory: MemoryHeap, config: AllocatedMemoryConfig | SharedAllocatedMemory | AllocatedMemoryPointer);
|
|
14
14
|
getArray<T extends TypedArray>(type: TypedArrayConstructor<T>, offset: number, length: number): T;
|
|
15
15
|
getSubAllocation(offset: number, length: number): AllocatedMemory;
|
|
16
16
|
getArrayMemory(offset: number, length: number): SharedAllocatedMemory;
|
|
@@ -24,5 +24,10 @@ interface AllocatedMemoryConfig {
|
|
|
24
24
|
interface SharedAllocatedMemory {
|
|
25
25
|
bufferPosition: number;
|
|
26
26
|
bufferByteOffset: number;
|
|
27
|
+
length?: number;
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
+
interface AllocatedMemoryPointer {
|
|
30
|
+
bufferPosition: number;
|
|
31
|
+
bufferByteOffset: number;
|
|
32
|
+
}
|
|
33
|
+
export type { AllocatedMemoryPointer, SharedAllocatedMemory };
|
package/dist/allocated-memory.js
CHANGED
|
@@ -15,7 +15,12 @@ var t = class t {
|
|
|
15
15
|
return this.buffer.bytesFor(this.data.byteOffset) ?? 0;
|
|
16
16
|
}
|
|
17
17
|
constructor(e, t) {
|
|
18
|
-
this.memory = e, "buffer" in t
|
|
18
|
+
if (this.memory = e, "buffer" in t) this.data = t.data, this.buffer = t.buffer, this.bufferPosition = this.memory.buffers.indexOf(t.buffer);
|
|
19
|
+
else {
|
|
20
|
+
this.bufferPosition = t.bufferPosition, this.buffer = e.buffers[t.bufferPosition];
|
|
21
|
+
let n = "length" in t ? t.length : this.buffer.allocationLengthAt(t.bufferByteOffset);
|
|
22
|
+
this.data = new Uint32Array(this.buffer.buf, t.bufferByteOffset, n);
|
|
23
|
+
}
|
|
19
24
|
}
|
|
20
25
|
getArray(e, t, n) {
|
|
21
26
|
return new e(this.data.buffer, this.data.byteOffset + t * e.BYTES_PER_ELEMENT, n);
|
|
@@ -29,7 +34,8 @@ var t = class t {
|
|
|
29
34
|
getArrayMemory(e, t) {
|
|
30
35
|
return {
|
|
31
36
|
bufferPosition: this.bufferPosition,
|
|
32
|
-
bufferByteOffset: this.bufferByteOffset + e * this.data.BYTES_PER_ELEMENT
|
|
37
|
+
bufferByteOffset: this.bufferByteOffset + e * this.data.BYTES_PER_ELEMENT,
|
|
38
|
+
length: t
|
|
33
39
|
};
|
|
34
40
|
}
|
|
35
41
|
free() {
|
|
@@ -38,7 +44,8 @@ var t = class t {
|
|
|
38
44
|
getSharedMemory() {
|
|
39
45
|
return {
|
|
40
46
|
bufferPosition: this.bufferPosition,
|
|
41
|
-
bufferByteOffset: this.bufferByteOffset
|
|
47
|
+
bufferByteOffset: this.bufferByteOffset,
|
|
48
|
+
length: this.data.length
|
|
42
49
|
};
|
|
43
50
|
}
|
|
44
51
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"allocated-memory.js","names":[],"sources":["../src/allocated-memory.ts"],"sourcesContent":["import type { TypedArray } from './interfaces/typed-array';\nimport type { TypedArrayConstructor } from './interfaces/typed-array-constructor';\nimport type MemoryBuffer from './memory-buffer';\nimport type MemoryHeap from './memory-heap';\nimport { createPointer } from './utils/pointer';\n\nexport default class AllocatedMemory {\n\tprivate readonly memory: MemoryHeap;\n\n\treadonly bufferPosition: number;\n\tget bufferByteOffset(): number {\n\t\treturn this.data.byteOffset;\n\t}\n\tget pointer(): number {\n\t\treturn createPointer(this.bufferPosition, this.bufferByteOffset, this.memory.positionBits);\n\t}\n\tprivate buffer: MemoryBuffer;\n\tdata: Uint32Array;\n\n\t// Bytes this allocation occupies in its buffer (aligned data size, excluding the block header)\n\tget usedMemory(): number {\n\t\treturn this.buffer.bytesFor(this.data.byteOffset) ?? 0;\n\t}\n\n\tconstructor(memory: MemoryHeap, config: AllocatedMemoryConfig | SharedAllocatedMemory) {\n\t\tthis.memory = memory;\n\n\t\tif('buffer' in config) {\n\t\t\tthis.data = config.data;\n\t\t\tthis.buffer = config.buffer;\n\t\t\tthis.bufferPosition = this.memory.buffers.indexOf(config.buffer);\n\t\t} else {\n\t\t\tthis.bufferPosition = config.bufferPosition;\n\t\t\tthis.buffer = memory.buffers[config.bufferPosition];\n\n\t\t\
|
|
1
|
+
{"version":3,"file":"allocated-memory.js","names":[],"sources":["../src/allocated-memory.ts"],"sourcesContent":["import type { TypedArray } from './interfaces/typed-array';\nimport type { TypedArrayConstructor } from './interfaces/typed-array-constructor';\nimport type MemoryBuffer from './memory-buffer';\nimport type MemoryHeap from './memory-heap';\nimport { createPointer } from './utils/pointer';\n\nexport default class AllocatedMemory {\n\tprivate readonly memory: MemoryHeap;\n\n\treadonly bufferPosition: number;\n\tget bufferByteOffset(): number {\n\t\treturn this.data.byteOffset;\n\t}\n\tget pointer(): number {\n\t\treturn createPointer(this.bufferPosition, this.bufferByteOffset, this.memory.positionBits);\n\t}\n\tprivate buffer: MemoryBuffer;\n\tdata: Uint32Array;\n\n\t// Bytes this allocation occupies in its buffer (aligned data size, excluding the block header)\n\tget usedMemory(): number {\n\t\treturn this.buffer.bytesFor(this.data.byteOffset) ?? 0;\n\t}\n\n\tconstructor(memory: MemoryHeap, config: AllocatedMemoryConfig | SharedAllocatedMemory | AllocatedMemoryPointer) {\n\t\tthis.memory = memory;\n\n\t\tif('buffer' in config) {\n\t\t\tthis.data = config.data;\n\t\t\tthis.buffer = config.buffer;\n\t\t\tthis.bufferPosition = this.memory.buffers.indexOf(config.buffer);\n\t\t} else {\n\t\t\tthis.bufferPosition = config.bufferPosition;\n\t\t\tthis.buffer = memory.buffers[config.bufferPosition];\n\n\t\t\tconst length = 'length' in config\n\t\t\t\t? config.length\n\t\t\t\t: this.buffer.allocationLengthAt(config.bufferByteOffset);\n\t\t\tthis.data = new Uint32Array(this.buffer.buf, config.bufferByteOffset, length);\n\t\t}\n\t}\n\n\tgetArray<T extends TypedArray>(type: TypedArrayConstructor<T>, offset: number, length: number): T {\n\t\tif(import.meta.env.MODE === 'development' || import.meta.env.MODE === 'test') {\n\t\t\tif((offset + length) * type.BYTES_PER_ELEMENT > this.data.byteLength) {\n\t\t\t\tconst message = 'Trying to grab more memory from AllocatedMemory.getArray then we have: '\n\t\t\t\t\t+ `${offset * type.BYTES_PER_ELEMENT} + ${length * type.BYTES_PER_ELEMENT} > ${this.data.byteLength}`;\n\t\t\t\tif(import.meta.env.MODE === 'test') {\n\t\t\t\t\tthrow new Error(message);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.warn(message);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new type(this.data.buffer, this.data.byteOffset + offset * type.BYTES_PER_ELEMENT, length);\n\t}\n\t// A child AllocatedMemory over a slice of this block, sharing the same buffer. Built through the {data, buffer} path\n\t// (same as a fresh allocUI32) so callers stay on the cheap, monomorphic construction branch instead of re-resolving a\n\t// pointer. Used to inline sub-structures (e.g. SharedPool's stacks) inside one contiguous allocation.\n\tgetSubAllocation(offset: number, length: number): AllocatedMemory {\n\t\treturn new AllocatedMemory(this.memory, {\n\t\t\tdata: new Uint32Array(this.data.buffer, this.bufferByteOffset + offset * Uint32Array.BYTES_PER_ELEMENT, length),\n\t\t\tbuffer: this.buffer,\n\t\t});\n\t}\n\n\tgetArrayMemory(offset: number, length: number): SharedAllocatedMemory {\n\t\tif(import.meta.env.MODE === 'development') {\n\t\t\tif(offset + length > this.data.length) {\n\t\t\t\tconsole.warn(`Trying to grab more memory from AllocatedMemory.getArrayMemory then we have: ${offset} + ${length} > ${this.data.length}`);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tbufferPosition: this.bufferPosition,\n\t\t\tbufferByteOffset: this.bufferByteOffset + offset * this.data.BYTES_PER_ELEMENT,\n\t\t\tlength,\n\t\t};\n\t}\n\n\tfree() {\n\t\t// NOTE: From worker thread you can't pass the array, you have to pass an explicit address to free\n\t\tthis.buffer.free(this.data.byteOffset);\n\t}\n\n\tgetSharedMemory(): SharedAllocatedMemory {\n\t\treturn {\n\t\t\tbufferPosition: this.bufferPosition,\n\t\t\tbufferByteOffset: this.bufferByteOffset,\n\t\t\tlength: this.data.length,\n\t\t};\n\t}\n}\n\ninterface AllocatedMemoryConfig {\n\tdata: Uint32Array\n\tbuffer: MemoryBuffer\n}\n\ninterface SharedAllocatedMemory {\n\tbufferPosition: number\n\tbufferByteOffset: number\n\tlength?: number\n}\ninterface AllocatedMemoryPointer {\n\tbufferPosition: number\n\tbufferByteOffset: number\n}\nexport type { AllocatedMemoryPointer, SharedAllocatedMemory };"],"mappings":";;AAMA,IAAqB,IAArB,MAAqB,EAAgB;CACpC;CAEA;CACA,IAAI,mBAA2B;EAC9B,OAAO,KAAK,KAAK;CAClB;CACA,IAAI,UAAkB;EACrB,OAAO,EAAc,KAAK,gBAAgB,KAAK,kBAAkB,KAAK,OAAO,YAAY;CAC1F;CACA;CACA;CAGA,IAAI,aAAqB;EACxB,OAAO,KAAK,OAAO,SAAS,KAAK,KAAK,UAAU,KAAK;CACtD;CAEA,YAAY,GAAoB,GAAgF;EAG/G,IAFA,KAAK,SAAS,GAEX,YAAY,GAGd,AAFA,KAAK,OAAO,EAAO,MACnB,KAAK,SAAS,EAAO,QACrB,KAAK,iBAAiB,KAAK,OAAO,QAAQ,QAAQ,EAAO,MAAM;OACzD;GAEN,AADA,KAAK,iBAAiB,EAAO,gBAC7B,KAAK,SAAS,EAAO,QAAQ,EAAO;GAEpC,IAAM,IAAS,YAAY,IACxB,EAAO,SACP,KAAK,OAAO,mBAAmB,EAAO,gBAAgB;GACzD,KAAK,OAAO,IAAI,YAAY,KAAK,OAAO,KAAK,EAAO,kBAAkB,CAAM;EAC7E;CACD;CAEA,SAA+B,GAAgC,GAAgB,GAAmB;EAajG,OAAO,IAAI,EAAK,KAAK,KAAK,QAAQ,KAAK,KAAK,aAAa,IAAS,EAAK,mBAAmB,CAAM;CACjG;CAIA,iBAAiB,GAAgB,GAAiC;EACjE,OAAO,IAAI,EAAgB,KAAK,QAAQ;GACvC,MAAM,IAAI,YAAY,KAAK,KAAK,QAAQ,KAAK,mBAAmB,IAAS,YAAY,mBAAmB,CAAM;GAC9G,QAAQ,KAAK;EACd,CAAC;CACF;CAEA,eAAe,GAAgB,GAAuC;EAOrE,OAAO;GACN,gBAAgB,KAAK;GACrB,kBAAkB,KAAK,mBAAmB,IAAS,KAAK,KAAK;GAC7D;EACD;CACD;CAEA,OAAO;EAEN,KAAK,OAAO,KAAK,KAAK,KAAK,UAAU;CACtC;CAEA,kBAAyC;EACxC,OAAO;GACN,gBAAgB,KAAK;GACrB,kBAAkB,KAAK;GACvB,QAAQ,KAAK,KAAK;EACnB;CACD;AACD"}
|
|
@@ -5,7 +5,7 @@ export default abstract class CachedItemList<T extends Item> implements Iterable
|
|
|
5
5
|
item: T;
|
|
6
6
|
deleteCurrent: () => void;
|
|
7
7
|
}> {
|
|
8
|
-
static readonly ALLOCATE_COUNT =
|
|
8
|
+
static readonly ALLOCATE_COUNT = 7;
|
|
9
9
|
protected heap: MemoryHeap;
|
|
10
10
|
protected list: SharedList;
|
|
11
11
|
protected cache: Map<number, T>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare function readLock(data: Int32Array, index?: number): void;
|
|
2
2
|
export declare function writeLock(data: Int32Array, index?: number): void;
|
|
3
|
+
export declare function tryWriteLock(data: Int32Array, index?: number): boolean;
|
|
3
4
|
export declare function readUnlock(data: Int32Array, index?: number): void;
|
|
4
5
|
export declare function writeUnlock(data: Int32Array, index?: number): void;
|
|
5
6
|
export declare const READ_WRITE_LOCK_ALLOCATE_COUNT = 2;
|
|
@@ -21,13 +21,16 @@ function n(t, n = 0) {
|
|
|
21
21
|
Atomics.sub(t, n + 1, 1);
|
|
22
22
|
}
|
|
23
23
|
function r(e, t = 0) {
|
|
24
|
-
Atomics.
|
|
24
|
+
return Atomics.compareExchange(e, t, 0, -1) === 0;
|
|
25
25
|
}
|
|
26
26
|
function i(e, t = 0) {
|
|
27
|
+
Atomics.sub(e, t, 1) === 1 && Atomics.notify(e, t);
|
|
28
|
+
}
|
|
29
|
+
function a(e, t = 0) {
|
|
27
30
|
Atomics.compareExchange(e, t, -1, 0) !== -1 && console.warn("We are unlocking when it was not write locked!"), Atomics.notify(e, t), Atomics.notify(e, t + 1);
|
|
28
31
|
}
|
|
29
|
-
var
|
|
32
|
+
var o = 2;
|
|
30
33
|
//#endregion
|
|
31
|
-
export {
|
|
34
|
+
export { o as READ_WRITE_LOCK_ALLOCATE_COUNT, t as readLock, i as readUnlock, r as tryWriteLock, n as writeLock, a as writeUnlock };
|
|
32
35
|
|
|
33
36
|
//# sourceMappingURL=read-write-lock.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-write-lock.js","names":[],"sources":["../../src/lock/read-write-lock.ts"],"sourcesContent":["const WRITE_LOCKED = -1;\n\nfunction canWait(): boolean {\n\treturn typeof self !== 'undefined' && 'WorkerGlobalScope' in self;\n}\n\nexport function readLock(data: Int32Array, index: number = 0) {\n\t// Pending writers block new readers so a steady stream of queries cannot starve a resize.\n\twhile(true) {\n\t\tlet writers = data[index + 1];\n\t\tif(writers !== 0) {\n\t\t\tif(canWait()) {\n\t\t\t\tAtomics.wait(data, index + 1, writers);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tlet readers = data[index];\n\t\tif(readers !== WRITE_LOCKED && Atomics.compareExchange(data, index, readers, readers + 1) === readers) {\n\t\t\treturn;\n\t\t}\n\t\tif(canWait() && readers === WRITE_LOCKED) {\n\t\t\tAtomics.wait(data, index, WRITE_LOCKED);\n\t\t}\n\t}\n}\nexport function writeLock(data: Int32Array, index: number = 0) {\n\tAtomics.add(data, index + 1, 1);\n\twhile(Atomics.compareExchange(data, index, 0, WRITE_LOCKED) !== 0) {\n\t\tlet state = data[index];\n\t\tif(canWait() && state !== 0) {\n\t\t\tAtomics.wait(data, index, state);\n\t\t}\n\t}\n\tAtomics.sub(data, index + 1, 1);\n}\n\nexport function readUnlock(data: Int32Array, index: number = 0) {\n\tif(Atomics.sub(data, index, 1) === 1) {\n\t\tAtomics.notify(data, index);\n\t}\n}\nexport function writeUnlock(data: Int32Array, index: number = 0) {\n\tif(Atomics.compareExchange(data, index, WRITE_LOCKED, 0) !== WRITE_LOCKED) {\n\t\tconsole.warn('We are unlocking when it was not write locked!');\n\t}\n\tAtomics.notify(data, index);\n\tAtomics.notify(data, index + 1);\n}\n\nexport const READ_WRITE_LOCK_ALLOCATE_COUNT = 2;\n"],"mappings":"AAEA,SAAS,IAAmB;CAC3B,OAAO,OAAO,OAAS,OAAe,uBAAuB;AAC9D;AAEA,SAAgB,EAAS,GAAkB,IAAgB,GAAG;CAE7D,SAAY;EACX,IAAI,IAAU,EAAK,IAAQ;EAC3B,IAAG,MAAY,GAAG;GACjB,AAAG,EAAQ,KACV,QAAQ,KAAK,GAAM,IAAQ,GAAG,CAAO;GAEtC;EACD;EACA,IAAI,IAAU,EAAK;EACnB,IAAG,MAAY,MAAgB,QAAQ,gBAAgB,GAAM,GAAO,GAAS,IAAU,CAAC,MAAM,GAC7F;EAED,AAAG,EAAQ,KAAK,MAAY,MAC3B,QAAQ,KAAK,GAAM,GAAO,EAAY;CAExC;AACD;AACA,SAAgB,EAAU,GAAkB,IAAgB,GAAG;CAE9D,KADA,QAAQ,IAAI,GAAM,IAAQ,GAAG,CAAC,GACxB,QAAQ,gBAAgB,GAAM,GAAO,GAAG,EAAY,MAAM,IAAG;EAClE,IAAI,IAAQ,EAAK;EACjB,AAAG,EAAQ,KAAK,MAAU,KACzB,QAAQ,KAAK,GAAM,GAAO,CAAK;CAEjC;CACA,QAAQ,IAAI,GAAM,IAAQ,GAAG,CAAC;AAC/B;AAEA,SAAgB,EAAW,GAAkB,IAAgB,GAAG;CAC/D,AAAG,QAAQ,IAAI,GAAM,GAAO,CAAC,MAAM,KAClC,QAAQ,OAAO,GAAM,CAAK;AAE5B;AACA,SAAgB,EAAY,GAAkB,IAAgB,GAAG;CAKhE,AAJG,QAAQ,gBAAgB,GAAM,GAAO,IAAc,CAAC,MAAM,MAC5D,QAAQ,KAAK,gDAAgD,GAE9D,QAAQ,OAAO,GAAM,CAAK,GAC1B,QAAQ,OAAO,GAAM,IAAQ,CAAC;AAC/B;AAEA,IAAa,IAAiC"}
|
|
1
|
+
{"version":3,"file":"read-write-lock.js","names":[],"sources":["../../src/lock/read-write-lock.ts"],"sourcesContent":["const WRITE_LOCKED = -1;\n\nfunction canWait(): boolean {\n\treturn typeof self !== 'undefined' && 'WorkerGlobalScope' in self;\n}\n\nexport function readLock(data: Int32Array, index: number = 0) {\n\t// Pending writers block new readers so a steady stream of queries cannot starve a resize.\n\twhile(true) {\n\t\tlet writers = data[index + 1];\n\t\tif(writers !== 0) {\n\t\t\tif(canWait()) {\n\t\t\t\tAtomics.wait(data, index + 1, writers);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tlet readers = data[index];\n\t\tif(readers !== WRITE_LOCKED && Atomics.compareExchange(data, index, readers, readers + 1) === readers) {\n\t\t\treturn;\n\t\t}\n\t\tif(canWait() && readers === WRITE_LOCKED) {\n\t\t\tAtomics.wait(data, index, WRITE_LOCKED);\n\t\t}\n\t}\n}\nexport function writeLock(data: Int32Array, index: number = 0) {\n\tAtomics.add(data, index + 1, 1);\n\twhile(Atomics.compareExchange(data, index, 0, WRITE_LOCKED) !== 0) {\n\t\tlet state = data[index];\n\t\tif(canWait() && state !== 0) {\n\t\t\tAtomics.wait(data, index, state);\n\t\t}\n\t}\n\tAtomics.sub(data, index + 1, 1);\n}\n// Non-blocking write acquire: succeeds only when there is no active reader and no writer. Unlike writeLock it never\n// registers a pending writer, so a failed attempt leaves readers completely untouched - the caller just backs off.\nexport function tryWriteLock(data: Int32Array, index: number = 0): boolean {\n\treturn Atomics.compareExchange(data, index, 0, WRITE_LOCKED) === 0;\n}\n\nexport function readUnlock(data: Int32Array, index: number = 0) {\n\tif(Atomics.sub(data, index, 1) === 1) {\n\t\tAtomics.notify(data, index);\n\t}\n}\nexport function writeUnlock(data: Int32Array, index: number = 0) {\n\tif(Atomics.compareExchange(data, index, WRITE_LOCKED, 0) !== WRITE_LOCKED) {\n\t\tconsole.warn('We are unlocking when it was not write locked!');\n\t}\n\tAtomics.notify(data, index);\n\tAtomics.notify(data, index + 1);\n}\n\nexport const READ_WRITE_LOCK_ALLOCATE_COUNT = 2;\n"],"mappings":"AAEA,SAAS,IAAmB;CAC3B,OAAO,OAAO,OAAS,OAAe,uBAAuB;AAC9D;AAEA,SAAgB,EAAS,GAAkB,IAAgB,GAAG;CAE7D,SAAY;EACX,IAAI,IAAU,EAAK,IAAQ;EAC3B,IAAG,MAAY,GAAG;GACjB,AAAG,EAAQ,KACV,QAAQ,KAAK,GAAM,IAAQ,GAAG,CAAO;GAEtC;EACD;EACA,IAAI,IAAU,EAAK;EACnB,IAAG,MAAY,MAAgB,QAAQ,gBAAgB,GAAM,GAAO,GAAS,IAAU,CAAC,MAAM,GAC7F;EAED,AAAG,EAAQ,KAAK,MAAY,MAC3B,QAAQ,KAAK,GAAM,GAAO,EAAY;CAExC;AACD;AACA,SAAgB,EAAU,GAAkB,IAAgB,GAAG;CAE9D,KADA,QAAQ,IAAI,GAAM,IAAQ,GAAG,CAAC,GACxB,QAAQ,gBAAgB,GAAM,GAAO,GAAG,EAAY,MAAM,IAAG;EAClE,IAAI,IAAQ,EAAK;EACjB,AAAG,EAAQ,KAAK,MAAU,KACzB,QAAQ,KAAK,GAAM,GAAO,CAAK;CAEjC;CACA,QAAQ,IAAI,GAAM,IAAQ,GAAG,CAAC;AAC/B;AAGA,SAAgB,EAAa,GAAkB,IAAgB,GAAY;CAC1E,OAAO,QAAQ,gBAAgB,GAAM,GAAO,GAAG,EAAY,MAAM;AAClE;AAEA,SAAgB,EAAW,GAAkB,IAAgB,GAAG;CAC/D,AAAG,QAAQ,IAAI,GAAM,GAAO,CAAC,MAAM,KAClC,QAAQ,OAAO,GAAM,CAAK;AAE5B;AACA,SAAgB,EAAY,GAAkB,IAAgB,GAAG;CAKhE,AAJG,QAAQ,gBAAgB,GAAM,GAAO,IAAc,CAAC,MAAM,MAC5D,QAAQ,KAAK,gDAAgD,GAE9D,QAAQ,OAAO,GAAM,CAAK,GAC1B,QAAQ,OAAO,GAAM,IAAQ,CAAC;AAC/B;AAEA,IAAa,IAAiC"}
|
package/dist/memory-buffer.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export default class MemoryBuffer {
|
|
|
9
9
|
protected u32: Uint32Array;
|
|
10
10
|
protected state: Uint32Array;
|
|
11
11
|
protected lock: Int32Array;
|
|
12
|
+
private lastMallocFresh;
|
|
12
13
|
constructor(opts?: Partial<MemoryBufferConfig>);
|
|
13
14
|
stats(): Readonly<MemoryBufferStats>;
|
|
14
15
|
callocAs<T extends Type>(type: T, num: number, fill?: number): import("./utils/typedarray").TypedArrayTypeMap[T] | undefined;
|
|
@@ -16,13 +17,10 @@ export default class MemoryBuffer {
|
|
|
16
17
|
calloc(bytes: number, fill?: number): number;
|
|
17
18
|
malloc(bytes: number): number;
|
|
18
19
|
private mallocTop;
|
|
19
|
-
realloc(ptr: number, bytes: number): number;
|
|
20
|
-
private reallocBlock;
|
|
21
|
-
reallocArray<T extends TypedArray>(array: T, num: number): T | undefined;
|
|
22
20
|
bytesFor(ptrOrArray: number | TypedArray): number | undefined;
|
|
23
21
|
lengthOf(ptrOrArray: number | TypedArray): number | undefined;
|
|
22
|
+
allocationLengthAt(dataAddress: number): number;
|
|
24
23
|
free(ptrOrArray: number | TypedArray): boolean;
|
|
25
|
-
freeAll(): void;
|
|
26
24
|
release(): boolean;
|
|
27
25
|
protected get align(): Pow2;
|
|
28
26
|
protected set align(x: Pow2);
|
|
@@ -30,6 +28,8 @@ export default class MemoryBuffer {
|
|
|
30
28
|
protected set end(x: number);
|
|
31
29
|
get top(): number;
|
|
32
30
|
protected set top(x: number);
|
|
31
|
+
protected get highWater(): number;
|
|
32
|
+
protected set highWater(x: number);
|
|
33
33
|
get isEmpty(): boolean;
|
|
34
34
|
protected get _free(): number;
|
|
35
35
|
protected set _free(block: number);
|
|
@@ -56,6 +56,11 @@ export default class MemoryBuffer {
|
|
|
56
56
|
* @param block -
|
|
57
57
|
*/
|
|
58
58
|
protected setBlockNext(block: number, next: number): void;
|
|
59
|
+
protected blockPrev(block: number): number;
|
|
60
|
+
protected setBlockPrev(block: number, prev: number): void;
|
|
61
|
+
protected blockState(block: number): number;
|
|
62
|
+
protected setBlockState(block: number, state: number): void;
|
|
63
|
+
protected pushUsed(block: number): void;
|
|
59
64
|
/**
|
|
60
65
|
* Initializes block header with given `size` and `next` pointer. Returns `block`.
|
|
61
66
|
*
|
|
@@ -80,7 +85,8 @@ export default class MemoryBuffer {
|
|
|
80
85
|
*/
|
|
81
86
|
protected insert(block: number): void;
|
|
82
87
|
}
|
|
83
|
-
|
|
88
|
+
declare const FIRST_BLOCK_DATA_BYTE_OFFSET: number;
|
|
89
|
+
export { SIZEOF_STATE, SIZEOF_MEM_BLOCK, FIRST_BLOCK_DATA_BYTE_OFFSET };
|
|
84
90
|
type Type = 'u8' | 'u8c' | 'i8' | 'u16' | 'i16' | 'u32' | 'i32' | 'f32' | 'f64';
|
|
85
91
|
interface MemoryBufferConfig {
|
|
86
92
|
/**
|
package/dist/memory-buffer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { lock as e, unlock as t } from "./lock/simple-lock.js";
|
|
2
2
|
import { typedArray as n } from "./utils/typedarray.js";
|
|
3
3
|
//#region src/memory-buffer.ts
|
|
4
|
-
var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u =
|
|
4
|
+
var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 7, d = 1, f = 2, p = {
|
|
5
5
|
u8: 1,
|
|
6
6
|
u8c: 1,
|
|
7
7
|
i8: 1,
|
|
@@ -13,20 +13,21 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
13
13
|
u64: 8,
|
|
14
14
|
f32: 4,
|
|
15
15
|
f64: 8
|
|
16
|
-
},
|
|
16
|
+
}, m = 36, h = 0, g = 1, _ = 2, v = 3, y = 16, b = 0, x = 1, S = class {
|
|
17
17
|
buf;
|
|
18
18
|
start;
|
|
19
19
|
u8;
|
|
20
20
|
u32;
|
|
21
21
|
state;
|
|
22
22
|
lock;
|
|
23
|
+
lastMallocFresh = !1;
|
|
23
24
|
constructor(e = {}) {
|
|
24
|
-
if (this.buf = e.buf ? e.buf : new ArrayBuffer(e.size || 4096), this.start = e.start == null ? 0 :
|
|
25
|
+
if (this.buf = e.buf ? e.buf : new ArrayBuffer(e.size || 4096), this.start = e.start == null ? 0 : T(Math.max(e.start, 0), 4), this.u8 = new Uint8Array(this.buf), this.u32 = new Uint32Array(this.buf), this.state = new Uint32Array(this.buf, this.start, 9), this.lock = new Int32Array(this.buf, this.start + this.state.byteLength - 4, 1), !e.skipInitialization) {
|
|
25
26
|
let t = e.align || 8;
|
|
26
27
|
if (t < 8) throw Error(`invalid alignment: ${t}, must be a pow2 and >= 8`);
|
|
27
28
|
let n = this.initialTop(t), r = e.end == null ? this.buf.byteLength : Math.min(e.end, this.buf.byteLength);
|
|
28
29
|
if (n >= r) throw Error(`insufficient address range (0x${this.start.toString(16)} - 0x${r.toString(16)})`);
|
|
29
|
-
this.align = t, this.doCompact = e.compact !== !1, this.doSplit = e.split !== !1, this.minSplit = e.minSplit ||
|
|
30
|
+
this.align = t, this.doCompact = e.compact !== !1, this.doSplit = e.split !== !1, this.minSplit = e.minSplit || 32, this.end = r, this.top = n, this.highWater = n, this._free = 0, this._used = 0;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
stats() {
|
|
@@ -51,71 +52,43 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
51
52
|
}
|
|
52
53
|
callocAs(e, t, n = 0) {
|
|
53
54
|
let r = this.mallocAs(e, t);
|
|
54
|
-
return r && r.fill(n), r;
|
|
55
|
+
return r && (n !== 0 || !this.lastMallocFresh) && r.fill(n), r;
|
|
55
56
|
}
|
|
56
57
|
mallocAs(e, t) {
|
|
57
|
-
let r = this.malloc(t *
|
|
58
|
+
let r = this.malloc(t * p[e]);
|
|
58
59
|
return r ? n(e, this.buf, r, t) : void 0;
|
|
59
60
|
}
|
|
60
61
|
calloc(e, t = 0) {
|
|
61
62
|
let n = this.malloc(e);
|
|
62
|
-
return n && this.u8.fill(t, n, n + e), n;
|
|
63
|
+
return n && (t !== 0 || !this.lastMallocFresh) && this.u8.fill(t, n, n + e), n;
|
|
63
64
|
}
|
|
64
65
|
malloc(n) {
|
|
65
66
|
if (n <= 0) return 0;
|
|
66
67
|
e(this.lock);
|
|
67
|
-
let r =
|
|
68
|
-
for (;
|
|
69
|
-
let e = this.blockSize(
|
|
68
|
+
let r = T(n + 16, this.align), i = this.end, a = this.doCompact, o = a ? this.highWater : 0, s = this.top, c = this._free, l = 0;
|
|
69
|
+
for (; c;) {
|
|
70
|
+
let e = this.blockSize(c), n = c + e >= s;
|
|
70
71
|
if (n || e >= r) {
|
|
71
|
-
let i = this.mallocTop(
|
|
72
|
-
return t(this.lock), i;
|
|
72
|
+
let i = this.mallocTop(c, l, e, r, n);
|
|
73
|
+
return this.lastMallocFresh = i !== 0 && a && c >= o, a && this.top > o && (this.highWater = this.top), t(this.lock), i;
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
+
l = c, c = this.blockNext(c);
|
|
75
76
|
}
|
|
76
|
-
if (
|
|
77
|
-
this.
|
|
78
|
-
let e =
|
|
77
|
+
if (c = s, s = c + r, s <= i) {
|
|
78
|
+
this.setBlockSize(c, r), this.pushUsed(c), this.top = s, this.lastMallocFresh = !a || c >= o, a && s > o && (this.highWater = s);
|
|
79
|
+
let e = C(c);
|
|
79
80
|
return t(this.lock), e;
|
|
80
81
|
}
|
|
81
|
-
return t(this.lock), 0;
|
|
82
|
+
return this.lastMallocFresh = !1, t(this.lock), 0;
|
|
82
83
|
}
|
|
83
84
|
mallocTop(e, t, n, r, i) {
|
|
84
85
|
if (i && e + r > this.end) return 0;
|
|
85
|
-
if (t ? this.unlinkBlock(t, e) : this._free = this.blockNext(e), this.
|
|
86
|
+
if (t ? this.unlinkBlock(t, e) : this._free = this.blockNext(e), this.pushUsed(e), i) (this.doSplit || r >= n) && (this.top = e + this.setBlockSize(e, r));
|
|
86
87
|
else if (this.doSplit) {
|
|
87
88
|
let t = n - r;
|
|
88
89
|
t >= this.minSplit && this.splitBlock(e, r, t);
|
|
89
90
|
}
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
realloc(e, t) {
|
|
93
|
-
if (t <= 0) return 0;
|
|
94
|
-
let n = y(e), r = 0, i = this._used, a = 0;
|
|
95
|
-
for (; i;) {
|
|
96
|
-
if (i === n) {
|
|
97
|
-
[r, a] = this.reallocBlock(i, t);
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
i = this.blockNext(i);
|
|
101
|
-
}
|
|
102
|
-
return r && r !== n && this.u8.copyWithin(v(r), v(n), a), v(r);
|
|
103
|
-
}
|
|
104
|
-
reallocBlock(e, t) {
|
|
105
|
-
let n = this.blockSize(e), r = e + n, i = r >= this.top, a = b(t + 8, this.align);
|
|
106
|
-
if (a <= n) {
|
|
107
|
-
if (this.doSplit) {
|
|
108
|
-
let t = n - a;
|
|
109
|
-
t >= this.minSplit ? this.splitBlock(e, a, t) : i && (this.top = e + a);
|
|
110
|
-
} else i && (this.top = e + a);
|
|
111
|
-
return [e, r];
|
|
112
|
-
}
|
|
113
|
-
return i && e + a < this.end ? (this.top = e + this.setBlockSize(e, a), [e, r]) : (this.free(e), [y(this.malloc(t)), r]);
|
|
114
|
-
}
|
|
115
|
-
reallocArray(e, t) {
|
|
116
|
-
if (e.buffer !== this.buf) return;
|
|
117
|
-
let n = this.realloc(e.byteOffset, t * e.BYTES_PER_ELEMENT);
|
|
118
|
-
return n ? new e.constructor(this.buf, n, t) : void 0;
|
|
91
|
+
return C(e);
|
|
119
92
|
}
|
|
120
93
|
bytesFor(e) {
|
|
121
94
|
let t;
|
|
@@ -123,10 +96,10 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
123
96
|
if (e.buffer !== this.buf) return;
|
|
124
97
|
t = e.byteOffset;
|
|
125
98
|
} else t = e;
|
|
126
|
-
t =
|
|
99
|
+
t = w(t);
|
|
127
100
|
let n = this._used;
|
|
128
101
|
for (; n;) {
|
|
129
|
-
if (n === t) return this.blockSize(t) -
|
|
102
|
+
if (n === t) return this.blockSize(t) - 16;
|
|
130
103
|
n = this.blockNext(n);
|
|
131
104
|
}
|
|
132
105
|
}
|
|
@@ -134,22 +107,18 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
134
107
|
let t = this.bytesFor(e);
|
|
135
108
|
if (t) return t / this.u32.BYTES_PER_ELEMENT;
|
|
136
109
|
}
|
|
110
|
+
allocationLengthAt(e) {
|
|
111
|
+
return (this.blockSize(w(e)) - 16) / this.u32.BYTES_PER_ELEMENT;
|
|
112
|
+
}
|
|
137
113
|
free(n) {
|
|
138
114
|
let r;
|
|
139
115
|
if (typeof n != "number") {
|
|
140
116
|
if (n.buffer !== this.buf) return !1;
|
|
141
117
|
r = n.byteOffset;
|
|
142
118
|
} else r = n;
|
|
143
|
-
e(this.lock), r =
|
|
144
|
-
let i = this.
|
|
145
|
-
|
|
146
|
-
if (i === r) return a ? this.unlinkBlock(a, i) : this._used = this.blockNext(i), this.insert(i), this.doCompact && this.compact(), t(this.lock), !0;
|
|
147
|
-
a = i, i = this.blockNext(i);
|
|
148
|
-
}
|
|
149
|
-
return t(this.lock), !1;
|
|
150
|
-
}
|
|
151
|
-
freeAll() {
|
|
152
|
-
this._free = 0, this._used = 0, this.top = this.initialTop();
|
|
119
|
+
if (e(this.lock), r = w(r), this.blockState(r) !== x) return t(this.lock), !1;
|
|
120
|
+
let i = this.blockNext(r), a = this.blockPrev(r);
|
|
121
|
+
return a ? this.setBlockNext(a, i) : this._used = i, i && this.setBlockPrev(i, a), this.setBlockState(r, b), this.insert(r), this.doCompact && this.compact(), t(this.lock), !0;
|
|
153
122
|
}
|
|
154
123
|
release() {
|
|
155
124
|
return delete this.u8, delete this.u32, delete this.state, delete this.buf, !0;
|
|
@@ -172,6 +141,12 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
172
141
|
set top(e) {
|
|
173
142
|
Atomics.store(this.state, a, e);
|
|
174
143
|
}
|
|
144
|
+
get highWater() {
|
|
145
|
+
return Atomics.load(this.state, u);
|
|
146
|
+
}
|
|
147
|
+
set highWater(e) {
|
|
148
|
+
Atomics.store(this.state, u, e);
|
|
149
|
+
}
|
|
175
150
|
get isEmpty() {
|
|
176
151
|
return this._used === 0;
|
|
177
152
|
}
|
|
@@ -188,13 +163,13 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
188
163
|
Atomics.store(this.state, i, e);
|
|
189
164
|
}
|
|
190
165
|
get doCompact() {
|
|
191
|
-
return !!(this.state[c] &
|
|
166
|
+
return !!(this.state[c] & d);
|
|
192
167
|
}
|
|
193
168
|
set doCompact(e) {
|
|
194
169
|
e ? this.state[c] |= 1 : this.state[c] &= -2;
|
|
195
170
|
}
|
|
196
171
|
get doSplit() {
|
|
197
|
-
return !!(this.state[c] &
|
|
172
|
+
return !!(this.state[c] & f);
|
|
198
173
|
}
|
|
199
174
|
set doSplit(e) {
|
|
200
175
|
e ? this.state[c] |= 2 : this.state[c] &= -3;
|
|
@@ -203,24 +178,40 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
203
178
|
return this.state[l];
|
|
204
179
|
}
|
|
205
180
|
set minSplit(e) {
|
|
206
|
-
if (e <=
|
|
181
|
+
if (e <= 16) throw Error(`illegal min split threshold: ${e}, require at least 17`);
|
|
207
182
|
this.state[l] = e;
|
|
208
183
|
}
|
|
209
184
|
blockSize(e) {
|
|
210
|
-
return Atomics.load(this.u32, (e >> 2) +
|
|
185
|
+
return Atomics.load(this.u32, (e >> 2) + h);
|
|
211
186
|
}
|
|
212
187
|
setBlockSize(e, t) {
|
|
213
|
-
return Atomics.store(this.u32, (e >> 2) +
|
|
188
|
+
return Atomics.store(this.u32, (e >> 2) + h, t), t;
|
|
214
189
|
}
|
|
215
190
|
blockNext(e) {
|
|
216
|
-
return Atomics.load(this.u32, (e >> 2) +
|
|
191
|
+
return Atomics.load(this.u32, (e >> 2) + g);
|
|
217
192
|
}
|
|
218
193
|
setBlockNext(e, t) {
|
|
219
|
-
Atomics.store(this.u32, (e >> 2) +
|
|
194
|
+
Atomics.store(this.u32, (e >> 2) + g, t);
|
|
195
|
+
}
|
|
196
|
+
blockPrev(e) {
|
|
197
|
+
return Atomics.load(this.u32, (e >> 2) + _);
|
|
198
|
+
}
|
|
199
|
+
setBlockPrev(e, t) {
|
|
200
|
+
Atomics.store(this.u32, (e >> 2) + _, t);
|
|
201
|
+
}
|
|
202
|
+
blockState(e) {
|
|
203
|
+
return Atomics.load(this.u32, (e >> 2) + v);
|
|
204
|
+
}
|
|
205
|
+
setBlockState(e, t) {
|
|
206
|
+
Atomics.store(this.u32, (e >> 2) + v, t);
|
|
207
|
+
}
|
|
208
|
+
pushUsed(e) {
|
|
209
|
+
let t = this._used;
|
|
210
|
+
this.setBlockNext(e, t), this.setBlockPrev(e, 0), this.setBlockState(e, x), t && this.setBlockPrev(t, e), this._used = e;
|
|
220
211
|
}
|
|
221
212
|
initBlock(e, t, n) {
|
|
222
213
|
let r = e >>> 2;
|
|
223
|
-
return Atomics.store(this.u32, r +
|
|
214
|
+
return Atomics.store(this.u32, r + h, t), Atomics.store(this.u32, r + g, n), Atomics.store(this.u32, r + v, b), e;
|
|
224
215
|
}
|
|
225
216
|
unlinkBlock(e, t) {
|
|
226
217
|
this.setBlockNext(e, this.blockNext(t));
|
|
@@ -229,7 +220,7 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
229
220
|
this.insert(this.initBlock(e + this.setBlockSize(e, t), n, 0)), this.doCompact && this.compact();
|
|
230
221
|
}
|
|
231
222
|
initialTop(e = this.align) {
|
|
232
|
-
return
|
|
223
|
+
return T(this.start + 36 + 16, e) - 16;
|
|
233
224
|
}
|
|
234
225
|
compact() {
|
|
235
226
|
let e = this._free, t = 0, n = 0, r, i = !1;
|
|
@@ -250,21 +241,26 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
|
|
|
250
241
|
return i;
|
|
251
242
|
}
|
|
252
243
|
insert(e) {
|
|
244
|
+
if (!this.doCompact) {
|
|
245
|
+
this.setBlockNext(e, this._free), this._free = e;
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
253
248
|
let t = this._free, n = 0;
|
|
254
249
|
for (; t && !(e <= t);) n = t, t = this.blockNext(t);
|
|
255
250
|
n ? this.setBlockNext(n, e) : this._free = e, this.setBlockNext(e, t);
|
|
256
251
|
}
|
|
257
252
|
};
|
|
258
|
-
function
|
|
259
|
-
return e > 0 ? e +
|
|
253
|
+
function C(e) {
|
|
254
|
+
return e > 0 ? e + 16 : 0;
|
|
260
255
|
}
|
|
261
|
-
function
|
|
262
|
-
return e > 0 ? e -
|
|
256
|
+
function w(e) {
|
|
257
|
+
return e > 0 ? e - 16 : 0;
|
|
263
258
|
}
|
|
264
|
-
function
|
|
259
|
+
function T(e, t) {
|
|
265
260
|
return t--, e + t & ~t;
|
|
266
261
|
}
|
|
262
|
+
var E = T(52, 8);
|
|
267
263
|
//#endregion
|
|
268
|
-
export {
|
|
264
|
+
export { E as FIRST_BLOCK_DATA_BYTE_OFFSET, y as SIZEOF_MEM_BLOCK, m as SIZEOF_STATE, S as default };
|
|
269
265
|
|
|
270
266
|
//# sourceMappingURL=memory-buffer.js.map
|
|
@@ -1 +1 @@
|
|
|
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
|
+
{"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// Highest top ever reached. callock can skip re-zeroing it\nconst STATE_HIGH_WATER = 7;\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 = 9 * 4;\n\nconst MEM_BLOCK_SIZE = 0;\nconst MEM_BLOCK_NEXT = 1;\n// The used list is doubly linked so free() can unlink a block in O(1) instead of walking to find its predecessor.\n// MEM_BLOCK_STATE marks live blocks so free() rejects a double-free (which would otherwise splice free-list pointers\n// into the used list) without that walk. Word 3 also pads the header to 16 bytes, keeping data addresses aligned exactly\n// as the original 8-byte header did.\nconst MEM_BLOCK_PREV = 2;\nconst MEM_BLOCK_STATE = 3;\n\nconst SIZEOF_MEM_BLOCK = 4 * 4;\n\nconst BLOCK_FREE = 0;\nconst BLOCK_USED = 1;\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\t// Whether the most recent malloc came from never-before-allocated (already-zeroed) memory. Per-instance/per-thread and\n\t// read by calloc immediately after malloc under the same call, so no locking is needed.\n\tprivate lastMallocFresh = false;\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 || SIZEOF_MEM_BLOCK * 2;\n\t\t\tthis.end = resolvedEnd;\n\t\t\tthis.top = top;\n\t\t\tthis.highWater = 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\t// Fresh bump memory is already zero from the backing buffer; only fill for a non-zero value or reused (dirty) memory.\n\t\tblock && (fill !== 0 || !this.lastMallocFresh) && 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\t// Fresh bump memory is already zero from the backing buffer; only fill for a non-zero value or reused (dirty) memory.\n\t\taddr && (fill !== 0 || !this.lastMallocFresh) && 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\t// Without compaction top never retreats, so bump memory is always pristine and no high-water tracking is needed. With\n\t\t// compaction top can move back below the high-water mark, so a bump there reuses dirty memory and must be zeroed.\n\t\tconst doCompact = this.doCompact;\n\t\tconst highWater = doCompact ? this.highWater : 0;\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\t// A free-list block was previously allocated (below the high-water mark), so its memory is dirty.\n\t\t\t\tthis.lastMallocFresh = result !== 0 && doCompact && block >= highWater;\n\t\t\t\tif(doCompact && this.top > highWater) {\n\t\t\t\t\tthis.highWater = this.top;\n\t\t\t\t}\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.setBlockSize(block, paddedSize);\n\t\t\tthis.pushUsed(block);\n\t\t\tthis.top = top;\n\t\t\t// Bump allocation only ever advances into untouched memory, so it is fresh whenever it is at/above the mark.\n\t\t\tthis.lastMallocFresh = !doCompact || block >= highWater;\n\t\t\tif(doCompact && top > highWater) {\n\t\t\t\tthis.highWater = top;\n\t\t\t}\n\t\t\tlet result = blockDataAddress(block);\n\t\t\tunlock(this.lock);\n\n\t\t\treturn result;\n\t\t}\n\t\tthis.lastMallocFresh = false;\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.pushUsed(block);\n\t\tif(isTop) {\n\t\t\t// Without splitting, shrinking would expose a new block header inside stale views of the old allocation.\n\t\t\tif(this.doSplit || paddedSize >= blockSize) {\n\t\t\t\tthis.top = block + this.setBlockSize(block, paddedSize);\n\t\t\t}\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\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\tallocationLengthAt(dataAddress: number): number {\n\t\treturn (this.blockSize(blockSelfAddress(dataAddress)) - SIZEOF_MEM_BLOCK) / this.u32.BYTES_PER_ELEMENT;\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\t// Reject anything not currently live (double-free or a stray pointer) without walking the used list.\n\t\tif(this.blockState(addr) !== BLOCK_USED) {\n\t\t\tunlock(this.lock);\n\t\t\treturn false;\n\t\t}\n\t\tconst next = this.blockNext(addr);\n\t\tconst prev = this.blockPrev(addr);\n\t\tif(prev) {\n\t\t\tthis.setBlockNext(prev, next);\n\t\t} else {\n\t\t\tthis._used = next;\n\t\t}\n\t\tif(next) {\n\t\t\tthis.setBlockPrev(next, prev);\n\t\t}\n\t\tthis.setBlockState(addr, BLOCK_FREE);\n\t\tthis.insert(addr);\n\t\tthis.doCompact && this.compact();\n\n\t\tunlock(this.lock);\n\t\treturn true;\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 highWater() {\n\t\treturn Atomics.load(this.state, STATE_HIGH_WATER);\n\t}\n\n\tprotected set highWater(x: number) {\n\t\tAtomics.store(this.state, STATE_HIGH_WATER, 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\tprotected blockPrev(block: number) {\n\t\treturn Atomics.load(this.u32, (block >> 2) + MEM_BLOCK_PREV);\n\t}\n\n\tprotected setBlockPrev(block: number, prev: number) {\n\t\tAtomics.store(this.u32, (block >> 2) + MEM_BLOCK_PREV, prev);\n\t}\n\n\tprotected blockState(block: number) {\n\t\treturn Atomics.load(this.u32, (block >> 2) + MEM_BLOCK_STATE);\n\t}\n\n\tprotected setBlockState(block: number, state: number) {\n\t\tAtomics.store(this.u32, (block >> 2) + MEM_BLOCK_STATE, state);\n\t}\n\n\t// Prepend a block onto the doubly-linked used list, keeping the back-links free() relies on for O(1) removal.\n\tprotected pushUsed(block: number) {\n\t\tconst head = this._used;\n\t\tthis.setBlockNext(block, head);\n\t\tthis.setBlockPrev(block, 0);\n\t\tthis.setBlockState(block, BLOCK_USED);\n\t\tif(head) {\n\t\t\tthis.setBlockPrev(head, block);\n\t\t}\n\t\tthis._used = block;\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\t// Only used for free-list blocks (split excess); the used list is built via pushUsed which also sets prev/state.\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\tAtomics.store(this.u32, idx + MEM_BLOCK_STATE, BLOCK_FREE);\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\t// Address ordering only exists so compact() can merge neighbours; without compaction a prepend keeps free O(1).\n\t\tif(!this.doCompact) {\n\t\t\tthis.setBlockNext(block, this._free);\n\t\t\tthis._free = block;\n\t\t\treturn;\n\t\t}\n\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.\n// Byte offset of the first allocation's data in a freshly initialized buffer (default align). The heap's state block is\n// always the first allocation, so a clone can resolve it without guessing.\nconst FIRST_BLOCK_DATA_BYTE_OFFSET = align(SIZEOF_STATE + SIZEOF_MEM_BLOCK, 8);\n\nexport { SIZEOF_STATE, SIZEOF_MEM_BLOCK, FIRST_BLOCK_DATA_BYTE_OFFSET };\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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"}
|