@daneren2005/shared-memory-objects 0.0.21 → 1.1.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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +167 -167
  3. package/dist/allocated-memory.js +38 -0
  4. package/dist/allocated-memory.js.map +1 -0
  5. package/dist/cached-item-list.js +76 -0
  6. package/dist/cached-item-list.js.map +1 -0
  7. package/dist/interfaces/pow2.js +2 -0
  8. package/dist/interfaces/pow2.js.map +1 -0
  9. package/dist/interfaces/typed-array-constructor.js +2 -0
  10. package/dist/interfaces/typed-array-constructor.js.map +1 -0
  11. package/dist/interfaces/typed-array.js +2 -0
  12. package/dist/interfaces/typed-array.js.map +1 -0
  13. package/dist/local-pool.js +95 -0
  14. package/dist/local-pool.js.map +1 -0
  15. package/dist/lock/read-write-lock.js +25 -0
  16. package/dist/lock/read-write-lock.js.map +1 -0
  17. package/dist/lock/simple-lock.js +14 -0
  18. package/dist/lock/simple-lock.js.map +1 -0
  19. package/dist/memory-buffer.js +327 -0
  20. package/dist/memory-buffer.js.map +1 -0
  21. package/dist/memory-heap.js +116 -0
  22. package/dist/memory-heap.js.map +1 -0
  23. package/dist/serialize-object.js +59 -0
  24. package/dist/serialize-object.js.map +1 -0
  25. package/dist/shared-list.js +165 -0
  26. package/dist/shared-list.js.map +1 -0
  27. package/dist/shared-map.js +140 -0
  28. package/dist/shared-map.js.map +1 -0
  29. package/dist/shared-pointer-list.js +50 -0
  30. package/dist/shared-pointer-list.js.map +1 -0
  31. package/dist/shared-pool.js +165 -0
  32. package/dist/shared-pool.js.map +1 -0
  33. package/dist/shared-string.js +79 -0
  34. package/dist/shared-string.js.map +1 -0
  35. package/dist/shared-vector.js +165 -0
  36. package/dist/shared-vector.js.map +1 -0
  37. package/dist/src/memory-heap.d.ts +0 -1
  38. package/dist/src/utils/atomic-math.d.ts +4 -4
  39. package/dist/src/utils/typedarray.d.ts +278 -278
  40. package/dist/utils/16-from-32-array.js +20 -0
  41. package/dist/utils/16-from-32-array.js.map +1 -0
  42. package/dist/utils/16-from-64-array.js +12 -0
  43. package/dist/utils/16-from-64-array.js.map +1 -0
  44. package/dist/utils/atomic-math.js +36 -0
  45. package/dist/utils/atomic-math.js.map +1 -0
  46. package/dist/utils/float32-atomics.js +28 -0
  47. package/dist/utils/float32-atomics.js.map +1 -0
  48. package/dist/utils/float64-atomics.js +28 -0
  49. package/dist/utils/float64-atomics.js.map +1 -0
  50. package/dist/utils/pointer.js +44 -0
  51. package/dist/utils/pointer.js.map +1 -0
  52. package/dist/utils/typedarray.js +46 -0
  53. package/dist/utils/typedarray.js.map +1 -0
  54. package/package.json +65 -72
  55. package/dist/shared-memory-objects.js +0 -1674
  56. package/dist/shared-memory-objects.js.map +0 -1
  57. package/dist/shared-memory-objects.umd.cjs +0 -2
  58. package/dist/shared-memory-objects.umd.cjs.map +0 -1
  59. package/dist/src/main.d.ts +0 -22
@@ -0,0 +1,165 @@
1
+ import d from "./allocated-memory.js";
2
+ import { loadRawPointer as h, replaceRawPointer as k, getPointer as y, storeRawPointer as b, loadPointer as c, storePointer as A } from "./utils/pointer.js";
3
+ const P = 4, w = 1, n = 2;
4
+ class p {
5
+ static ALLOCATE_COUNT = P;
6
+ memory;
7
+ /* First block
8
+ 32 index 0
9
+ uint16 0 - next buffer position
10
+ uint16 1 - next buffer index
11
+ 32 index 1
12
+ uint16 2 - last buffer position
13
+ uint16 3 - last buffer index
14
+ 32 index 2
15
+ uint32 4 - length
16
+ 32 index 3
17
+ uint16 6 - type
18
+ uint16 7 - data length (defaults to 1 number per data)
19
+ */
20
+ /* Other blocks
21
+ 32 index 0
22
+ uint16 0 - next buffer position
23
+ uint16 1 - next buffer index
24
+ 32 index 1 => data
25
+ */
26
+ firstBlock;
27
+ uint16Array;
28
+ onDelete;
29
+ get length() {
30
+ return Atomics.load(this.firstBlock.data, n);
31
+ }
32
+ get type() {
33
+ return Atomics.load(this.uint16Array, 0);
34
+ }
35
+ set type(t) {
36
+ Atomics.store(this.uint16Array, 0, t);
37
+ }
38
+ get dataLength() {
39
+ return Math.max(1, Atomics.load(this.uint16Array, 1));
40
+ }
41
+ set dataLength(t) {
42
+ Atomics.store(this.uint16Array, 1, t);
43
+ }
44
+ constructor(t, e) {
45
+ if (this.memory = t, e && "firstBlock" in e)
46
+ this.firstBlock = new d(t, e.firstBlock), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + (n + 1) * Uint32Array.BYTES_PER_ELEMENT, 2);
47
+ else {
48
+ e && e.initWithBlock ? this.firstBlock = new d(t, e.initWithBlock) : this.firstBlock = t.allocUI32(P), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + (n + 1) * Uint32Array.BYTES_PER_ELEMENT, 2);
49
+ const r = e?.type ?? Uint32Array;
50
+ r === Uint32Array ? this.type = 0 : r === Int32Array ? this.type = 1 : r === Float32Array && (this.type = 2), this.dataLength = e?.dataLength ?? 1;
51
+ }
52
+ }
53
+ insert(t) {
54
+ typeof t == "number" && (t = [t]);
55
+ let e = this.dataLength;
56
+ if (t.length > e)
57
+ throw new Error(`Can't insert ${t.length} array into shared list of ${e} dataLength`);
58
+ let r = this.memory.allocUI32(w + e), s = this.getDataBlock(r.data), o = r.pointer;
59
+ for (let i = 0; i < t.length; i++)
60
+ s instanceof Int32Array || s instanceof Uint32Array ? Atomics.store(s, i, t[i]) : s[i] = t[i];
61
+ let a, f = !1;
62
+ for (; !f; )
63
+ a = h(this.firstBlock.data, 1), f = k(this.firstBlock.data, 1, o, a);
64
+ if (a) {
65
+ let { bufferPosition: i, bufferByteOffset: l } = y(a), B = new Uint32Array(this.memory.buffers[i].buf, l, 1);
66
+ b(B, 0, o);
67
+ } else
68
+ b(this.firstBlock.data, 0, o);
69
+ Atomics.add(this.firstBlock.data, n, 1);
70
+ }
71
+ deleteMatch(t) {
72
+ for (let { data: e, index: r, deleteCurrent: s } of this)
73
+ if (t(e, r))
74
+ return s(), !0;
75
+ return !1;
76
+ }
77
+ deleteIndex(t) {
78
+ return t >= this.length || t < 0 ? !1 : this.deleteMatch((e, r) => r === t);
79
+ }
80
+ deleteValue(t) {
81
+ return typeof t == "number" ? this.deleteMatch((e) => e[0] === t) : this.deleteMatch((e) => {
82
+ if (e.length !== t.length)
83
+ return !1;
84
+ for (let r = 0; r < e.length; r++)
85
+ if (e[r] !== t[r])
86
+ return !1;
87
+ return !0;
88
+ });
89
+ }
90
+ clear() {
91
+ let t, e, r = !1;
92
+ for (; !r; ) {
93
+ if (t = h(this.firstBlock.data, 0), e = h(this.firstBlock.data, 1), !e)
94
+ return;
95
+ r = k(this.firstBlock.data, 1, 0, e);
96
+ }
97
+ if (!t)
98
+ return;
99
+ k(this.firstBlock.data, 0, 0, t);
100
+ let s = 0, o = t;
101
+ for (; o; ) {
102
+ let { bufferPosition: a, bufferByteOffset: f } = y(o), i = this.memory.buffers[a];
103
+ if (!i)
104
+ break;
105
+ let l = new Uint32Array(i.buf, f, 2);
106
+ o = h(l, 0), s++, this.onDelete && this.onDelete(this.getDataBlock(l)), i.free(l.byteOffset);
107
+ }
108
+ Atomics.sub(this.firstBlock.data, n, s);
109
+ }
110
+ *[Symbol.iterator]() {
111
+ let t = 0, { bufferPosition: e, bufferByteOffset: r } = c(this.firstBlock.data, 0), s = this.firstBlock.data, o = 0, a = 0;
112
+ for (; r; ) {
113
+ let f = this.memory.buffers[e];
114
+ if (!f)
115
+ return;
116
+ let i = new Uint32Array(f.buf, r, 2), l = this.getDataBlock(i), B = e, E = r;
117
+ ({ bufferPosition: e, bufferByteOffset: r } = c(i, 0));
118
+ let u = !0;
119
+ yield {
120
+ data: l,
121
+ index: t,
122
+ deleteCurrent: () => {
123
+ A(s, 0, e, r), r || A(this.firstBlock.data, 1, o, a), this.onDelete && this.onDelete(this.getDataBlock(i)), f.free(i.byteOffset), Atomics.sub(this.firstBlock.data, n, 1), u = !1;
124
+ }
125
+ }, u && (s = i, o = B, a = E, t++);
126
+ }
127
+ }
128
+ forEach(t) {
129
+ for (let e of this)
130
+ t(e.data);
131
+ }
132
+ getSharedMemory() {
133
+ return {
134
+ firstBlock: this.firstBlock.getSharedMemory()
135
+ };
136
+ }
137
+ getDataBlock(t) {
138
+ const e = t.byteOffset + w * t.BYTES_PER_ELEMENT;
139
+ switch (this.type) {
140
+ case 1:
141
+ return new Int32Array(t.buffer, e, this.dataLength);
142
+ case 0:
143
+ return new Uint32Array(t.buffer, e, this.dataLength);
144
+ case 2:
145
+ return new Float32Array(t.buffer, e, this.dataLength);
146
+ default:
147
+ throw new Error(`Unknown data block type ${this.type}`);
148
+ }
149
+ }
150
+ free() {
151
+ let { bufferPosition: t, bufferByteOffset: e } = c(this.firstBlock.data, 0);
152
+ for (; e; ) {
153
+ let r = new d(this.memory, {
154
+ bufferPosition: t,
155
+ bufferByteOffset: e
156
+ });
157
+ ({ bufferPosition: t, bufferByteOffset: e } = c(r.data, 0)), this.onDelete && this.onDelete(this.getDataBlock(r.data)), r.free();
158
+ }
159
+ this.firstBlock.free();
160
+ }
161
+ }
162
+ export {
163
+ p as default
164
+ };
165
+ //# sourceMappingURL=shared-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-list.js","sources":["../src/shared-list.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport type { TypedArrayConstructor } from './interfaces/typed-array-constructor';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer, loadPointer, loadRawPointer, replaceRawPointer, storePointer, storeRawPointer } from './utils/pointer';\n\nenum TYPE {\n\tuint32,\n\tint32,\n\tfloat32\n}\n\n// TODO: We need some sort of locking on insert/deletes!\nconst FIRST_BLOCK_RECORD_KEEPING_COUNT = 4;\nconst DATA_BLOCK_RECORD_KEEPING_COUNT = 1;\nconst LENGTH_INDEX = 2;\nexport default class SharedList<T extends Uint32Array | Int32Array | Float32Array = Uint32Array> implements Iterable<SharedListIterable<T>> {\n\tstatic readonly ALLOCATE_COUNT = FIRST_BLOCK_RECORD_KEEPING_COUNT;\n\n\tprivate memory: MemoryHeap;\n\t/* First block\n\t\t32 index 0\n\t\tuint16 0 - next buffer position\n\t\tuint16 1 - next buffer index\n\t\t32 index 1\n\t\tuint16 2 - last buffer position\n\t\tuint16 3 - last buffer index\n\t\t32 index 2\n\t\tuint32 4 - length\n\t\t32 index 3\n\t\tuint16 6 - type\n\t\tuint16 7 - data length (defaults to 1 number per data)\n\t*/\n\t/* Other blocks\n\t\t32 index 0\n\t\tuint16 0 - next buffer position\n\t\tuint16 1 - next buffer index\n\t\t32 index 1 => data\n\t*/\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\tonDelete?: (data: T) => void;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t}\n\t\n\tget type(): number {\n\t\treturn Atomics.load(this.uint16Array, 0);\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget dataLength(): number {\n\t\t// Can technically be initialized by passing memory without actually every being called - need to make sure dataLength is always at least one\n\t\treturn Math.max(1, Atomics.load(this.uint16Array, 1));\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedListConfig<T> | SharedListMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\t// TODO: How to handle referencing memory we don't have access to yet because buffer not synced from worker?\n\t\t\tthis.firstBlock = new AllocatedMemory(memory, config.firstBlock);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + (LENGTH_INDEX + 1) * Uint32Array.BYTES_PER_ELEMENT, 2);\n\t\t} else {\n\t\t\tif(config && config.initWithBlock) {\n\t\t\t\tthis.firstBlock = new AllocatedMemory(memory, config.initWithBlock);\n\t\t\t} else {\n\t\t\t\tthis.firstBlock = memory.allocUI32(FIRST_BLOCK_RECORD_KEEPING_COUNT);\n\t\t\t}\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + (LENGTH_INDEX + 1) * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\tconst type = config?.type ?? Uint32Array;\n\t\t\tif(type === Uint32Array) {\n\t\t\t\tthis.type = TYPE.uint32;\n\t\t\t}\n\t\t\t// @ts-expect-error\n\t\t\telse if(type === Int32Array) {\n\t\t\t\tthis.type = TYPE.int32;\n\t\t\t}\n\t\t\t// @ts-expect-error\n\t\t\telse if(type === Float32Array) {\n\t\t\t\tthis.type = TYPE.float32;\n\t\t\t}\n\t\t\tthis.dataLength = config?.dataLength ?? 1;\n\t\t}\n\t}\n\n\tinsert(values: number | Array<number>) {\n\t\tif(typeof values === 'number') {\n\t\t\tvalues = [values];\n\t\t}\n\n\t\tlet dataLength = this.dataLength;\n\t\tif(values.length > dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${dataLength} dataLength`);\n\t\t}\n\t\tlet newBlock = this.memory.allocUI32(DATA_BLOCK_RECORD_KEEPING_COUNT + dataLength);\n\t\tlet newData = this.getDataBlock(newBlock.data);\n\t\tlet newBlockPointer = newBlock.pointer;\n\t\t\n\t\tfor(let i = 0; i < values.length; i++) {\n\t\t\tif(newData instanceof Int32Array || newData instanceof Uint32Array) {\n\t\t\t\tAtomics.store(newData, i, values[i]);\n\t\t\t} else {\n\t\t\t\t// TODO: Should we replace with pass thru float32 conversion -> store?\n\t\t\t\tnewData[i] = values[i];\n\t\t\t}\n\t\t}\n\n\t\tlet lastBlockPointer;\n\t\tlet updateWorked = false;\n\t\twhile(!updateWorked) {\n\t\t\tlastBlockPointer = loadRawPointer(this.firstBlock.data, 1);\n\t\t\tupdateWorked = replaceRawPointer(this.firstBlock.data, 1, newBlockPointer, lastBlockPointer);\n\t\t}\n\n\t\tif(lastBlockPointer) {\n\t\t\tlet { bufferPosition: lastBlockPosition, bufferByteOffset: lastBlockByteOffset } = getPointer(lastBlockPointer);\n\t\t\t// TODO: How to handle referencing memory we don't have access to yet because buffer not synced from worker?\n\t\t\tlet lastBlock = new Uint32Array(this.memory.buffers[lastBlockPosition].buf, lastBlockByteOffset, 1);\n\t\t\tstoreRawPointer(lastBlock, 0, newBlockPointer);\n\t\t} else {\n\t\t\t// First item - store on first block\n\t\t\tstoreRawPointer(this.firstBlock.data, 0, newBlockPointer);\n\t\t}\n\t\t\n\t\t// Always update new last buffer position and length\n\t\tAtomics.add(this.firstBlock.data, LENGTH_INDEX, 1);\n\t}\n\n\tdeleteMatch(callback: (values: T, index: number) => boolean): boolean {\n\t\tfor(let { data, index, deleteCurrent } of this) {\n\t\t\tif(callback(data, index)) {\n\t\t\t\tdeleteCurrent();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\tdeleteIndex(deleteIndex: number): boolean {\n\t\tif(deleteIndex >= this.length || deleteIndex < 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.deleteMatch((values, index) => index === deleteIndex);\n\t}\n\tdeleteValue(deleteValues: number | Array<number>) {\n\t\tif(typeof deleteValues === 'number') {\n\t\t\treturn this.deleteMatch(values => values[0] === deleteValues);\n\t\t} else {\n\t\t\treturn this.deleteMatch(values => {\n\t\t\t\tif(values.length !== deleteValues.length) {\n\t\t\t\t\treturn false;\n\t\t\t\t} else {\n\t\t\t\t\tfor(let i = 0; i < values.length; i++) {\n\t\t\t\t\t\tif(values[i] !== deleteValues[i]) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tclear() {\n\t\tlet firstBlockPointer, lastBlockPointer;\n\t\tlet updateWorked = false;\n\t\twhile(!updateWorked) {\n\t\t\tfirstBlockPointer = loadRawPointer(this.firstBlock.data, 0);\n\t\t\tlastBlockPointer = loadRawPointer(this.firstBlock.data, 1);\n\t\t\t// Already cleared\n\t\t\tif(!lastBlockPointer) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tupdateWorked = replaceRawPointer(this.firstBlock.data, 1, 0, lastBlockPointer);\n\t\t}\n\t\t\n\t\t// Shouldn't be possible to hit: making Typescript happy\n\t\tif(!firstBlockPointer) {\n\t\t\treturn;\n\t\t}\n\n\t\t// We only want to update the last block if this is ran before something new was inserted\n\t\treplaceRawPointer(this.firstBlock.data, 0, 0, firstBlockPointer);\n\n\t\t// Iterate through inaccessible nodes and delete them\n\t\tlet deletedItems = 0;\n\t\tlet nextBlockPointer = firstBlockPointer;\n\t\twhile(nextBlockPointer) {\n\t\t\tlet { bufferPosition: nextBlockPosition, bufferByteOffset: nextBlockByteOffset } = getPointer(nextBlockPointer);\n\t\t\tlet memPool = this.memory.buffers[nextBlockPosition];\n\t\t\t// Short circuit iterations if we can't access memory\n\t\t\tif(!memPool) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlet blockRecord = new Uint32Array(memPool.buf, nextBlockByteOffset, 2);\n\t\t\tnextBlockPointer = loadRawPointer(blockRecord, 0);\n\t\t\tdeletedItems++;\n\n\t\t\tif(this.onDelete) {\n\t\t\t\tthis.onDelete(this.getDataBlock(blockRecord));\n\t\t\t}\n\n\t\t\tmemPool.free(blockRecord.byteOffset);\n\t\t}\n\t\t\n\t\t// Subtract by however many we deleted so that a insert during this operation is accurate\n\t\tAtomics.sub(this.firstBlock.data, LENGTH_INDEX, deletedItems);\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tlet currentIndex = 0;\n\t\tlet { bufferPosition: nextBlockPosition, bufferByteOffset: nextBlockByteOffset } = loadPointer(this.firstBlock.data, 0);\n\t\tlet lastBlockData = this.firstBlock.data;\n\t\tlet lastBlockPosition = 0;\n\t\tlet lastBlockByteOffset = 0;\n\t\twhile(nextBlockByteOffset) {\n\t\t\tlet memPool = this.memory.buffers[nextBlockPosition];\n\t\t\t// Short circuit iterations if we can't access memory\n\t\t\tif(!memPool) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet blockRecord = new Uint32Array(memPool.buf, nextBlockByteOffset, 2);\n\t\t\tlet blockData = this.getDataBlock(blockRecord);\n\n\t\t\tlet currentBlockPosition = nextBlockPosition;\n\t\t\tlet currentBlockByteOffset = nextBlockByteOffset;\n\t\t\t({ bufferPosition: nextBlockPosition, bufferByteOffset: nextBlockByteOffset } = loadPointer(blockRecord, 0));\n\n\t\t\tlet updateLastBlock = true;\n\t\t\tyield {\n\t\t\t\tdata: blockData,\n\t\t\t\tindex: currentIndex,\n\t\t\t\tdeleteCurrent: () => {\n\t\t\t\t\t// Move previous index to point to one after\n\t\t\t\t\tstorePointer(lastBlockData, 0, nextBlockPosition, nextBlockByteOffset);\n\n\t\t\t\t\t// If this is the last item, update last block to be previous location\n\t\t\t\t\tif(!nextBlockByteOffset) {\n\t\t\t\t\t\tstorePointer(this.firstBlock.data, 1, lastBlockPosition, lastBlockByteOffset);\n\t\t\t\t\t}\n\n\t\t\t\t\tif(this.onDelete) {\n\t\t\t\t\t\tthis.onDelete(this.getDataBlock(blockRecord));\n\t\t\t\t\t}\n\n\t\t\t\t\tmemPool.free(blockRecord.byteOffset);\n\t\t\t\t\tAtomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\t\t\t\tupdateLastBlock = false;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tif(updateLastBlock) {\n\t\t\t\tlastBlockData = blockRecord;\n\t\t\t\tlastBlockPosition = currentBlockPosition;\n\t\t\t\tlastBlockByteOffset = currentBlockByteOffset;\n\t\t\t\tcurrentIndex++;\n\t\t\t}\n\t\t}\n\t}\n\n\tforEach(callback: (data: T) => void) {\n\t\tfor(let value of this) {\n\t\t\tcallback(value.data);\n\t\t}\n\t}\n\n\tgetSharedMemory(): SharedListMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory()\n\t\t};\n\t}\n\n\tprivate getDataBlock(memory: Uint32Array): T {\n\t\tconst startIndex = memory.byteOffset + DATA_BLOCK_RECORD_KEEPING_COUNT * memory.BYTES_PER_ELEMENT;\n\n\t\tswitch(this.type) {\n\t\t\tcase TYPE.int32:\n\t\t\t\treturn new Int32Array(memory.buffer, startIndex, this.dataLength) as T;\n\t\t\tcase TYPE.uint32:\n\t\t\t\treturn new Uint32Array(memory.buffer, startIndex, this.dataLength) as T;\n\t\t\tcase TYPE.float32:\n\t\t\t\treturn new Float32Array(memory.buffer, startIndex, this.dataLength) as T;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown data block type ${this.type}`);\n\t\t}\n\t}\n\n\tfree() {\n\t\tlet { bufferPosition: nextBlockPosition, bufferByteOffset: nextBlockByteOffset } = loadPointer(this.firstBlock.data, 0);\n\t\twhile(nextBlockByteOffset) {\n\t\t\tlet allocatedMemory = new AllocatedMemory(this.memory, {\n\t\t\t\tbufferPosition: nextBlockPosition,\n\t\t\t\tbufferByteOffset: nextBlockByteOffset\n\t\t\t});\n\n\t\t\t({ bufferPosition: nextBlockPosition, bufferByteOffset: nextBlockByteOffset } = loadPointer(allocatedMemory.data, 0));\n\n\t\t\tif(this.onDelete) {\n\t\t\t\tthis.onDelete(this.getDataBlock(allocatedMemory.data));\n\t\t\t}\n\n\t\t\tallocatedMemory.free();\n\t\t}\n\n\t\tthis.firstBlock.free();\n\t}\n}\n\ninterface SharedListConfig<T extends Uint32Array | Int32Array | Float32Array> {\n\tinitWithBlock?: SharedAllocatedMemory\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n}\ninterface SharedListMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\ninterface SharedListIterable<T extends Uint32Array | Int32Array | Float32Array> {\n\tdata: T\n\tindex: number\n\tdeleteCurrent: () => void\n}\n\nexport { type SharedListMemory };"],"names":["FIRST_BLOCK_RECORD_KEEPING_COUNT","DATA_BLOCK_RECORD_KEEPING_COUNT","LENGTH_INDEX","SharedList","value","memory","config","AllocatedMemory","type","values","dataLength","newBlock","newData","newBlockPointer","lastBlockPointer","updateWorked","loadRawPointer","replaceRawPointer","lastBlockPosition","lastBlockByteOffset","getPointer","lastBlock","storeRawPointer","callback","data","index","deleteCurrent","deleteIndex","deleteValues","i","firstBlockPointer","deletedItems","nextBlockPointer","nextBlockPosition","nextBlockByteOffset","memPool","blockRecord","currentIndex","loadPointer","lastBlockData","blockData","currentBlockPosition","currentBlockByteOffset","updateLastBlock","storePointer","startIndex","allocatedMemory"],"mappings":"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"}
@@ -0,0 +1,140 @@
1
+ import u from "./allocated-memory.js";
2
+ import f from "./shared-list.js";
3
+ import { loadPointer as l, storePointer as y } from "./utils/pointer.js";
4
+ const c = 10;
5
+ class M {
6
+ static ALLOCATE_COUNT = 4;
7
+ memory;
8
+ // Memory order: Pointer, Lock, Length, MaxHash
9
+ pointerMemory;
10
+ lock;
11
+ get hashMemory() {
12
+ return new u(this.memory, l(this.pointerMemory.data, 0));
13
+ }
14
+ get length() {
15
+ return Atomics.load(this.pointerMemory.data, 2);
16
+ }
17
+ get maxHash() {
18
+ return Atomics.load(this.pointerMemory.data, 3);
19
+ }
20
+ constructor(t, e) {
21
+ if (this.memory = t, e)
22
+ this.pointerMemory = new u(t, e.firstBlock);
23
+ else {
24
+ this.pointerMemory = t.allocUI32(M.ALLOCATE_COUNT);
25
+ let r = t.allocUI32(c);
26
+ y(this.pointerMemory.data, 0, r.bufferPosition, r.bufferByteOffset), Atomics.store(this.pointerMemory.data, 3, c);
27
+ }
28
+ this.lock = new Int32Array(this.pointerMemory.data.buffer, this.pointerMemory.bufferByteOffset + Uint32Array.BYTES_PER_ELEMENT, 1);
29
+ }
30
+ set(t, e) {
31
+ this.length >= this.maxHash * 2 && this.growHashTable();
32
+ let r = m(t);
33
+ this.setHashKey(this.hashMemory, this.maxHash, r, e) && Atomics.add(this.pointerMemory.data, 2, 1);
34
+ }
35
+ setHashKey(t, e, r, s) {
36
+ let a = this.hash(r, e), i, h = l(t.data, a);
37
+ if (h.bufferByteOffset === 0) {
38
+ i = new f(this.memory, {
39
+ dataLength: 2
40
+ });
41
+ let d = i.getSharedMemory();
42
+ y(t.data, a, d.firstBlock.bufferPosition, d.firstBlock.bufferByteOffset);
43
+ } else
44
+ i = new f(this.memory, {
45
+ firstBlock: h
46
+ });
47
+ let n = !0;
48
+ return i.deleteValue(r) && (n = !1), i.insert([r, s]), n;
49
+ }
50
+ get(t) {
51
+ let e = m(t), r = this.hash(e, this.maxHash), s = l(this.hashMemory.data, r);
52
+ if (s.bufferByteOffset === 0)
53
+ return;
54
+ let a = new f(this.memory, {
55
+ firstBlock: s
56
+ });
57
+ for (let { data: i } of a)
58
+ if (i[0] === e)
59
+ return i[1];
60
+ }
61
+ has(t) {
62
+ let e = m(t), r = this.hash(e, this.maxHash), s = l(this.hashMemory.data, r);
63
+ if (s.bufferByteOffset === 0)
64
+ return !1;
65
+ let a = new f(this.memory, {
66
+ firstBlock: s
67
+ });
68
+ for (let { data: i } of a)
69
+ if (i[0] === e)
70
+ return !0;
71
+ return !1;
72
+ }
73
+ delete(t) {
74
+ let e = m(t), r = this.hash(e, this.maxHash), s = l(this.hashMemory.data, r);
75
+ if (s.bufferByteOffset === 0)
76
+ return !1;
77
+ let a = new f(this.memory, {
78
+ firstBlock: s
79
+ });
80
+ for (let { data: i, deleteCurrent: h } of a)
81
+ if (i[0] === e)
82
+ return h(), Atomics.sub(this.pointerMemory.data, 2, 1), !0;
83
+ return !1;
84
+ }
85
+ growHashTable() {
86
+ let t = this.maxHash, e = t * 2, r = this.memory.allocUI32(e), s = this.hashMemory;
87
+ for (let a = 0; a < t; a++) {
88
+ let i = l(s.data, a);
89
+ if (i.bufferByteOffset === 0)
90
+ continue;
91
+ let h = new f(this.memory, {
92
+ firstBlock: i
93
+ });
94
+ for (let { data: n } of h)
95
+ this.setHashKey(r, e, n[0], n[1]);
96
+ h.free();
97
+ }
98
+ y(this.pointerMemory.data, 0, r.bufferPosition, r.bufferByteOffset), Atomics.store(this.pointerMemory.data, 3, e), s.free();
99
+ }
100
+ hash(t, e) {
101
+ return t % e;
102
+ }
103
+ free() {
104
+ for (let t = 0; t < this.maxHash; t++) {
105
+ let e = l(this.hashMemory.data, t);
106
+ if (e.bufferByteOffset === 0)
107
+ continue;
108
+ new f(this.memory, {
109
+ firstBlock: e
110
+ }).free();
111
+ }
112
+ this.hashMemory.free(), this.pointerMemory.free();
113
+ }
114
+ getSharedMemory() {
115
+ return {
116
+ firstBlock: this.pointerMemory.getSharedMemory()
117
+ };
118
+ }
119
+ }
120
+ function m(o) {
121
+ return typeof o == "number" ? o : typeof o == "string" ? p(o) : o;
122
+ }
123
+ function p(o) {
124
+ let t = o.length, e = 17 ^ t, r = 0, s;
125
+ for (; t >= 4; )
126
+ s = o.charCodeAt(r) & 255 | (o.charCodeAt(++r) & 255) << 8 | (o.charCodeAt(++r) & 255) << 16 | (o.charCodeAt(++r) & 255) << 14, s = (s & 65535) * 1540483477 + (((s >>> 16) * 1540483477 & 65535) << 16), s ^= s >>> 14, s = (s & 65535) * 1540483477 + (((s >>> 16) * 1540483477 & 65535) << 16), e = (e & 65535) * 1540483477 + (((e >>> 16) * 1540483477 & 65535) << 16) ^ s, t -= 4, ++r;
127
+ switch (t) {
128
+ case 3:
129
+ e ^= (o.charCodeAt(r + 2) & 255) << 16;
130
+ case 2:
131
+ e ^= (o.charCodeAt(r + 1) & 255) << 8;
132
+ case 1:
133
+ e ^= o.charCodeAt(r) & 255, e = (e & 65535) * 1540483477 + (((e >>> 16) * 1540483477 & 65535) << 16);
134
+ }
135
+ return e ^= e >>> 13, e = (e & 65535) * 1540483477 + (((e >>> 16) * 1540483477 & 65535) << 16), e ^= e >>> 15, e = e >>> 0, e;
136
+ }
137
+ export {
138
+ M as default
139
+ };
140
+ //# sourceMappingURL=shared-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-map.js","sources":["../src/shared-map.ts"],"sourcesContent":["import AllocatedMemory, { type SharedAllocatedMemory } from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport SharedList from './shared-list';\nimport { loadPointer, storePointer } from './utils/pointer';\n\n// TODO: Grow hashMemory\n// TODO: Add iterator\n// TODO: Add read/write locks\nconst DEFAULT_HASH_SIZE = 10;\nexport default class SharedMap<K extends string | number> {\n\tstatic readonly ALLOCATE_COUNT = 4;\n\n\tprivate memory: MemoryHeap;\n\t// Memory order: Pointer, Lock, Length, MaxHash\n\tprivate pointerMemory: AllocatedMemory;\n\tprivate lock: Int32Array;\n\tprivate get hashMemory(): AllocatedMemory {\n\t\treturn new AllocatedMemory(this.memory, loadPointer(this.pointerMemory.data, 0));\n\t}\n\n\tget length(): number {\n\t\treturn Atomics.load(this.pointerMemory.data, 2);\n\t}\n\tget maxHash(): number {\n\t\treturn Atomics.load(this.pointerMemory.data, 3);\n\t}\n\n\tconstructor(memory: MemoryHeap, clone?: SharedMapMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(clone) {\n\t\t\tthis.pointerMemory = new AllocatedMemory(memory, clone.firstBlock);\n\t\t} else {\n\t\t\tthis.pointerMemory = memory.allocUI32(SharedMap.ALLOCATE_COUNT);\n\t\t\tlet hashMemory = memory.allocUI32(DEFAULT_HASH_SIZE);\n\t\t\tstorePointer(this.pointerMemory.data, 0, hashMemory.bufferPosition, hashMemory.bufferByteOffset);\n\t\t\tAtomics.store(this.pointerMemory.data, 3, DEFAULT_HASH_SIZE);\n\t\t}\n\t\tthis.lock = new Int32Array(this.pointerMemory.data.buffer, this.pointerMemory.bufferByteOffset + Uint32Array.BYTES_PER_ELEMENT, 1);\n\t}\n\n\tset(key: K, value: number) {\n\t\tif(this.length >= this.maxHash * 2) {\n\t\t\tthis.growHashTable();\n\t\t}\n\n\t\tlet fullHashKey = get32BitHash(key);\n\t\tif(this.setHashKey(this.hashMemory, this.maxHash, fullHashKey, value)) {\n\t\t\tAtomics.add(this.pointerMemory.data, 2, 1);\n\t\t}\n\t}\n\tprivate setHashKey(hashMemory: AllocatedMemory, maxHash: number, fullHashKey: number, value: number) {\n\t\tlet hashKey = this.hash(fullHashKey, maxHash);\n\t\t\n\t\tlet list: SharedList;\n\t\tlet pointer = loadPointer(hashMemory.data, hashKey);\n\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\t// Initialize a list here\n\t\t\tlist = new SharedList(this.memory, {\n\t\t\t\tdataLength: 2\n\t\t\t});\n\n\t\t\tlet listMemory = list.getSharedMemory();\n\t\t\tstorePointer(hashMemory.data, hashKey, listMemory.firstBlock.bufferPosition, listMemory.firstBlock.bufferByteOffset);\n\t\t} else {\n\t\t\tlist = new SharedList(this.memory, {\n\t\t\t\tfirstBlock: pointer\n\t\t\t});\n\t\t}\n\n\t\t// Check if any other items in list have the same key and delete them\n\t\tlet inserted = true;\n\t\tif(list.deleteValue(fullHashKey)) {\n\t\t\tinserted = false;\n\t\t}\n\t\tlist.insert([fullHashKey, value]);\n\t\t\n\t\treturn inserted;\n\t}\n\n\tget(key: K): number | undefined {\n\t\tlet fullHashKey = get32BitHash(key);\n\t\tlet hashKey = this.hash(fullHashKey, this.maxHash);\n\n\t\tlet pointer = loadPointer(this.hashMemory.data, hashKey);\n\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet list = new SharedList(this.memory, {\n\t\t\tfirstBlock: pointer\n\t\t});\n\n\t\tfor(let { data } of list) {\n\t\t\tif(data[0] === fullHashKey) {\n\t\t\t\treturn data[1];\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\thas(key: K): boolean {\n\t\tlet fullHashKey = get32BitHash(key);\n\t\tlet hashKey = this.hash(fullHashKey, this.maxHash);\n\n\t\tlet pointer = loadPointer(this.hashMemory.data, hashKey);\n\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet list = new SharedList(this.memory, {\n\t\t\tfirstBlock: pointer\n\t\t});\n\n\t\tfor(let { data } of list) {\n\t\t\tif(data[0] === fullHashKey) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tdelete(key: K): boolean {\n\t\tlet fullHashKey = get32BitHash(key);\n\t\tlet hashKey = this.hash(fullHashKey, this.maxHash);\n\n\t\tlet pointer = loadPointer(this.hashMemory.data, hashKey);\n\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet list = new SharedList(this.memory, {\n\t\t\tfirstBlock: pointer\n\t\t});\n\n\t\tfor(let { data, deleteCurrent } of list) {\n\t\t\tif(data[0] === fullHashKey) {\n\t\t\t\tdeleteCurrent();\n\n\t\t\t\tAtomics.sub(this.pointerMemory.data, 2, 1);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate growHashTable() {\n\t\tlet oldMaxHash = this.maxHash;\n\t\tlet newMaxHash = oldMaxHash * 2;\n\t\tlet newHashMemory = this.memory.allocUI32(newMaxHash);\n\t\tlet oldHashMemory = this.hashMemory;\n\n\t\t// Copy each old hash value into new hash memory\n\t\tfor(let i = 0; i < oldMaxHash; i++) {\n\t\t\tlet pointer = loadPointer(oldHashMemory.data, i);\n\t\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet list = new SharedList(this.memory, {\n\t\t\t\tfirstBlock: pointer\n\t\t\t});\n\t\t\tfor(let { data } of list) {\n\t\t\t\tthis.setHashKey(newHashMemory, newMaxHash, data[0], data[1]);\n\t\t\t}\n\n\t\t\t// The entries have been copied into freshly allocated lists in the new hash table so the old list can be freed\n\t\t\tlist.free();\n\t\t}\n\n\t\tstorePointer(this.pointerMemory.data, 0, newHashMemory.bufferPosition, newHashMemory.bufferByteOffset);\n\t\tAtomics.store(this.pointerMemory.data, 3, newMaxHash);\n\n\t\t// pointerMemory now references newHashMemory so the old hash table memory can be freed\n\t\toldHashMemory.free();\n\t}\n\n\tprivate hash(key: number, maxHash: number) {\n\t\treturn key % maxHash;\n\t}\n\n\tfree() {\n\t\t// Loop through and free lists in hash table first\n\t\tfor(let i = 0; i < this.maxHash; i++) {\n\t\t\tlet pointer = loadPointer(this.hashMemory.data, i);\n\t\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet list = new SharedList(this.memory, {\n\t\t\t\tfirstBlock: pointer\n\t\t\t});\n\t\t\tlist.free();\n\t\t}\n\n\t\tthis.hashMemory.free();\n\t\tthis.pointerMemory.free();\n\t}\n\n\tgetSharedMemory(): SharedMapMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.pointerMemory.getSharedMemory()\n\t\t};\n\t}\n}\n\ninterface SharedMapMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nfunction get32BitHash<K extends string | number>(key: K): number {\n\tif(typeof key === 'number') {\n\t\treturn key;\n\t} else if(typeof key === 'string') {\n\t\treturn hashString(key as string);\n\t} else {\n\t\treturn key;\n\t}\n}\n\n// Copied from https://github.com/mmomtchev/SharedMap/blob/master/index.js - MurmurHash2\nfunction hashString(str: string): number {\n\tlet\n\t\tl = str.length,\n\t\th = 17 ^ l,\n\t\ti = 0,\n\t\tk;\n\twhile(l >= 4) {\n\t\tk =\n\t\t\t((str.charCodeAt(i) & 0xff)) |\n\t\t\t((str.charCodeAt(++i) & 0xff) << 8) |\n\t\t\t((str.charCodeAt(++i) & 0xff) << 16) |\n\t\t\t((str.charCodeAt(++i) & 0xff) << 14);\n\t\tk = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\t\tk ^= k >>> 14;\n\t\tk = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\t\th = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;\n\t\tl -= 4;\n\t\t++i;\n\t}\n\t/* eslint-disable no-fallthrough */\n\tswitch(l) {\n\t\tcase 3: h ^= (str.charCodeAt(i + 2) & 0xff) << 16;\n\t\tcase 2: h ^= (str.charCodeAt(i + 1) & 0xff) << 8;\n\t\tcase 1: h ^= (str.charCodeAt(i) & 0xff);\n\t\t\th = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\t}\n\t/* eslint-enable no-fallthrough */\n\th ^= h >>> 13;\n\th = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\th ^= h >>> 15;\n\th = h >>> 0;\n\treturn h;\n}\n\nexport type { SharedMapMemory };"],"names":["DEFAULT_HASH_SIZE","SharedMap","AllocatedMemory","loadPointer","memory","clone","hashMemory","storePointer","key","value","fullHashKey","get32BitHash","maxHash","hashKey","list","pointer","SharedList","listMemory","inserted","data","deleteCurrent","oldMaxHash","newMaxHash","newHashMemory","oldHashMemory","i","hashString","str","l","h","k"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import l from "./allocated-memory.js";
2
+ import r from "./shared-list.js";
3
+ import { createPointer as i, loadPointer as m } from "./utils/pointer.js";
4
+ class u {
5
+ memory;
6
+ list;
7
+ constructor(e, t) {
8
+ this.memory = e, t ? this.list = new r(e, t) : this.list = new r(e);
9
+ }
10
+ get length() {
11
+ return this.list.length;
12
+ }
13
+ insert(e) {
14
+ this.list.insert(i(e.memory.bufferPosition, e.memory.bufferByteOffset));
15
+ }
16
+ delete(e) {
17
+ return this.list.deleteValue(i(e.memory.bufferPosition, e.memory.bufferByteOffset));
18
+ }
19
+ *[Symbol.iterator]() {
20
+ let e = this.list[Symbol.iterator]();
21
+ for (let { data: t } of e) {
22
+ let { bufferPosition: o, bufferByteOffset: f } = m(t, 0), s = new l(this.memory, {
23
+ bufferPosition: o,
24
+ bufferByteOffset: f
25
+ });
26
+ yield this.createItem(s);
27
+ }
28
+ }
29
+ forEach(e) {
30
+ for (let t of this)
31
+ e(t);
32
+ }
33
+ find(e) {
34
+ for (let t of this)
35
+ if (e(t))
36
+ return t;
37
+ }
38
+ getSharedMemory() {
39
+ return this.list.getSharedMemory();
40
+ }
41
+ free() {
42
+ for (let e of this)
43
+ "free" in e && typeof e.free == "function" ? e.free() : e.memory.free();
44
+ this.list.free();
45
+ }
46
+ }
47
+ export {
48
+ u as default
49
+ };
50
+ //# sourceMappingURL=shared-pointer-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-pointer-list.js","sources":["../src/shared-pointer-list.ts"],"sourcesContent":["import AllocatedMemory from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport type { SharedListMemory } from './shared-list';\nimport SharedList from './shared-list';\nimport { createPointer, loadPointer } from './utils/pointer';\n\nexport default abstract class SharedPointerList<T extends PointerItem> implements Iterable<T> {\n\tprivate memory: MemoryHeap;\n\tprivate list: SharedList;\n\n\tconstructor(heap: MemoryHeap, memory?: SharedListMemory) {\n\t\tthis.memory = heap;\n\n\t\tif(memory) {\n\t\t\tthis.list = new SharedList(heap, memory);\n\t\t} else {\n\t\t\tthis.list = new SharedList(heap);\n\t\t}\n\t}\n\n\tget length() {\n\t\treturn this.list.length;\n\t}\n\n\tinsert(item: T) {\n\t\tthis.list.insert(createPointer(item.memory.bufferPosition, item.memory.bufferByteOffset));\n\t}\n\tdelete(item: T) {\n\t\treturn this.list.deleteValue(createPointer(item.memory.bufferPosition, item.memory.bufferByteOffset));\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tlet iterator = this.list[Symbol.iterator]();\n\n\t\tfor(let { data: pointerData } of iterator) {\n\t\t\tlet { bufferPosition, bufferByteOffset } = loadPointer(pointerData, 0);\n\t\t\tlet allocatedMemory = new AllocatedMemory(this.memory, {\n\t\t\t\tbufferPosition,\n\t\t\t\tbufferByteOffset\n\t\t\t});\n\t\t\tyield this.createItem(allocatedMemory);\n\t\t}\n\t}\n\tforEach(callback: (item: T) => void) {\n\t\tfor(let value of this) {\n\t\t\tcallback(value);\n\t\t}\n\t}\n\n\tfind(callback: (item: T) => boolean): T | undefined {\n\t\tfor(let value of this) {\n\t\t\tif(callback(value)) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t}\n\n\tgetSharedMemory() {\n\t\treturn this.list.getSharedMemory();\n\t}\n\n\tprotected abstract createItem(allocatedMemory: AllocatedMemory): T;\n\n\tfree() {\n\t\tfor(let item of this) {\n\t\t\t// NOTE: Anything that allocates it's own memory (ie: type for Item) needs to call free for that class so we can clear all memory recursively\n\t\t\tif('free' in item && typeof item.free === 'function') {\n\t\t\t\titem.free();\n\t\t\t} else {\n\t\t\t\titem.memory.free();\n\t\t\t}\n\t\t}\n\n\t\tthis.list.free();\n\t}\n}\n\ninterface PointerItem {\n\treadonly memory: AllocatedMemory\n}"],"names":["SharedPointerList","heap","memory","SharedList","item","createPointer","iterator","pointerData","bufferPosition","bufferByteOffset","loadPointer","allocatedMemory","AllocatedMemory","callback","value"],"mappings":";;;AAMA,MAA8BA,EAAgE;AAAA,EACrF;AAAA,EACA;AAAA,EAER,YAAYC,GAAkBC,GAA2B;AACxD,SAAK,SAASD,GAEXC,IACF,KAAK,OAAO,IAAIC,EAAWF,GAAMC,CAAM,IAEvC,KAAK,OAAO,IAAIC,EAAWF,CAAI;AAAA,EAEjC;AAAA,EAEA,IAAI,SAAS;AACZ,WAAO,KAAK,KAAK;AAAA,EAClB;AAAA,EAEA,OAAOG,GAAS;AACf,SAAK,KAAK,OAAOC,EAAcD,EAAK,OAAO,gBAAgBA,EAAK,OAAO,gBAAgB,CAAC;AAAA,EACzF;AAAA,EACA,OAAOA,GAAS;AACf,WAAO,KAAK,KAAK,YAAYC,EAAcD,EAAK,OAAO,gBAAgBA,EAAK,OAAO,gBAAgB,CAAC;AAAA,EACrG;AAAA,EAEA,EAAE,OAAO,QAAQ,IAAI;AACpB,QAAIE,IAAW,KAAK,KAAK,OAAO,QAAQ,EAAA;AAExC,aAAQ,EAAE,MAAMC,EAAA,KAAiBD,GAAU;AAC1C,UAAI,EAAE,gBAAAE,GAAgB,kBAAAC,EAAA,IAAqBC,EAAYH,GAAa,CAAC,GACjEI,IAAkB,IAAIC,EAAgB,KAAK,QAAQ;AAAA,QACtD,gBAAAJ;AAAA,QACA,kBAAAC;AAAA,MAAA,CACA;AACD,YAAM,KAAK,WAAWE,CAAe;AAAA,IACtC;AAAA,EACD;AAAA,EACA,QAAQE,GAA6B;AACpC,aAAQC,KAAS;AAChB,MAAAD,EAASC,CAAK;AAAA,EAEhB;AAAA,EAEA,KAAKD,GAA+C;AACnD,aAAQC,KAAS;AAChB,UAAGD,EAASC,CAAK;AAChB,eAAOA;AAAA,EAGV;AAAA,EAEA,kBAAkB;AACjB,WAAO,KAAK,KAAK,gBAAA;AAAA,EAClB;AAAA,EAIA,OAAO;AACN,aAAQV,KAAQ;AAEf,MAAG,UAAUA,KAAQ,OAAOA,EAAK,QAAS,aACzCA,EAAK,KAAA,IAELA,EAAK,OAAO,KAAA;AAId,SAAK,KAAK,KAAA;AAAA,EACX;AACD;"}
@@ -0,0 +1,165 @@
1
+ import f from "./allocated-memory.js";
2
+ import s from "./shared-vector.js";
3
+ import { getPointer as n } from "./utils/pointer.js";
4
+ const o = 0, c = 1, u = 2, l = 3, y = l + s.ALLOCATE_COUNT;
5
+ class k {
6
+ static ALLOCATE_COUNT = 3 + s.ALLOCATE_COUNT * 2;
7
+ memory;
8
+ // Current Length, Type/DataLength, MaxChunkLength, Pointer vector, Recycle vector
9
+ firstBlock;
10
+ uint16Array;
11
+ pointerVector;
12
+ recycleVector;
13
+ cachedFullDataBlock = {};
14
+ get length() {
15
+ return Atomics.load(this.firstBlock.data, o) - this.recycleVector.length;
16
+ }
17
+ get maxChunkSize() {
18
+ return this.firstBlock.data[u];
19
+ }
20
+ set maxChunkSize(t) {
21
+ Atomics.store(this.firstBlock.data, u, t);
22
+ }
23
+ get type() {
24
+ return this.uint16Array[0];
25
+ }
26
+ set type(t) {
27
+ Atomics.store(this.uint16Array, 0, t);
28
+ }
29
+ get dataLength() {
30
+ return Math.max(1, this.uint16Array[1]);
31
+ }
32
+ set dataLength(t) {
33
+ Atomics.store(this.uint16Array, 1, t);
34
+ }
35
+ get bufferLength() {
36
+ return this.maxChunkSize * this.pointerVector.length;
37
+ }
38
+ get recycleBufferLength() {
39
+ return this.recycleVector.bufferLength;
40
+ }
41
+ get byteMultipler() {
42
+ return this.type === 3 ? 2 : 1;
43
+ }
44
+ constructor(t, e) {
45
+ if (this.memory = t, e && "firstBlock" in e)
46
+ this.firstBlock = new f(t, e.firstBlock), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + c * Uint32Array.BYTES_PER_ELEMENT, 2), this.pointerVector = new s(t, {
47
+ firstBlock: {
48
+ bufferPosition: this.firstBlock.bufferPosition,
49
+ bufferByteOffset: this.firstBlock.bufferByteOffset + l * Uint32Array.BYTES_PER_ELEMENT
50
+ }
51
+ }), this.recycleVector = new s(t, {
52
+ firstBlock: {
53
+ bufferPosition: this.firstBlock.bufferPosition,
54
+ bufferByteOffset: this.firstBlock.bufferByteOffset + y * Uint32Array.BYTES_PER_ELEMENT
55
+ }
56
+ });
57
+ else {
58
+ this.firstBlock = t.allocUI32(k.ALLOCATE_COUNT), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + c * Uint32Array.BYTES_PER_ELEMENT, 2);
59
+ let i = e?.dataLength ?? 1, r = e?.maxChunkSize ?? 100;
60
+ this.pointerVector = new s(t, {
61
+ type: Uint32Array,
62
+ firstBlock: {
63
+ bufferPosition: this.firstBlock.bufferPosition,
64
+ bufferByteOffset: this.firstBlock.bufferByteOffset + l * Uint32Array.BYTES_PER_ELEMENT
65
+ }
66
+ }), this.recycleVector = new s(t, {
67
+ type: Uint32Array,
68
+ firstBlock: {
69
+ bufferPosition: this.firstBlock.bufferPosition,
70
+ bufferByteOffset: this.firstBlock.bufferByteOffset + y * Uint32Array.BYTES_PER_ELEMENT
71
+ },
72
+ bufferLength: e?.recycleBufferLength
73
+ });
74
+ const a = e?.type ?? Uint32Array;
75
+ a === Uint32Array ? this.type = 0 : a === Int32Array ? this.type = 1 : a === Float32Array ? this.type = 2 : a === Float64Array && (this.type = 3), this.dataLength = i, this.maxChunkSize = r;
76
+ let h = t.allocUI32(r * i * this.byteMultipler);
77
+ this.pointerVector.push(h.pointer);
78
+ }
79
+ }
80
+ at(t) {
81
+ let e = this.getFullDataBlock(t);
82
+ return this.getDataBlock(e, t % this.maxChunkSize);
83
+ }
84
+ get(t, e = 0) {
85
+ const i = this.dataLength;
86
+ if (e >= i)
87
+ throw new Error(`${e} is out of dataLength bounds ${i}`);
88
+ return this.getFullDataBlock(t)[t % this.maxChunkSize * i + e];
89
+ }
90
+ push(t) {
91
+ typeof t == "number" && (t = [t]);
92
+ let e = this.dataLength;
93
+ if (t.length > e)
94
+ throw new Error(`Can't insert ${t.length} array into shared list of ${e} dataLength`);
95
+ let i;
96
+ this.recycleVector.length ? i = this.recycleVector.popNumber() : i = Atomics.add(this.firstBlock.data, o, 1);
97
+ let r = this.getFullDataBlock(i), a = i % this.maxChunkSize;
98
+ return r.set(t, e * a), i;
99
+ }
100
+ deleteIndex(t) {
101
+ this.recycleVector.push(t);
102
+ }
103
+ clear() {
104
+ this.firstBlock.data[o] = 0, this.recycleVector.clear();
105
+ }
106
+ *[Symbol.iterator]() {
107
+ const t = {};
108
+ for (let r of this.recycleVector)
109
+ t[r[0]] = !0;
110
+ let e = this.getFullDataBlock(0), i = 0;
111
+ for (let r = 0; r < Atomics.load(this.firstBlock.data, o); r++)
112
+ if (!t[r]) {
113
+ let a = Math.floor(r / this.maxChunkSize);
114
+ a !== i && (e = this.getFullDataBlock(r), i = a), yield this.getDataBlock(e, r % this.maxChunkSize);
115
+ }
116
+ }
117
+ getFullDataBlock(t) {
118
+ let e = Math.floor(t / this.maxChunkSize), i = this.cachedFullDataBlock[e];
119
+ if (i)
120
+ return i;
121
+ if (e >= this.pointerVector.length) {
122
+ let h = this.memory.allocUI32(this.maxChunkSize * this.dataLength * this.byteMultipler);
123
+ this.pointerVector.push(h.pointer);
124
+ }
125
+ let r = new f(this.memory, n(this.pointerVector.get(e))), a;
126
+ switch (this.type) {
127
+ case 1:
128
+ a = new Int32Array(r.data.buffer, r.bufferByteOffset, this.dataLength * this.maxChunkSize);
129
+ break;
130
+ case 0:
131
+ a = new Uint32Array(r.data.buffer, r.bufferByteOffset, this.dataLength * this.maxChunkSize);
132
+ break;
133
+ case 2:
134
+ a = new Float32Array(r.data.buffer, r.bufferByteOffset, this.dataLength * this.maxChunkSize);
135
+ break;
136
+ case 3:
137
+ a = new Float64Array(r.data.buffer, r.bufferByteOffset, this.dataLength * this.maxChunkSize);
138
+ break;
139
+ default:
140
+ throw new Error(`Unknown data block type ${this.type}`);
141
+ }
142
+ return this.cachedFullDataBlock[e] = a, a;
143
+ }
144
+ getDataBlock(t, e) {
145
+ const i = e * this.dataLength;
146
+ return t.subarray(i, i + this.dataLength);
147
+ }
148
+ free() {
149
+ this.recycleVector.free();
150
+ for (let t of this.pointerVector) {
151
+ let e = t[0];
152
+ new f(this.memory, n(e)).free();
153
+ }
154
+ this.pointerVector.free(), this.firstBlock.free();
155
+ }
156
+ getSharedMemory() {
157
+ return {
158
+ firstBlock: this.firstBlock.getSharedMemory()
159
+ };
160
+ }
161
+ }
162
+ export {
163
+ k as default
164
+ };
165
+ //# sourceMappingURL=shared-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-pool.js","sources":["../src/shared-pool.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport type { TypedArrayConstructor } from './interfaces/typed-array-constructor';\nimport type MemoryHeap from './memory-heap';\nimport SharedVector from './shared-vector';\nimport { getPointer } from './utils/pointer';\n\nenum TYPE {\n\tuint32,\n\tint32,\n\tfloat32,\n\tfloat64\n}\n\nconst LENGTH_INDEX = 0;\nconst TYPE_INDEX = 1;\nconst MAX_CHUNK_SIZE_INDEX = 2;\nconst POINTERS_INDEX = 3;\nconst RECYCLE_INDEX = POINTERS_INDEX + SharedVector.ALLOCATE_COUNT;\n\n// Array with stable indexes and maximum contiguous memory sizes (necessary to fit large data sets into max 1MB buffers)\n// https://plflib.org/colony.htm for future enhancements - it seems to be an optimized version of what we were aiming for with this\nexport default class SharedPool<T extends Uint32Array | Int32Array | Float32Array | Float64Array = Uint32Array> implements Iterable<T> {\n\tstatic readonly ALLOCATE_COUNT = 3 + SharedVector.ALLOCATE_COUNT * 2;\n\tprivate memory: MemoryHeap;\n\n\t// Current Length, Type/DataLength, MaxChunkLength, Pointer vector, Recycle vector\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\tprivate pointerVector: SharedVector<Uint32Array>;\n\tprivate recycleVector: SharedVector<Uint32Array>;\n\n\tprivate cachedFullDataBlock: { [key: number]: T } = {};\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX) - this.recycleVector.length;\n\t}\n\tget maxChunkSize(): number {\n\t\treturn this.firstBlock.data[MAX_CHUNK_SIZE_INDEX];\n\t}\n\tprivate set maxChunkSize(value: number) {\n\t\tAtomics.store(this.firstBlock.data, MAX_CHUNK_SIZE_INDEX, value);\n\t}\n\t\n\tget type(): number {\n\t\treturn this.uint16Array[0];\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget dataLength(): number {\n\t\treturn Math.max(1, this.uint16Array[1]);\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tget bufferLength(): number {\n\t\treturn this.maxChunkSize * this.pointerVector.length;\n\t}\n\tget recycleBufferLength(): number {\n\t\treturn this.recycleVector.bufferLength;\n\t}\n\tget byteMultipler(): number {\n\t\tif(this.type === TYPE.float64) {\n\t\t\treturn 2;\n\t\t} else {\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedPoolConfig<T> | SharedPoolMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\tthis.firstBlock = new AllocatedMemory(memory, config.firstBlock);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\t\t\tthis.pointerVector = new SharedVector(memory, {\n\t\t\t\tfirstBlock: {\n\t\t\t\t\tbufferPosition: this.firstBlock.bufferPosition,\n\t\t\t\t\tbufferByteOffset: this.firstBlock.bufferByteOffset + POINTERS_INDEX * Uint32Array.BYTES_PER_ELEMENT\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.recycleVector = new SharedVector(memory, {\n\t\t\t\tfirstBlock: {\n\t\t\t\t\tbufferPosition: this.firstBlock.bufferPosition,\n\t\t\t\t\tbufferByteOffset: this.firstBlock.bufferByteOffset + RECYCLE_INDEX * Uint32Array.BYTES_PER_ELEMENT\n\t\t\t\t}\n\t\t\t});\n\t\t} else {\n\t\t\tthis.firstBlock = memory.allocUI32(SharedPool.ALLOCATE_COUNT);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\tlet dataLength = config?.dataLength ?? 1;\n\t\t\tlet maxLength = config?.maxChunkSize ?? 100;\n\n\t\t\tthis.pointerVector = new SharedVector(memory, {\n\t\t\t\ttype: Uint32Array,\n\t\t\t\tfirstBlock: {\n\t\t\t\t\tbufferPosition: this.firstBlock.bufferPosition,\n\t\t\t\t\tbufferByteOffset: this.firstBlock.bufferByteOffset + POINTERS_INDEX * Uint32Array.BYTES_PER_ELEMENT\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.recycleVector = new SharedVector(memory, {\n\t\t\t\ttype: Uint32Array,\n\t\t\t\tfirstBlock: {\n\t\t\t\t\tbufferPosition: this.firstBlock.bufferPosition,\n\t\t\t\t\tbufferByteOffset: this.firstBlock.bufferByteOffset + RECYCLE_INDEX * Uint32Array.BYTES_PER_ELEMENT\n\t\t\t\t},\n\t\t\t\tbufferLength: config?.recycleBufferLength\n\t\t\t});\n\n\t\t\tconst type = config?.type ?? Uint32Array;\n\t\t\tif(type === Uint32Array) {\n\t\t\t\tthis.type = TYPE.uint32;\n\t\t\t}\n\t\t\t// @ts-expect-error\n\t\t\telse if(type === Int32Array) {\n\t\t\t\tthis.type = TYPE.int32;\n\t\t\t}\n\t\t\t// @ts-expect-error\n\t\t\telse if(type === Float32Array) {\n\t\t\t\tthis.type = TYPE.float32;\n\t\t\t// @ts-expect-error\n\t\t\t} else if(type === Float64Array) {\n\t\t\t\tthis.type = TYPE.float64;\n\t\t\t}\n\t\t\tthis.dataLength = dataLength;\n\t\t\tthis.maxChunkSize = maxLength;\n\n\t\t\tlet firstArray = memory.allocUI32(maxLength * dataLength * this.byteMultipler);\n\t\t\tthis.pointerVector.push(firstArray.pointer);\n\t\t}\n\t}\n\n\tat(index: number): T {\n\t\tlet dataBlock = this.getFullDataBlock(index);\n\t\treturn this.getDataBlock(dataBlock, index % this.maxChunkSize);\n\t}\n\tget(index: number, dataIndex = 0): number {\n\t\tconst dataLength = this.dataLength;\n\t\tif(dataIndex >= dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${dataLength}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(index);\n\t\treturn dataBlock[(index % this.maxChunkSize) * dataLength + dataIndex];\n\t}\n\n\tpush(values: number | Array<number>): number {\n\t\tif(typeof values === 'number') {\n\t\t\tvalues = [values];\n\t\t}\n\n\t\tlet dataLength = this.dataLength;\n\t\tif(values.length > dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${dataLength} dataLength`);\n\t\t}\n\n\t\tlet newIndex;\n\t\tif(this.recycleVector.length) {\n\t\t\tnewIndex = this.recycleVector.popNumber();\n\t\t} else {\n\t\t\tnewIndex = Atomics.add(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\t}\n\t\t\n\t\tlet dataBlock = this.getFullDataBlock(newIndex);\n\t\tlet blockIndex = newIndex % this.maxChunkSize;\n\t\tdataBlock.set(values, dataLength * blockIndex);\n\n\t\treturn newIndex;\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tthis.recycleVector.push(index);\n\t}\n\n\tclear() {\n\t\tthis.firstBlock.data[LENGTH_INDEX] = 0;\n\t\tthis.recycleVector.clear();\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycleVector) {\n\t\t\trecycledValues[value[0]] = true;\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < Atomics.load(this.firstBlock.data, LENGTH_INDEX); i++) {\n\t\t\tif(!recycledValues[i]) {\n\t\t\t\tlet newDataBlockIndex = Math.floor(i / this.maxChunkSize);\n\t\t\t\tif(newDataBlockIndex !== dataBlockIndex) {\n\t\t\t\t\tdataBlock = this.getFullDataBlock(i);\n\t\t\t\t\tdataBlockIndex = newDataBlockIndex;\n\t\t\t\t}\n\t\t\t\tyield this.getDataBlock(dataBlock, i % this.maxChunkSize);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getFullDataBlock(index: number) {\n\t\tlet pointerIndex = Math.floor(index / this.maxChunkSize);\n\t\tlet cachedDataBlock = this.cachedFullDataBlock[pointerIndex];\n\t\tif(cachedDataBlock) {\n\t\t\treturn cachedDataBlock;\n\t\t}\n\t\tif(pointerIndex >= this.pointerVector.length) {\n\t\t\tlet newArray = this.memory.allocUI32(this.maxChunkSize * this.dataLength * this.byteMultipler);\n\t\t\tthis.pointerVector.push(newArray.pointer);\n\t\t}\n\n\t\tlet array = new AllocatedMemory(this.memory, getPointer(this.pointerVector.get(pointerIndex)));\n\n\t\tlet data: T;\n\t\tswitch(this.type) {\n\t\t\tcase TYPE.int32:\n\t\t\t\tdata = new Int32Array(array.data.buffer, array.bufferByteOffset, this.dataLength * this.maxChunkSize) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.uint32:\n\t\t\t\tdata = new Uint32Array(array.data.buffer, array.bufferByteOffset, this.dataLength * this.maxChunkSize) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.float32:\n\t\t\t\tdata = new Float32Array(array.data.buffer, array.bufferByteOffset, this.dataLength * this.maxChunkSize) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.float64:\n\t\t\t\tdata = new Float64Array(array.data.buffer, array.bufferByteOffset, this.dataLength * this.maxChunkSize) as T;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown data block type ${this.type}`);\n\t\t}\n\n\t\tthis.cachedFullDataBlock[pointerIndex] = data;\n\t\treturn data;\n\t}\n\n\tprivate getDataBlock(rawData: T, index: number): T {\n\t\tconst start = index * this.dataLength;\n\t\treturn rawData.subarray(start, start + this.dataLength) as T;\n\t}\n\n\tfree() {\n\t\tthis.recycleVector.free();\n\n\t\tfor(let pointerArray of this.pointerVector) {\n\t\t\tlet pointer = pointerArray[0];\n\t\t\tlet memory = new AllocatedMemory(this.memory, getPointer(pointer));\n\t\t\tmemory.free();\n\t\t}\n\t\tthis.pointerVector.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedPoolMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory()\n\t\t};\n\t}\n}\n\ninterface SharedPoolConfig<T extends Uint32Array | Int32Array | Float32Array | Float64Array> {\n\tmaxChunkSize?: number\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n\trecycleBufferLength?: number\n}\ninterface SharedPoolMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedPoolConfig, SharedPoolMemory };"],"names":["LENGTH_INDEX","TYPE_INDEX","MAX_CHUNK_SIZE_INDEX","POINTERS_INDEX","RECYCLE_INDEX","SharedVector","SharedPool","value","memory","config","AllocatedMemory","dataLength","maxLength","type","firstArray","index","dataBlock","dataIndex","values","newIndex","blockIndex","recycledValues","dataBlockIndex","i","newDataBlockIndex","pointerIndex","cachedDataBlock","newArray","array","getPointer","data","rawData","start","pointerArray","pointer"],"mappings":"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"}