@daneren2005/shared-memory-objects 1.2.0 → 1.4.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 (43) hide show
  1. package/README.md +69 -7
  2. package/dist/allocated-memory.d.ts +1 -0
  3. package/dist/allocated-memory.js +3 -0
  4. package/dist/allocated-memory.js.map +1 -1
  5. package/dist/cached-item-list.d.ts +2 -1
  6. package/dist/cached-item-list.js +6 -1
  7. package/dist/cached-item-list.js.map +1 -1
  8. package/dist/local-pool.d.ts +5 -5
  9. package/dist/local-pool.js +13 -10
  10. package/dist/local-pool.js.map +1 -1
  11. package/dist/lock/simple-lock.js +7 -2
  12. package/dist/lock/simple-lock.js.map +1 -1
  13. package/dist/memory-buffer.d.ts +4 -1
  14. package/dist/memory-buffer.js +12 -9
  15. package/dist/memory-buffer.js.map +1 -1
  16. package/dist/memory-heap.d.ts +2 -0
  17. package/dist/memory-heap.js +11 -1
  18. package/dist/memory-heap.js.map +1 -1
  19. package/dist/shared-list.d.ts +17 -8
  20. package/dist/shared-list.js +99 -68
  21. package/dist/shared-list.js.map +1 -1
  22. package/dist/shared-map.d.ts +25 -10
  23. package/dist/shared-map.js +141 -78
  24. package/dist/shared-map.js.map +1 -1
  25. package/dist/shared-pointer-list.d.ts +1 -0
  26. package/dist/shared-pointer-list.js +5 -1
  27. package/dist/shared-pointer-list.js.map +1 -1
  28. package/dist/shared-pool.d.ts +9 -5
  29. package/dist/shared-pool.js +43 -48
  30. package/dist/shared-pool.js.map +1 -1
  31. package/dist/shared-stack.d.ts +23 -9
  32. package/dist/shared-stack.js +130 -66
  33. package/dist/shared-stack.js.map +1 -1
  34. package/dist/shared-vector.d.ts +9 -6
  35. package/dist/shared-vector.js +37 -56
  36. package/dist/shared-vector.js.map +1 -1
  37. package/dist/utils/array-type.d.ts +20 -0
  38. package/dist/utils/array-type.js +36 -0
  39. package/dist/utils/array-type.js.map +1 -0
  40. package/dist/utils/hash.d.ts +3 -0
  41. package/dist/utils/hash.js +21 -0
  42. package/dist/utils/hash.js.map +1 -0
  43. package/package.json +3 -1
package/README.md CHANGED
@@ -66,17 +66,26 @@ let secondList = new SharedList(memory, mainList.getSharedMemory());
66
66
  - SharedString
67
67
  - ConstantString - an immutable SharedString: the value is written once and never changes, so it drops the lock word and all of SharedString's read/write locking
68
68
 
69
+ ## Memory Usage
70
+ `SharedList`, `SharedVector`, `SharedPool`, and `SharedStack` each expose a `usedMemory` getter that returns the number of bytes the structure occupies in the heap, including every pointer resource it owns. For example, `SharedStack.usedMemory` is its own internal memory plus the combined memory of each already allocated segment, and `SharedPool.usedMemory` includes each chunk buffer and the segments of its two internal stacks (but not those stacks' internal memory, since that is inlined into the pool's own internal memory). The number is the aligned data size of each allocation and excludes the allocator's per-block header. SharedStack and SharedPool get a lot of their close to native performance by allocating more memory than maybe needed and locking in max length up front. This works well when used for a few high-performance structures, but if you are giving each entity in an ECS framework multiple SharedPools that memory is going to add up quickly. Both SharedPool and SharedStack initial memory can be tweaked by lowering the maxLength param.
71
+
72
+ Freshly allocated with the default options:
73
+
74
+ | Structure | Used Memory |
75
+ | ------------- | ----------- |
76
+ | SharedList | 16 bytes |
77
+ | SharedVector | 32 bytes |
78
+ | SharedStack | 144 bytes |
79
+ | SharedPool | 656 bytes |
80
+ | SharedMap | 216 bytes |
81
+
69
82
  ## Thread Safety
70
- - Memory allocations is thread safe as long as it does not need to create a new buffer. Right now that can only be done from the main thread.
71
- - SharedPool and SharedStack are thread safe
72
- - SharedList, SharedVector, and SharedMap are *not* thread safe.
83
+ - Memory allocations is thread safe as long as it does not need to create a new buffer. Right now that can only be done from the main thread. I just make sure there is always an extra empty buffer with SharedHeap.ensureSpareBuffer() before sending more work to worker threads.
84
+ - SharedList, SharedPool, SharedStack, and SharedMap are thread safe
85
+ - SharedVector is *not* thread safe and probably never will be - it is useful for updating in main thread and then sending off to works for processing
73
86
  - SharedString is thread safe with a lock on read/write with a cached version of the string so it doesn't need to lock after the first read unless the string has changed.
74
87
  - ConstantString is safe to read from any thread without a lock precisely because it is never written after construction
75
88
 
76
- ## TODO
77
- - Make creating new buffers from allocations possible from multiple threads
78
- - Make data structures thread safe
79
- - Make map structure that isn't so slow as to be useless
80
89
 
81
90
  ## Performance
82
91
  The tl;dr is that none of these data structures are close to what you can get by just using native data structures, but I wasn't expecting them to be with their overhead.
@@ -187,5 +196,58 @@ local pool
187
196
  985.37x faster than shared list
188
197
  ```
189
198
 
199
+ ### SharedMap vs native Map
200
+ `SharedMap` uses open-addressing with linear probing over a contiguous SharedArrayBuffer table, so it stays within a small constant factor of the native `Map` rather than the order-of-magnitude gap seen elsewhere. Iterating and deleting are the closest to native; sets are the slowest since they can trigger a rehash. Keys of 1000 numbers, values randomized:
201
+
202
+ Shared Map: 1000 sets
203
+ ```
204
+ name hz min max mean p75 p99 p995 p999 rme samples
205
+ shared map 7,565.94 0.1166 1.1183 0.1322 0.1278 0.2565 0.2973 0.3598 ±0.76% 3783
206
+ native map 48,357.73 0.0177 0.2432 0.0207 0.0199 0.0808 0.0934 0.1398 ±0.57% 24179
207
+
208
+ native map
209
+ 6.39x faster than shared map
210
+ ```
211
+
212
+ Shared Map: 1000 overwrites
213
+ ```
214
+ name hz min max mean p75 p99 p995 p999 rme samples
215
+ shared map 16,906.24 0.0551 0.2499 0.0591 0.0569 0.1194 0.1433 0.1940 ±0.43% 8454
216
+ native map 83,196.44 0.0105 0.1686 0.0120 0.0119 0.0197 0.0231 0.0465 ±0.27% 41599
217
+
218
+ native map
219
+ 4.92x faster than shared map
220
+ ```
221
+
222
+ Shared Map: 1000 gets
223
+ ```
224
+ name hz min max mean p75 p99 p995 p999 rme samples
225
+ shared map 16,598.62 0.0494 0.3111 0.0602 0.0593 0.1121 0.1279 0.1718 ±0.70% 8300
226
+ native map 93,483.83 0.0073 2.7586 0.0107 0.0138 0.0222 0.0255 0.0398 ±1.23% 46742
227
+
228
+ native map
229
+ 5.63x faster than shared map
230
+ ```
231
+
232
+ Shared Map: 1000 deletes
233
+ ```
234
+ name hz min max mean p75 p99 p995 p999 rme samples
235
+ shared map 17,590.31 0.0497 0.2837 0.0568 0.0526 0.1252 0.1393 0.1909 ±0.59% 8796
236
+ native map 59,139.95 0.0147 0.2453 0.0169 0.0164 0.0291 0.0349 0.1017 ±0.36% 29570
237
+
238
+ native map
239
+ 3.36x faster than shared map
240
+ ```
241
+
242
+ Shared Map: iterate 1000 entries
243
+ ```
244
+ name hz min max mean p75 p99 p995 p999 rme samples
245
+ shared map 31,900.32 0.0213 0.4626 0.0313 0.0375 0.0552 0.2321 0.3119 ±1.03% 15951
246
+ native map 93,101.22 0.0068 0.1661 0.0107 0.0127 0.0194 0.0224 0.0320 ±0.25% 46551
247
+
248
+ native map
249
+ 2.92x faster than shared map
250
+ ```
251
+
190
252
  ## Credit
191
253
  The entire core of this library is based on a fork of @thi.ng/malloc found at https://github.com/thi-ng/umbrella/blob/develop/packages/malloc. The only big difference between our MemoryBuffer and their MemPool is making allocations/freeing memory thread safe.
@@ -9,6 +9,7 @@ export default class AllocatedMemory {
9
9
  get pointer(): number;
10
10
  private buffer;
11
11
  data: Uint32Array;
12
+ get usedMemory(): number;
12
13
  constructor(memory: MemoryHeap, config: AllocatedMemoryConfig | SharedAllocatedMemory);
13
14
  getArray<T extends TypedArray>(type: TypedArrayConstructor<T>, offset: number, length: number): T;
14
15
  getSubAllocation(offset: number, length: number): AllocatedMemory;
@@ -11,6 +11,9 @@ var t = class t {
11
11
  }
12
12
  buffer;
13
13
  data;
14
+ get usedMemory() {
15
+ return this.buffer.bytesFor(this.data.byteOffset) ?? 0;
16
+ }
14
17
  constructor(e, t) {
15
18
  this.memory = e, "buffer" in t ? (this.data = t.data, this.buffer = t.buffer, this.bufferPosition = this.memory.buffers.indexOf(t.buffer)) : (this.bufferPosition = t.bufferPosition, this.buffer = e.buffers[t.bufferPosition], this.data = new Uint32Array(this.buffer.buf, t.bufferByteOffset));
16
19
  }
@@ -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);\n\t}\n\tprivate buffer: MemoryBuffer;\n\tdata: Uint32Array;\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\t// Making sure these are the correct size is slow but in dev we want to make sure we aren't allowing to go out of bounds\n\t\t\tif(import.meta.env.MODE === 'production') {\n\t\t\t\tthis.data = new Uint32Array(this.buffer.buf, config.bufferByteOffset);\n\t\t\t} else {\n\t\t\t\tthis.data = new Uint32Array(this.buffer.buf, config.bufferByteOffset, this.buffer.lengthOf(config.bufferByteOffset));\n\t\t\t}\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};\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};\n\t}\n}\n\ninterface AllocatedMemoryConfig {\n\tdata: Uint32Array\n\tbuffer: MemoryBuffer\n}\n\ninterface SharedAllocatedMemory {\n\tbufferPosition: number\n\tbufferByteOffset: number\n}\nexport type { 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,gBAAgB;CAChE;CACA;CACA;CAEA,YAAY,GAAoB,GAAuD;EAGtF,AAFA,KAAK,SAAS,GAEX,YAAY,KACd,KAAK,OAAO,EAAO,MACnB,KAAK,SAAS,EAAO,QACrB,KAAK,iBAAiB,KAAK,OAAO,QAAQ,QAAQ,EAAO,MAAM,MAE/D,KAAK,iBAAiB,EAAO,gBAC7B,KAAK,SAAS,EAAO,QAAQ,EAAO,iBAInC,KAAK,OAAO,IAAI,YAAY,KAAK,OAAO,KAAK,EAAO,gBAAgB;CAKvE;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;EAC9D;CACD;CAEA,OAAO;EAEN,KAAK,OAAO,KAAK,KAAK,KAAK,UAAU;CACtC;CAEA,kBAAyC;EACxC,OAAO;GACN,gBAAgB,KAAK;GACrB,kBAAkB,KAAK;EACxB;CACD;AACD"}
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);\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\t// Making sure these are the correct size is slow but in dev we want to make sure we aren't allowing to go out of bounds\n\t\t\tif(import.meta.env.MODE === 'production') {\n\t\t\t\tthis.data = new Uint32Array(this.buffer.buf, config.bufferByteOffset);\n\t\t\t} else {\n\t\t\t\tthis.data = new Uint32Array(this.buffer.buf, config.bufferByteOffset, this.buffer.lengthOf(config.bufferByteOffset));\n\t\t\t}\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};\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};\n\t}\n}\n\ninterface AllocatedMemoryConfig {\n\tdata: Uint32Array\n\tbuffer: MemoryBuffer\n}\n\ninterface SharedAllocatedMemory {\n\tbufferPosition: number\n\tbufferByteOffset: number\n}\nexport type { 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,gBAAgB;CAChE;CACA;CACA;CAGA,IAAI,aAAqB;EACxB,OAAO,KAAK,OAAO,SAAS,KAAK,KAAK,UAAU,KAAK;CACtD;CAEA,YAAY,GAAoB,GAAuD;EAGtF,AAFA,KAAK,SAAS,GAEX,YAAY,KACd,KAAK,OAAO,EAAO,MACnB,KAAK,SAAS,EAAO,QACrB,KAAK,iBAAiB,KAAK,OAAO,QAAQ,QAAQ,EAAO,MAAM,MAE/D,KAAK,iBAAiB,EAAO,gBAC7B,KAAK,SAAS,EAAO,QAAQ,EAAO,iBAInC,KAAK,OAAO,IAAI,YAAY,KAAK,OAAO,KAAK,EAAO,gBAAgB;CAKvE;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;EAC9D;CACD;CAEA,OAAO;EAEN,KAAK,OAAO,KAAK,KAAK,KAAK,UAAU;CACtC;CAEA,kBAAyC;EACxC,OAAO;GACN,gBAAgB,KAAK;GACrB,kBAAkB,KAAK;EACxB;CACD;AACD"}
@@ -14,11 +14,12 @@ export default abstract class CachedItemList<T extends Item> implements Iterable
14
14
  clear(): void;
15
15
  insert(item: T): void;
16
16
  delete(item: T): boolean;
17
+ compact(): void;
17
18
  getByPointer(pointer: number): T | undefined;
18
19
  protected abstract initItem(pointer: number): T | undefined;
19
20
  [Symbol.iterator](): Generator<{
20
21
  item: T;
21
- deleteCurrent: () => void;
22
+ deleteCurrent: () => boolean;
22
23
  }, void, unknown>;
23
24
  forEach(callback: (item: T) => void, filter?: (item: T) => boolean): void;
24
25
  find(callback: (item: T) => boolean): T | undefined;
@@ -24,7 +24,12 @@ var t = class {
24
24
  this.list.insert(e.pointer), this.cache.set(e.pointer, e);
25
25
  }
26
26
  delete(e) {
27
- return this.cache.delete(e.pointer), this.list.deleteValue(e.pointer);
27
+ this.cache.delete(e.pointer);
28
+ let t = this.list.deleteValue(e.pointer);
29
+ return this.list.compact(), t;
30
+ }
31
+ compact() {
32
+ this.list.compact();
28
33
  }
29
34
  getByPointer(e) {
30
35
  let t = this.cache.get(e);
@@ -1 +1 @@
1
- {"version":3,"file":"cached-item-list.js","names":[],"sources":["../src/cached-item-list.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport SharedList, { type SharedListMemory } from './shared-list';\n\nexport default abstract class CachedItemList<T extends Item> implements Iterable<{ item: T, deleteCurrent: () => void }> {\n\tstatic readonly ALLOCATE_COUNT = SharedList.ALLOCATE_COUNT;\n\n\tprotected heap: MemoryHeap;\n\tprotected list: SharedList;\n\tprotected cache: Map<number, T> = new Map();\n\n\tconstructor(heap: MemoryHeap, config?: CachedListConfig | SharedListMemory) {\n\t\tif(config) {\n\t\t\tthis.list = new SharedList(heap, config);\n\t\t} else {\n\t\t\tthis.list = new SharedList(heap);\n\t\t}\n\t\tthis.heap = heap;\n\n\t\tthis.list.onDelete = (pointerData: Uint32Array) => {\n\t\t\tlet pointer = Atomics.load(pointerData, 0);\n\t\t\tif(pointer) {\n\t\t\t\tlet item = this.cache.get(pointer);\n\t\t\t\tif(!item) {\n\t\t\t\t\titem = this.initItem(pointer);\n\t\t\t\t}\n\n\t\t\t\tif(item) {\n\t\t\t\t\titem.free();\n\t\t\t\t\tthis.cache.delete(pointer);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tget length() {\n\t\treturn this.list.length;\n\t}\n\n\tclear() {\n\t\tthis.list.clear();\n\t\tthis.cache.clear();\n\t}\n\n\tinsert(item: T) {\n\t\tthis.list.insert(item.pointer);\n\t\tthis.cache.set(item.pointer, item);\n\t}\n\tdelete(item: T) {\n\t\tthis.cache.delete(item.pointer);\n\t\treturn this.list.deleteValue(item.pointer);\n\t}\n\n\tgetByPointer(pointer: number): T | undefined {\n\t\tlet item = this.cache.get(pointer);\n\t\tif(!item) {\n\t\t\titem = this.initItem(pointer);\n\t\t\tif(item) {\n\t\t\t\tthis.cache.set(pointer, item);\n\t\t\t}\n\t\t}\n\n\t\treturn item;\n\t}\n\tprotected abstract initItem(pointer: number): T | undefined;\n\n\t*[Symbol.iterator]() {\n\t\tlet iterator = this.list[Symbol.iterator]();\n\n\t\tfor(let { data: pointerData, deleteCurrent } of iterator) {\n\t\t\tlet pointer = Atomics.load(pointerData, 0);\n\t\t\tif(!pointer) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet item = this.cache.get(pointer);\n\t\t\tif(!item) {\n\t\t\t\titem = this.initItem(pointer);\n\t\t\t\tif(item) {\n\t\t\t\t\tthis.cache.set(pointer, item);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(item) {\n\t\t\t\tyield {\n\t\t\t\t\titem,\n\t\t\t\t\tdeleteCurrent,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\tforEach(callback: (item: T) => void, filter?: (item: T) => boolean) {\n\t\tfor(let { item } of this) {\n\t\t\tif(!filter || filter(item)) {\n\t\t\t\tcallback(item);\n\t\t\t}\n\t\t}\n\t}\n\n\tfind(callback: (item: T) => boolean): T | undefined {\n\t\tfor(let { item } of this) {\n\t\t\tif(callback(item)) {\n\t\t\t\treturn item;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\tfilter(callback: (entity: T) => boolean): Array<T> {\n\t\tlet items = [];\n\t\tfor(let { item } of this) {\n\t\t\tif(callback(item)) {\n\t\t\t\titems.push(item);\n\t\t\t}\n\t\t}\n\n\t\treturn items;\n\t}\n\tmap<X>(callback: (item: T) => X): Array<X> {\n\t\tconst array: Array<X> = [];\n\t\tfor(let { item } of this) {\n\t\t\tarray.push(callback(item));\n\t\t}\n\n\t\treturn array;\n\t}\n\n\tgetSharedMemory() {\n\t\treturn this.list.getSharedMemory();\n\t}\n\n\tfree() {\n\t\tthis.list.free();\n\t\tthis.cache.clear();\n\t}\n}\n\nexport interface CachedListConfig {\n\tinitWithBlock: SharedAllocatedMemory\n}\n\ninterface Item {\n\tpointer: number\n\tfree: () => void\n}"],"mappings":";;AAIA,IAA8B,IAA9B,MAAyH;CACxH,OAAgB,iBAAiB,EAAW;CAE5C;CACA;CACA,wBAAkC,IAAI,IAAI;CAE1C,YAAY,GAAkB,GAA8C;EAQ3E,AAPA,AAGC,KAAK,OAHH,IACU,IAAI,EAAW,GAAM,CAAM,IAE3B,IAAI,EAAW,CAAI,GAEhC,KAAK,OAAO,GAEZ,KAAK,KAAK,YAAY,MAA6B;GAClD,IAAI,IAAU,QAAQ,KAAK,GAAa,CAAC;GACzC,IAAG,GAAS;IACX,IAAI,IAAO,KAAK,MAAM,IAAI,CAAO;IAKjC,AAJA,AACC,MAAO,KAAK,SAAS,CAAO,GAG1B,MACF,EAAK,KAAK,GACV,KAAK,MAAM,OAAO,CAAO;GAE3B;EACD;CACD;CAEA,IAAI,SAAS;EACZ,OAAO,KAAK,KAAK;CAClB;CAEA,QAAQ;EAEP,AADA,KAAK,KAAK,MAAM,GAChB,KAAK,MAAM,MAAM;CAClB;CAEA,OAAO,GAAS;EAEf,AADA,KAAK,KAAK,OAAO,EAAK,OAAO,GAC7B,KAAK,MAAM,IAAI,EAAK,SAAS,CAAI;CAClC;CACA,OAAO,GAAS;EAEf,OADA,KAAK,MAAM,OAAO,EAAK,OAAO,GACvB,KAAK,KAAK,YAAY,EAAK,OAAO;CAC1C;CAEA,aAAa,GAAgC;EAC5C,IAAI,IAAO,KAAK,MAAM,IAAI,CAAO;EAQjC,OAPI,MACH,IAAO,KAAK,SAAS,CAAO,GACzB,KACF,KAAK,MAAM,IAAI,GAAS,CAAI,IAIvB;CACR;CAGA,EAAE,OAAO,YAAY;EACpB,IAAI,IAAW,KAAK,KAAK,OAAO,SAAS,CAAC;EAE1C,KAAI,IAAI,EAAE,MAAM,GAAa,sBAAmB,GAAU;GACzD,IAAI,IAAU,QAAQ,KAAK,GAAa,CAAC;GACzC,IAAG,CAAC,GACH;GAGD,IAAI,IAAO,KAAK,MAAM,IAAI,CAAO;GAQjC,AAPI,MACH,IAAO,KAAK,SAAS,CAAO,GACzB,KACF,KAAK,MAAM,IAAI,GAAS,CAAI,IAI3B,MACF,MAAM;IACL;IACA;GACD;EAEF;CACD;CACA,QAAQ,GAA6B,GAA+B;EACnE,KAAI,IAAI,EAAE,aAAU,MACnB,CAAG,CAAC,KAAU,EAAO,CAAI,MACxB,EAAS,CAAI;CAGhB;CAEA,KAAK,GAA+C;EACnD,KAAI,IAAI,EAAE,aAAU,MACnB,IAAG,EAAS,CAAI,GACf,OAAO;CAKV;CACA,OAAO,GAA4C;EAClD,IAAI,IAAQ,CAAC;EACb,KAAI,IAAI,EAAE,aAAU,MACnB,AAAG,EAAS,CAAI,KACf,EAAM,KAAK,CAAI;EAIjB,OAAO;CACR;CACA,IAAO,GAAoC;EAC1C,IAAM,IAAkB,CAAC;EACzB,KAAI,IAAI,EAAE,aAAU,MACnB,EAAM,KAAK,EAAS,CAAI,CAAC;EAG1B,OAAO;CACR;CAEA,kBAAkB;EACjB,OAAO,KAAK,KAAK,gBAAgB;CAClC;CAEA,OAAO;EAEN,AADA,KAAK,KAAK,KAAK,GACf,KAAK,MAAM,MAAM;CAClB;AACD"}
1
+ {"version":3,"file":"cached-item-list.js","names":[],"sources":["../src/cached-item-list.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport SharedList, { type SharedListMemory } from './shared-list';\n\nexport default abstract class CachedItemList<T extends Item> implements Iterable<{ item: T, deleteCurrent: () => void }> {\n\tstatic readonly ALLOCATE_COUNT = SharedList.ALLOCATE_COUNT;\n\n\tprotected heap: MemoryHeap;\n\tprotected list: SharedList;\n\tprotected cache: Map<number, T> = new Map();\n\n\tconstructor(heap: MemoryHeap, config?: CachedListConfig | SharedListMemory) {\n\t\tif(config) {\n\t\t\tthis.list = new SharedList(heap, config);\n\t\t} else {\n\t\t\tthis.list = new SharedList(heap);\n\t\t}\n\t\tthis.heap = heap;\n\n\t\tthis.list.onDelete = (pointerData: Uint32Array) => {\n\t\t\tlet pointer = Atomics.load(pointerData, 0);\n\t\t\tif(pointer) {\n\t\t\t\tlet item = this.cache.get(pointer);\n\t\t\t\tif(!item) {\n\t\t\t\t\titem = this.initItem(pointer);\n\t\t\t\t}\n\n\t\t\t\tif(item) {\n\t\t\t\t\titem.free();\n\t\t\t\t\tthis.cache.delete(pointer);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tget length() {\n\t\treturn this.list.length;\n\t}\n\n\tclear() {\n\t\tthis.list.clear();\n\t\tthis.cache.clear();\n\t}\n\n\tinsert(item: T) {\n\t\tthis.list.insert(item.pointer);\n\t\tthis.cache.set(item.pointer, item);\n\t}\n\tdelete(item: T) {\n\t\tthis.cache.delete(item.pointer);\n\t\tlet deleted = this.list.deleteValue(item.pointer);\n\t\t// This wrapper is single-threaded per instance, so reclaim the tombstoned node right away\n\t\tthis.list.compact();\n\t\treturn deleted;\n\t}\n\n\tcompact() {\n\t\tthis.list.compact();\n\t}\n\n\tgetByPointer(pointer: number): T | undefined {\n\t\tlet item = this.cache.get(pointer);\n\t\tif(!item) {\n\t\t\titem = this.initItem(pointer);\n\t\t\tif(item) {\n\t\t\t\tthis.cache.set(pointer, item);\n\t\t\t}\n\t\t}\n\n\t\treturn item;\n\t}\n\tprotected abstract initItem(pointer: number): T | undefined;\n\n\t*[Symbol.iterator]() {\n\t\tlet iterator = this.list[Symbol.iterator]();\n\n\t\tfor(let { data: pointerData, deleteCurrent } of iterator) {\n\t\t\tlet pointer = Atomics.load(pointerData, 0);\n\t\t\tif(!pointer) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet item = this.cache.get(pointer);\n\t\t\tif(!item) {\n\t\t\t\titem = this.initItem(pointer);\n\t\t\t\tif(item) {\n\t\t\t\t\tthis.cache.set(pointer, item);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(item) {\n\t\t\t\tyield {\n\t\t\t\t\titem,\n\t\t\t\t\tdeleteCurrent,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\tforEach(callback: (item: T) => void, filter?: (item: T) => boolean) {\n\t\tfor(let { item } of this) {\n\t\t\tif(!filter || filter(item)) {\n\t\t\t\tcallback(item);\n\t\t\t}\n\t\t}\n\t}\n\n\tfind(callback: (item: T) => boolean): T | undefined {\n\t\tfor(let { item } of this) {\n\t\t\tif(callback(item)) {\n\t\t\t\treturn item;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\tfilter(callback: (entity: T) => boolean): Array<T> {\n\t\tlet items = [];\n\t\tfor(let { item } of this) {\n\t\t\tif(callback(item)) {\n\t\t\t\titems.push(item);\n\t\t\t}\n\t\t}\n\n\t\treturn items;\n\t}\n\tmap<X>(callback: (item: T) => X): Array<X> {\n\t\tconst array: Array<X> = [];\n\t\tfor(let { item } of this) {\n\t\t\tarray.push(callback(item));\n\t\t}\n\n\t\treturn array;\n\t}\n\n\tgetSharedMemory() {\n\t\treturn this.list.getSharedMemory();\n\t}\n\n\tfree() {\n\t\tthis.list.free();\n\t\tthis.cache.clear();\n\t}\n}\n\nexport interface CachedListConfig {\n\tinitWithBlock: SharedAllocatedMemory\n}\n\ninterface Item {\n\tpointer: number\n\tfree: () => void\n}"],"mappings":";;AAIA,IAA8B,IAA9B,MAAyH;CACxH,OAAgB,iBAAiB,EAAW;CAE5C;CACA;CACA,wBAAkC,IAAI,IAAI;CAE1C,YAAY,GAAkB,GAA8C;EAQ3E,AAPA,AAGC,KAAK,OAHH,IACU,IAAI,EAAW,GAAM,CAAM,IAE3B,IAAI,EAAW,CAAI,GAEhC,KAAK,OAAO,GAEZ,KAAK,KAAK,YAAY,MAA6B;GAClD,IAAI,IAAU,QAAQ,KAAK,GAAa,CAAC;GACzC,IAAG,GAAS;IACX,IAAI,IAAO,KAAK,MAAM,IAAI,CAAO;IAKjC,AAJA,AACC,MAAO,KAAK,SAAS,CAAO,GAG1B,MACF,EAAK,KAAK,GACV,KAAK,MAAM,OAAO,CAAO;GAE3B;EACD;CACD;CAEA,IAAI,SAAS;EACZ,OAAO,KAAK,KAAK;CAClB;CAEA,QAAQ;EAEP,AADA,KAAK,KAAK,MAAM,GAChB,KAAK,MAAM,MAAM;CAClB;CAEA,OAAO,GAAS;EAEf,AADA,KAAK,KAAK,OAAO,EAAK,OAAO,GAC7B,KAAK,MAAM,IAAI,EAAK,SAAS,CAAI;CAClC;CACA,OAAO,GAAS;EACf,KAAK,MAAM,OAAO,EAAK,OAAO;EAC9B,IAAI,IAAU,KAAK,KAAK,YAAY,EAAK,OAAO;EAGhD,OADA,KAAK,KAAK,QAAQ,GACX;CACR;CAEA,UAAU;EACT,KAAK,KAAK,QAAQ;CACnB;CAEA,aAAa,GAAgC;EAC5C,IAAI,IAAO,KAAK,MAAM,IAAI,CAAO;EAQjC,OAPI,MACH,IAAO,KAAK,SAAS,CAAO,GACzB,KACF,KAAK,MAAM,IAAI,GAAS,CAAI,IAIvB;CACR;CAGA,EAAE,OAAO,YAAY;EACpB,IAAI,IAAW,KAAK,KAAK,OAAO,SAAS,CAAC;EAE1C,KAAI,IAAI,EAAE,MAAM,GAAa,sBAAmB,GAAU;GACzD,IAAI,IAAU,QAAQ,KAAK,GAAa,CAAC;GACzC,IAAG,CAAC,GACH;GAGD,IAAI,IAAO,KAAK,MAAM,IAAI,CAAO;GAQjC,AAPI,MACH,IAAO,KAAK,SAAS,CAAO,GACzB,KACF,KAAK,MAAM,IAAI,GAAS,CAAI,IAI3B,MACF,MAAM;IACL;IACA;GACD;EAEF;CACD;CACA,QAAQ,GAA6B,GAA+B;EACnE,KAAI,IAAI,EAAE,aAAU,MACnB,CAAG,CAAC,KAAU,EAAO,CAAI,MACxB,EAAS,CAAI;CAGhB;CAEA,KAAK,GAA+C;EACnD,KAAI,IAAI,EAAE,aAAU,MACnB,IAAG,EAAS,CAAI,GACf,OAAO;CAKV;CACA,OAAO,GAA4C;EAClD,IAAI,IAAQ,CAAC;EACb,KAAI,IAAI,EAAE,aAAU,MACnB,AAAG,EAAS,CAAI,KACf,EAAM,KAAK,CAAI;EAIjB,OAAO;CACR;CACA,IAAO,GAAoC;EAC1C,IAAM,IAAkB,CAAC;EACzB,KAAI,IAAI,EAAE,aAAU,MACnB,EAAM,KAAK,EAAS,CAAI,CAAC;EAG1B,OAAO;CACR;CAEA,kBAAkB;EACjB,OAAO,KAAK,KAAK,gBAAgB;CAClC;CAEA,OAAO;EAEN,AADA,KAAK,KAAK,KAAK,GACf,KAAK,MAAM,MAAM;CAClB;AACD"}
@@ -1,6 +1,6 @@
1
- import type { TypedArrayConstructor } from './interfaces/typed-array-constructor';
2
1
  import type MemoryHeap from './memory-heap';
3
- export default class LocalPool<T extends Uint32Array | Int32Array | Float32Array | Float64Array = Uint32Array> implements Iterable<T> {
2
+ import { type NumericArray, type TypedArrayConstructor } from './utils/array-type';
3
+ export default class LocalPool<T extends NumericArray = Uint32Array> implements Iterable<T> {
4
4
  private memory;
5
5
  private pointers;
6
6
  private recycledIndexes;
@@ -14,8 +14,8 @@ export default class LocalPool<T extends Uint32Array | Int32Array | Float32Array
14
14
  get bufferLength(): number;
15
15
  constructor(memory: MemoryHeap, config: LocalPoolConfig<T>);
16
16
  at(index: number): T;
17
- get(index: number, dataIndex?: number): number;
18
- push(values: number | Array<number>): number;
17
+ get(index: number, dataIndex?: number): T[number];
18
+ push(values: T[number] | Array<T[number]>): number;
19
19
  deleteIndex(index: number): void;
20
20
  clear(): void;
21
21
  [Symbol.iterator](): Generator<T, void, unknown>;
@@ -23,7 +23,7 @@ export default class LocalPool<T extends Uint32Array | Int32Array | Float32Array
23
23
  private getDataBlock;
24
24
  free(): void;
25
25
  }
26
- interface LocalPoolConfig<T extends Uint32Array | Int32Array | Float32Array | Float64Array> {
26
+ interface LocalPoolConfig<T extends NumericArray> {
27
27
  maxChunkSize?: number;
28
28
  type: TypedArrayConstructor<T>;
29
29
  dataLength?: number;
@@ -1,7 +1,8 @@
1
1
  import { getPointer as e } from "./utils/pointer.js";
2
2
  import t from "./allocated-memory.js";
3
+ import { getArrayTypeCode as n, getByteMultipler as r } from "./utils/array-type.js";
3
4
  //#region src/local-pool.ts
4
- var n = class {
5
+ var i = class {
5
6
  memory;
6
7
  pointers = [];
7
8
  recycledIndexes = [];
@@ -19,12 +20,12 @@ var n = class {
19
20
  }
20
21
  constructor(e, t) {
21
22
  this.memory = e;
22
- let n = t?.dataLength ?? 1, r = t?.maxChunkSize ?? 100;
23
- this.dataLength = n, this.maxChunkSize = r, this.typeConstructor = t.type, this.typeConstructor === Float64Array && (this.byteMultipler = 2);
24
- let i = e.allocUI32(r * n * this.byteMultipler);
25
- this.pointers.push(i.pointer);
26
- let a = new this.typeConstructor(i.data.buffer, i.bufferByteOffset, this.dataLength * this.maxChunkSize);
27
- this.fullDataBlocks[0] = a;
23
+ let i = t?.dataLength ?? 1, a = t?.maxChunkSize ?? 100;
24
+ this.dataLength = i, this.maxChunkSize = a, this.typeConstructor = t.type, this.byteMultipler = r(n(t.type));
25
+ let o = e.allocUI32(a * i * this.byteMultipler);
26
+ this.pointers.push(o.pointer);
27
+ let s = new this.typeConstructor(o.data.buffer, o.bufferByteOffset, this.dataLength * this.maxChunkSize);
28
+ this.fullDataBlocks[0] = s;
28
29
  }
29
30
  at(e) {
30
31
  let t = this.fullDataBlocks[Math.floor(e / this.maxChunkSize)];
@@ -36,7 +37,7 @@ var n = class {
36
37
  return this.fullDataBlocks[Math.floor(e / this.maxChunkSize)][e % this.maxChunkSize * n + t];
37
38
  }
38
39
  push(e) {
39
- let t = typeof e == "number";
40
+ let t = typeof e != "object";
40
41
  if (!t && e.length > this.dataLength) throw Error(`Can't insert ${e.length} array into shared list of ${this.dataLength} dataLength`);
41
42
  let n = this.recycledIndexes.pop();
42
43
  n === void 0 && (n = this.totalLength++);
@@ -48,7 +49,9 @@ var n = class {
48
49
  this.fullDataBlocks[r] = t;
49
50
  }
50
51
  let i = this.fullDataBlocks[r], a = n % this.maxChunkSize, o = this.dataLength * a;
51
- return t ? i[o] = e : i.set(e, o), n;
52
+ if (t) i[o] = e;
53
+ else for (let t = 0; t < e.length; t++) i[o + t] = e[t];
54
+ return n;
52
55
  }
53
56
  deleteIndex(e) {
54
57
  this.recycledIndexes.push(e);
@@ -85,6 +88,6 @@ var n = class {
85
88
  }
86
89
  };
87
90
  //#endregion
88
- export { n as default };
91
+ export { i as default };
89
92
 
90
93
  //# sourceMappingURL=local-pool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-pool.js","names":[],"sources":["../src/local-pool.ts"],"sourcesContent":["import AllocatedMemory from './allocated-memory';\nimport type { TypedArrayConstructor } from './interfaces/typed-array-constructor';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer } from './utils/pointer';\n\n// Array with stable indexes and maximum contiguous memory sizes (necessary to fit large data sets into max 1MB buffers)\n// Can only do insert/deletions from a single thread - useful if other threads are known to be read-only\nexport default class LocalPool<T extends Uint32Array | Int32Array | Float32Array | Float64Array = Uint32Array> implements Iterable<T> {\n\tprivate memory: MemoryHeap;\n\tprivate pointers: Array<number> = [];\n\tprivate recycledIndexes: Array<number> = [];\n\tprivate totalLength = 0;\n\treadonly maxChunkSize: number = 100;\n\treadonly dataLength: number = 1;\n\treadonly byteMultipler: number = 1;\n\tprivate typeConstructor: TypedArrayConstructor<T>;\n\tprivate fullDataBlocks: { [key: number]: T } = {};\n\n\tget length(): number {\n\t\treturn this.totalLength - this.recycledIndexes.length;\n\t}\n\tget bufferLength(): number {\n\t\treturn this.maxChunkSize * this.pointers.length;\n\t}\n\n\tconstructor(memory: MemoryHeap, config: LocalPoolConfig<T>) {\n\t\tthis.memory = memory;\n\n\t\tconst dataLength = config?.dataLength ?? 1;\n\t\tconst maxLength = config?.maxChunkSize ?? 100;\n\t\tthis.dataLength = dataLength;\n\t\tthis.maxChunkSize = maxLength;\n\n\t\tthis.typeConstructor = config.type;\n\t\t// @ts-expect-error\n\t\tif(this.typeConstructor === Float64Array) {\n\t\t\tthis.byteMultipler = 2;\n\t\t}\n\n\t\tlet firstArray = memory.allocUI32(maxLength * dataLength * this.byteMultipler);\n\t\tthis.pointers.push(firstArray.pointer);\n\t\tlet data: T = new this.typeConstructor(firstArray.data.buffer, firstArray.bufferByteOffset, this.dataLength * this.maxChunkSize);\n\t\tthis.fullDataBlocks[0] = data;\n\t}\n\n\tat(index: number): T {\n\t\tlet dataBlock = this.fullDataBlocks[Math.floor(index / this.maxChunkSize)];\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.fullDataBlocks[Math.floor(index / this.maxChunkSize)];\n\t\treturn dataBlock[(index % this.maxChunkSize) * dataLength + dataIndex];\n\t}\n\n\tpush(values: number | Array<number>): number {\n\t\tconst isSingleNumber = typeof values === 'number';\n\t\tif(!isSingleNumber && values.length > this.dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${this.dataLength} dataLength`);\n\t\t}\n\n\t\tlet newIndex = this.recycledIndexes.pop();\n\t\tif(newIndex === undefined) {\n\t\t\tnewIndex = this.totalLength++;\n\t\t}\n\t\t\n\t\t\n\t\tlet pointerIndex = Math.floor(newIndex / this.maxChunkSize);\n\t\tif(pointerIndex >= this.pointers.length) {\n\t\t\tlet newArray = this.memory.allocUI32(this.maxChunkSize * this.dataLength * this.byteMultipler);\n\t\t\tthis.pointers.push(newArray.pointer);\n\t\t\tlet data: T = new this.typeConstructor(newArray.data.buffer, newArray.bufferByteOffset, this.dataLength * this.maxChunkSize);\n\t\t\tthis.fullDataBlocks[pointerIndex] = data;\n\t\t}\n\n\t\tlet dataBlock = this.fullDataBlocks[pointerIndex];\n\t\tlet blockIndex = newIndex % this.maxChunkSize;\n\t\tlet startIndex = this.dataLength * blockIndex;\n\t\tif(isSingleNumber) {\n\t\t\tdataBlock[startIndex] = values;\n\t\t} else {\n\t\t\tdataBlock.set(values, startIndex);\n\t\t}\n\n\t\treturn newIndex;\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tthis.recycledIndexes.push(index);\n\t}\n\n\tclear() {\n\t\tthis.totalLength = 0;\n\t\tthis.recycledIndexes = [];\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycledIndexes) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < this.totalLength; 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.fullDataBlocks[pointerIndex];\n\t\tif(cachedDataBlock) {\n\t\t\treturn cachedDataBlock;\n\t\t}\n\t\tif(pointerIndex >= this.pointers.length) {\n\t\t\tlet newArray = this.memory.allocUI32(this.maxChunkSize * this.dataLength * this.byteMultipler);\n\t\t\tthis.pointers.push(newArray.pointer);\n\t\t}\n\n\t\tlet array = new AllocatedMemory(this.memory, getPointer(this.pointers[pointerIndex]));\n\t\tlet data: T = new this.typeConstructor(array.data.buffer, array.bufferByteOffset, this.dataLength * this.maxChunkSize);\n\t\tthis.fullDataBlocks[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\tfor(let pointer of this.pointers) {\n\t\t\tlet memory = new AllocatedMemory(this.memory, getPointer(pointer));\n\t\t\tmemory.free();\n\t\t}\n\t\tthis.pointers = [];\n\t\tthis.recycledIndexes = [];\n\t\tthis.totalLength = 0;\n\t\tthis.fullDataBlocks = {};\n\t}\n}\n\ninterface LocalPoolConfig<T extends Uint32Array | Int32Array | Float32Array | Float64Array> {\n\tmaxChunkSize?: number\n\ttype: TypedArrayConstructor<T>\n\tdataLength?: number\n}\nexport type { LocalPoolConfig };"],"mappings":"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"}
1
+ {"version":3,"file":"local-pool.js","names":[],"sources":["../src/local-pool.ts"],"sourcesContent":["import AllocatedMemory from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer } from './utils/pointer';\nimport { getArrayTypeCode, getByteMultipler, type NumericArray, type NumericArrayIO, type TypedArrayConstructor } from './utils/array-type';\n\n// Array with stable indexes and maximum contiguous memory sizes (necessary to fit large data sets into max 1MB buffers)\n// Can only do insert/deletions from a single thread - useful if other threads are known to be read-only\nexport default class LocalPool<T extends NumericArray = Uint32Array> implements Iterable<T> {\n\tprivate memory: MemoryHeap;\n\tprivate pointers: Array<number> = [];\n\tprivate recycledIndexes: Array<number> = [];\n\tprivate totalLength = 0;\n\treadonly maxChunkSize: number = 100;\n\treadonly dataLength: number = 1;\n\treadonly byteMultipler: number = 1;\n\tprivate typeConstructor: TypedArrayConstructor<T>;\n\tprivate fullDataBlocks: { [key: number]: T } = {};\n\n\tget length(): number {\n\t\treturn this.totalLength - this.recycledIndexes.length;\n\t}\n\tget bufferLength(): number {\n\t\treturn this.maxChunkSize * this.pointers.length;\n\t}\n\n\tconstructor(memory: MemoryHeap, config: LocalPoolConfig<T>) {\n\t\tthis.memory = memory;\n\n\t\tconst dataLength = config?.dataLength ?? 1;\n\t\tconst maxLength = config?.maxChunkSize ?? 100;\n\t\tthis.dataLength = dataLength;\n\t\tthis.maxChunkSize = maxLength;\n\n\t\tthis.typeConstructor = config.type;\n\t\tthis.byteMultipler = getByteMultipler(getArrayTypeCode(config.type));\n\n\t\tlet firstArray = memory.allocUI32(maxLength * dataLength * this.byteMultipler);\n\t\tthis.pointers.push(firstArray.pointer);\n\t\tlet data: T = new this.typeConstructor(firstArray.data.buffer, firstArray.bufferByteOffset, this.dataLength * this.maxChunkSize);\n\t\tthis.fullDataBlocks[0] = data;\n\t}\n\n\tat(index: number): T {\n\t\tlet dataBlock = this.fullDataBlocks[Math.floor(index / this.maxChunkSize)];\n\t\treturn this.getDataBlock(dataBlock, index % this.maxChunkSize);\n\t}\n\tget(index: number, dataIndex = 0): T[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.fullDataBlocks[Math.floor(index / this.maxChunkSize)] as NumericArrayIO;\n\t\treturn dataBlock[(index % this.maxChunkSize) * dataLength + dataIndex];\n\t}\n\n\tpush(values: T[number] | Array<T[number]>): number {\n\t\tconst isSingleValue = typeof values !== 'object';\n\t\tif(!isSingleValue && values.length > this.dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${this.dataLength} dataLength`);\n\t\t}\n\n\t\tlet newIndex = this.recycledIndexes.pop();\n\t\tif(newIndex === undefined) {\n\t\t\tnewIndex = this.totalLength++;\n\t\t}\n\n\n\t\tlet pointerIndex = Math.floor(newIndex / this.maxChunkSize);\n\t\tif(pointerIndex >= this.pointers.length) {\n\t\t\tlet newArray = this.memory.allocUI32(this.maxChunkSize * this.dataLength * this.byteMultipler);\n\t\t\tthis.pointers.push(newArray.pointer);\n\t\t\tlet data: T = new this.typeConstructor(newArray.data.buffer, newArray.bufferByteOffset, this.dataLength * this.maxChunkSize);\n\t\t\tthis.fullDataBlocks[pointerIndex] = data;\n\t\t}\n\n\t\tlet dataBlock = this.fullDataBlocks[pointerIndex] as NumericArrayIO;\n\t\tlet blockIndex = newIndex % this.maxChunkSize;\n\t\tlet startIndex = this.dataLength * blockIndex;\n\t\tif(isSingleValue) {\n\t\t\tdataBlock[startIndex] = values;\n\t\t} else {\n\t\t\tfor(let i = 0; i < values.length; i++) {\n\t\t\t\tdataBlock[startIndex + i] = values[i];\n\t\t\t}\n\t\t}\n\n\t\treturn newIndex;\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tthis.recycledIndexes.push(index);\n\t}\n\n\tclear() {\n\t\tthis.totalLength = 0;\n\t\tthis.recycledIndexes = [];\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycledIndexes) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < this.totalLength; 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.fullDataBlocks[pointerIndex];\n\t\tif(cachedDataBlock) {\n\t\t\treturn cachedDataBlock;\n\t\t}\n\t\tif(pointerIndex >= this.pointers.length) {\n\t\t\tlet newArray = this.memory.allocUI32(this.maxChunkSize * this.dataLength * this.byteMultipler);\n\t\t\tthis.pointers.push(newArray.pointer);\n\t\t}\n\n\t\tlet array = new AllocatedMemory(this.memory, getPointer(this.pointers[pointerIndex]));\n\t\tlet data: T = new this.typeConstructor(array.data.buffer, array.bufferByteOffset, this.dataLength * this.maxChunkSize);\n\t\tthis.fullDataBlocks[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\tfor(let pointer of this.pointers) {\n\t\t\tlet memory = new AllocatedMemory(this.memory, getPointer(pointer));\n\t\t\tmemory.free();\n\t\t}\n\t\tthis.pointers = [];\n\t\tthis.recycledIndexes = [];\n\t\tthis.totalLength = 0;\n\t\tthis.fullDataBlocks = {};\n\t}\n}\n\ninterface LocalPoolConfig<T extends NumericArray> {\n\tmaxChunkSize?: number\n\ttype: TypedArrayConstructor<T>\n\tdataLength?: number\n}\nexport type { LocalPoolConfig };"],"mappings":"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"}
@@ -1,8 +1,13 @@
1
1
  function e(e, t = 0) {
2
- for (; Atomics.compareExchange(e, t, 0, 1) !== 0;) "WorkerGlobalScope" in self && Atomics.wait(e, t, 1);
2
+ let n = Atomics.compareExchange(e, t, 0, 1);
3
+ if (n !== 0) {
4
+ n !== 2 && (n = Atomics.exchange(e, t, 2));
5
+ let r = typeof self < "u" && "WorkerGlobalScope" in self;
6
+ for (; n !== 0;) r && Atomics.wait(e, t, 2), n = Atomics.exchange(e, t, 2);
7
+ }
3
8
  }
4
9
  function t(e, t = 0) {
5
- Atomics.compareExchange(e, t, 1, 0) !== 1 && console.warn("We are unlocking when it was not locked!"), Atomics.notify(e, t);
10
+ Atomics.exchange(e, t, 0) === 2 && Atomics.notify(e, t, 1);
6
11
  }
7
12
  var n = 1;
8
13
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"simple-lock.js","names":[],"sources":["../../src/lock/simple-lock.ts"],"sourcesContent":["const UNLOCKED = 0;\nconst LOCKED = 1;\nexport function lock(data: Int32Array, index: number = 0) {\n\t// Wait over and over again until we are one who set this from UNLOCKED to LOCKED\n\twhile(Atomics.compareExchange(data, index, UNLOCKED, LOCKED) !== UNLOCKED) {\n\t\tif('WorkerGlobalScope' in self) {\n\t\t\tAtomics.wait(data, index, LOCKED);\n\t\t} else {\n\t\t\t// TODO: Spin-locks suck....\n\t\t}\n\t}\n}\nexport function unlock(data: Int32Array, index: number = 0) {\n\tif(Atomics.compareExchange(data, index, LOCKED, UNLOCKED) !== LOCKED) {\n\t\tconsole.warn('We are unlocking when it was not locked!');\n\t}\n\n\tAtomics.notify(data, index);\n}\n\nexport const SIMPLE_LOCK_ALLOCATE_COUNT = 1;"],"mappings":"AAEA,SAAgB,EAAK,GAAkB,IAAgB,GAAG;CAEzD,OAAM,QAAQ,gBAAgB,GAAM,GAAO,GAAU,CAAM,MAAM,IAChE,AAAG,uBAAuB,QACzB,QAAQ,KAAK,GAAM,GAAO,CAAM;AAKnC;AACA,SAAgB,EAAO,GAAkB,IAAgB,GAAG;CAK3D,AAJG,QAAQ,gBAAgB,GAAM,GAAO,GAAQ,CAAQ,MAAM,KAC7D,QAAQ,KAAK,0CAA0C,GAGxD,QAAQ,OAAO,GAAM,CAAK;AAC3B;AAEA,IAAa,IAA6B"}
1
+ {"version":3,"file":"simple-lock.js","names":[],"sources":["../../src/lock/simple-lock.ts"],"sourcesContent":["// Three-state futex mutex (Drepper / Lars T Hansen): 0 = unlocked, 1 = locked with no waiters, 2 = locked and contended.\n// Tracking contention lets unlock skip Atomics.notify entirely on the common uncontended path (notify is expensive even\n// with zero waiters), while still waking a waiter whenever one parked itself by moving the state to CONTENDED.\nconst UNLOCKED = 0;\nconst LOCKED = 1;\nconst CONTENDED = 2;\n\nexport function lock(data: Int32Array, index: number = 0) {\n\tlet c = Atomics.compareExchange(data, index, UNLOCKED, LOCKED);\n\tif(c !== UNLOCKED) {\n\t\t// Mark the lock contended so the current holder knows to notify us on release\n\t\tif(c !== CONTENDED) {\n\t\t\tc = Atomics.exchange(data, index, CONTENDED);\n\t\t}\n\t\tlet isWorker = typeof self !== 'undefined' && 'WorkerGlobalScope' in self;\n\t\twhile(c !== UNLOCKED) {\n\t\t\tif(isWorker) {\n\t\t\t\tAtomics.wait(data, index, CONTENDED);\n\t\t\t}\n\t\t\t// On the main thread Atomics.wait throws, so this loop degrades to a spin re-acquire\n\t\t\tc = Atomics.exchange(data, index, CONTENDED);\n\t\t}\n\t}\n}\nexport function unlock(data: Int32Array, index: number = 0) {\n\t// If the lock was contended a waiter may be parked, so publish the release and wake exactly one of them\n\tif(Atomics.exchange(data, index, UNLOCKED) === CONTENDED) {\n\t\tAtomics.notify(data, index, 1);\n\t}\n}\n\nexport const SIMPLE_LOCK_ALLOCATE_COUNT = 1;\n"],"mappings":"AAOA,SAAgB,EAAK,GAAkB,IAAgB,GAAG;CACzD,IAAI,IAAI,QAAQ,gBAAgB,GAAM,GAAO,GAAU,CAAM;CAC7D,IAAG,MAAM,GAAU;EAElB,AAAG,MAAM,MACR,IAAI,QAAQ,SAAS,GAAM,GAAO,CAAS;EAE5C,IAAI,IAAW,OAAO,OAAS,OAAe,uBAAuB;EACrE,OAAM,MAAM,IAKX,AAJG,KACF,QAAQ,KAAK,GAAM,GAAO,CAAS,GAGpC,IAAI,QAAQ,SAAS,GAAM,GAAO,CAAS;CAE7C;AACD;AACA,SAAgB,EAAO,GAAkB,IAAgB,GAAG;CAE3D,AAAG,QAAQ,SAAS,GAAM,GAAO,CAAQ,MAAM,KAC9C,QAAQ,OAAO,GAAM,GAAO,CAAC;AAE/B;AAEA,IAAa,IAA6B"}
@@ -1,5 +1,7 @@
1
1
  import type { Pow2 } from './interfaces/pow2';
2
2
  import type { TypedArray } from './interfaces/typed-array';
3
+ declare const SIZEOF_STATE: number;
4
+ declare const SIZEOF_MEM_BLOCK: number;
3
5
  export default class MemoryBuffer {
4
6
  buf: ArrayBufferLike;
5
7
  protected readonly start: number;
@@ -28,6 +30,7 @@ export default class MemoryBuffer {
28
30
  protected set end(x: number);
29
31
  get top(): number;
30
32
  protected set top(x: number);
33
+ get isEmpty(): boolean;
31
34
  protected get _free(): number;
32
35
  protected set _free(block: number);
33
36
  protected get _used(): number;
@@ -77,6 +80,7 @@ export default class MemoryBuffer {
77
80
  */
78
81
  protected insert(block: number): void;
79
82
  }
83
+ export { SIZEOF_STATE, SIZEOF_MEM_BLOCK };
80
84
  type Type = 'u8' | 'u8c' | 'i8' | 'u16' | 'i16' | 'u32' | 'i32' | 'f32' | 'f64';
81
85
  interface MemoryBufferConfig {
82
86
  /**
@@ -182,4 +186,3 @@ interface MemoryBufferStats {
182
186
  */
183
187
  total: number;
184
188
  }
185
- export {};
@@ -21,7 +21,7 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
21
21
  state;
22
22
  lock;
23
23
  constructor(e = {}) {
24
- if (this.buf = e.buf ? e.buf : new ArrayBuffer(e.size || 4096), this.start = e.start == null ? 0 : b(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, p / 4), this.lock = new Int32Array(this.buf, this.start + this.state.byteLength - 4, 1), !e.skipInitialization) {
24
+ if (this.buf = e.buf ? e.buf : new ArrayBuffer(e.size || 4096), this.start = e.start == null ? 0 : b(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, 8), this.lock = new Int32Array(this.buf, this.start + this.state.byteLength - 4, 1), !e.skipInitialization) {
25
25
  let t = e.align || 8;
26
26
  if (t < 8) throw Error(`invalid alignment: ${t}, must be a pow2 and >= 8`);
27
27
  let n = this.initialTop(t), r = e.end == null ? this.buf.byteLength : Math.min(e.end, this.buf.byteLength);
@@ -64,7 +64,7 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
64
64
  malloc(n) {
65
65
  if (n <= 0) return 0;
66
66
  e(this.lock);
67
- let r = b(n + g, this.align), i = this.end, a = this.top, o = this._free, s = 0;
67
+ let r = b(n + 8, this.align), i = this.end, a = this.top, o = this._free, s = 0;
68
68
  for (; o;) {
69
69
  let e = this.blockSize(o), n = o + e >= a;
70
70
  if (n || e >= r) {
@@ -102,7 +102,7 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
102
102
  return r && r !== n && this.u8.copyWithin(v(r), v(n), a), v(r);
103
103
  }
104
104
  reallocBlock(e, t) {
105
- let n = this.blockSize(e), r = e + n, i = r >= this.top, a = b(t + g, this.align);
105
+ let n = this.blockSize(e), r = e + n, i = r >= this.top, a = b(t + 8, this.align);
106
106
  if (a <= n) {
107
107
  if (this.doSplit) {
108
108
  let t = n - a;
@@ -126,7 +126,7 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
126
126
  t = y(t);
127
127
  let n = this._used;
128
128
  for (; n;) {
129
- if (n === t) return this.blockSize(t) - g;
129
+ if (n === t) return this.blockSize(t) - 8;
130
130
  n = this.blockNext(n);
131
131
  }
132
132
  }
@@ -172,6 +172,9 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
172
172
  set top(e) {
173
173
  Atomics.store(this.state, a, e);
174
174
  }
175
+ get isEmpty() {
176
+ return this._used === 0;
177
+ }
175
178
  get _free() {
176
179
  return Atomics.load(this.state, r);
177
180
  }
@@ -200,7 +203,7 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
200
203
  return this.state[l];
201
204
  }
202
205
  set minSplit(e) {
203
- if (e <= g) throw Error(`illegal min split threshold: ${e}, require at least 9`);
206
+ if (e <= 8) throw Error(`illegal min split threshold: ${e}, require at least 9`);
204
207
  this.state[l] = e;
205
208
  }
206
209
  blockSize(e) {
@@ -226,7 +229,7 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
226
229
  this.insert(this.initBlock(e + this.setBlockSize(e, t), n, 0)), this.doCompact && this.compact();
227
230
  }
228
231
  initialTop(e = this.align) {
229
- return b(this.start + p + g, e) - g;
232
+ return b(this.start + 32 + 8, e) - 8;
230
233
  }
231
234
  compact() {
232
235
  let e = this._free, t = 0, n = 0, r, i = !1;
@@ -253,15 +256,15 @@ var r = 0, i = 1, a = 2, o = 3, s = 4, c = 5, l = 6, u = 1, d = 2, f = {
253
256
  }
254
257
  };
255
258
  function v(e) {
256
- return e > 0 ? e + g : 0;
259
+ return e > 0 ? e + 8 : 0;
257
260
  }
258
261
  function y(e) {
259
- return e > 0 ? e - g : 0;
262
+ return e > 0 ? e - 8 : 0;
260
263
  }
261
264
  function b(e, t) {
262
265
  return t--, e + t & ~t;
263
266
  }
264
267
  //#endregion
265
- export { _ as default };
268
+ export { g as SIZEOF_MEM_BLOCK, p as SIZEOF_STATE, _ as default };
266
269
 
267
270
  //# 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\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}\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\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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"}
@@ -6,11 +6,13 @@ export default class MemoryHeap {
6
6
  isClone: boolean;
7
7
  private memory;
8
8
  get bufferSize(): number;
9
+ get maxAllocationLength(): number;
9
10
  constructor(config?: MemoryHeapConfig | MemoryHeapMemory);
10
11
  addSharedBuffer(data: GrowBufferData): void;
11
12
  private growBuffer;
12
13
  private createBuffer;
13
14
  addOnGrowBufferHandlers(handler: OnGrowBuffer): void;
15
+ ensureSpareBuffer(): boolean;
14
16
  allocUI32(count: number): AllocatedMemory;
15
17
  getSharedAlloc(shared: SharedAllocatedMemory): AllocatedMemory | undefined;
16
18
  get currentUsed(): number;