@daneren2005/shared-memory-objects 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -13
- package/dist/allocated-memory.js +1 -1
- package/dist/allocated-memory.js.map +1 -1
- package/dist/constant-string.js +2 -2
- package/dist/constant-string.js.map +1 -1
- package/dist/local-pool.d.ts +5 -5
- package/dist/local-pool.js +15 -12
- package/dist/local-pool.js.map +1 -1
- package/dist/lock/read-write-lock.js +25 -11
- package/dist/lock/read-write-lock.js.map +1 -1
- package/dist/lock/simple-lock.js +7 -2
- package/dist/lock/simple-lock.js.map +1 -1
- package/dist/memory-heap.d.ts +2 -0
- package/dist/memory-heap.js +28 -23
- package/dist/memory-heap.js.map +1 -1
- package/dist/serialize-object.js +1 -1
- package/dist/serialize-object.js.map +1 -1
- package/dist/shared-list.d.ts +11 -6
- package/dist/shared-list.js +55 -59
- package/dist/shared-list.js.map +1 -1
- package/dist/shared-map.d.ts +35 -12
- package/dist/shared-map.js +185 -82
- package/dist/shared-map.js.map +1 -1
- package/dist/shared-pointer-list.js +3 -3
- package/dist/shared-pointer-list.js.map +1 -1
- package/dist/shared-pool.d.ts +16 -7
- package/dist/shared-pool.js +74 -57
- package/dist/shared-pool.js.map +1 -1
- package/dist/shared-stack.d.ts +9 -8
- package/dist/shared-stack.js +68 -79
- package/dist/shared-stack.js.map +1 -1
- package/dist/shared-string.js +3 -3
- package/dist/shared-string.js.map +1 -1
- package/dist/shared-vector.d.ts +8 -6
- package/dist/shared-vector.js +34 -57
- package/dist/shared-vector.js.map +1 -1
- package/dist/spatial/shared-quadtree.d.ts +67 -0
- package/dist/spatial/shared-quadtree.js +361 -0
- package/dist/spatial/shared-quadtree.js.map +1 -0
- package/dist/spatial/shared-spatial-grid.d.ts +78 -0
- package/dist/spatial/shared-spatial-grid.js +426 -0
- package/dist/spatial/shared-spatial-grid.js.map +1 -0
- package/dist/spatial/shared-spatial-map.d.ts +87 -0
- package/dist/spatial/shared-spatial-map.js +555 -0
- package/dist/spatial/shared-spatial-map.js.map +1 -0
- package/dist/spatial/spatial-entity.d.ts +11 -0
- package/dist/spatial/spatial-entity.js +19 -0
- package/dist/spatial/spatial-entity.js.map +1 -0
- package/dist/spatial/spatial-neighbors.d.ts +21 -0
- package/dist/spatial/spatial-neighbors.js +55 -0
- package/dist/spatial/spatial-neighbors.js.map +1 -0
- package/dist/utils/array-type.d.ts +20 -0
- package/dist/utils/array-type.js +36 -0
- package/dist/utils/array-type.js.map +1 -0
- package/dist/utils/hash.d.ts +3 -0
- package/dist/utils/hash.js +21 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/pointer.d.ts +8 -6
- package/dist/utils/pointer.js +22 -17
- package/dist/utils/pointer.js.map +1 -1
- package/package.json +8 -2
package/dist/shared-pool.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { getPointer as e, loadRawPointer as t, storeRawPointer as n } from "./utils/pointer.js";
|
|
2
2
|
import r from "./allocated-memory.js";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
3
|
+
import { getArrayTypeCode as i, getByteMultipler as a, makeArrayView as o } from "./utils/array-type.js";
|
|
4
|
+
import { lock as s, unlock as c } from "./lock/simple-lock.js";
|
|
5
|
+
import l from "./shared-stack.js";
|
|
5
6
|
//#region src/shared-pool.ts
|
|
6
|
-
var
|
|
7
|
+
var u = 0, d = 1, f = 2, p = 3, m = 4, h = 5, g = 100, _ = 1e6, v = 1e5, y = class y {
|
|
7
8
|
static ALLOCATE_COUNT = 6;
|
|
9
|
+
static getAllocateCount(e, t) {
|
|
10
|
+
let n = t?.maxChunkSize ?? g, r = t?.maxLength ?? _, i = t?.maxRecycledLength ?? v, a = l.getMaxSegmentLength(e.maxAllocationLength), o = l.getAllocateCount(r / n, void 0, a), s = l.getAllocateCount(i, void 0, a);
|
|
11
|
+
return y.ALLOCATE_COUNT + o + s;
|
|
12
|
+
}
|
|
8
13
|
memory;
|
|
9
14
|
firstBlock;
|
|
10
15
|
uint16Array;
|
|
@@ -12,19 +17,20 @@ var s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = cla
|
|
|
12
17
|
pointerStack;
|
|
13
18
|
recycleStack;
|
|
14
19
|
maxLength;
|
|
15
|
-
|
|
20
|
+
ownsFirstBlock;
|
|
21
|
+
cachedFullDataBlock = [];
|
|
16
22
|
cachedMaxChunkSize;
|
|
17
23
|
cachedDataLength;
|
|
18
24
|
cachedType;
|
|
19
25
|
cachedByteMultipler;
|
|
20
26
|
get length() {
|
|
21
|
-
return Atomics.load(this.firstBlock.data,
|
|
27
|
+
return Atomics.load(this.firstBlock.data, u) - this.recycleStack.length;
|
|
22
28
|
}
|
|
23
29
|
get maxChunkSize() {
|
|
24
30
|
return this.cachedMaxChunkSize;
|
|
25
31
|
}
|
|
26
32
|
set maxChunkSize(e) {
|
|
27
|
-
Atomics.store(this.firstBlock.data,
|
|
33
|
+
Atomics.store(this.firstBlock.data, f, e);
|
|
28
34
|
}
|
|
29
35
|
get type() {
|
|
30
36
|
return this.cachedType;
|
|
@@ -45,29 +51,28 @@ var s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = cla
|
|
|
45
51
|
return this.cachedByteMultipler;
|
|
46
52
|
}
|
|
47
53
|
get usedMemory() {
|
|
48
|
-
let t = this.firstBlock.usedMemory;
|
|
49
|
-
for (let n of this.pointerStack) t += new r(this.memory, e(n)).usedMemory;
|
|
54
|
+
let t = this.ownsFirstBlock ? this.firstBlock.usedMemory : 0;
|
|
55
|
+
for (let n of this.pointerStack) t += new r(this.memory, e(n, this.memory.positionBits)).usedMemory;
|
|
50
56
|
return t + this.pointerStack.usedMemory + this.recycleStack.usedMemory;
|
|
51
57
|
}
|
|
52
|
-
constructor(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.cachedType = this.uint16Array[0], this.cachedDataLength = Math.max(1, this.uint16Array[1]), this.cachedMaxChunkSize = this.firstBlock.data[l], this.cachedByteMultipler = this.cachedType === 3 ? 2 : 1, this.maxLength = this.cachedMaxChunkSize * this.pointerStack.maxLength, this.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + u * Uint32Array.BYTES_PER_ELEMENT, 1);
|
|
58
|
+
constructor(n, i) {
|
|
59
|
+
this.memory = n, i && "firstBlock" in i ? (this.firstBlock = i.firstBlock instanceof r ? i.firstBlock : new r(n, i.firstBlock), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + d * Uint32Array.BYTES_PER_ELEMENT, 2), "type" in i || "dataLength" in i || "maxLength" in i || "maxChunkSize" in i || "maxRecycledLength" in i ? (this.initialize(i), this.ownsFirstBlock = !1) : (this.pointerStack = new l(n, { firstBlock: e(t(this.firstBlock.data, m), n.positionBits) }), this.recycleStack = new l(n, { firstBlock: e(t(this.firstBlock.data, h), n.positionBits) }), this.ownsFirstBlock = !0)) : (this.firstBlock = n.allocUI32(y.getAllocateCount(n, i)), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + d * Uint32Array.BYTES_PER_ELEMENT, 2), this.initialize(i), this.ownsFirstBlock = !0), this.cachedType = this.uint16Array[0], this.cachedDataLength = Math.max(1, this.uint16Array[1]), this.cachedMaxChunkSize = this.firstBlock.data[f], this.cachedByteMultipler = a(this.cachedType), this.maxLength = this.cachedMaxChunkSize * this.pointerStack.maxLength, this.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + p * Uint32Array.BYTES_PER_ELEMENT, 1);
|
|
60
|
+
}
|
|
61
|
+
initialize(e) {
|
|
62
|
+
let t = e?.dataLength ?? 1, r = e?.maxChunkSize ?? g, o = e?.maxLength ?? _, s = e?.maxRecycledLength ?? v, c = l.getMaxSegmentLength(this.memory.maxAllocationLength), u = o / r, d = l.getAllocateCount(u, void 0, c), f = l.getAllocateCount(s, void 0, c);
|
|
63
|
+
this.pointerStack = new l(this.memory, {
|
|
64
|
+
firstBlock: this.firstBlock.getSubAllocation(y.ALLOCATE_COUNT, d),
|
|
65
|
+
type: Uint32Array,
|
|
66
|
+
maxLength: u
|
|
67
|
+
}), n(this.firstBlock.data, m, this.pointerStack.pointer), this.recycleStack = new l(this.memory, {
|
|
68
|
+
firstBlock: this.firstBlock.getSubAllocation(y.ALLOCATE_COUNT + d, f),
|
|
69
|
+
type: Uint32Array,
|
|
70
|
+
maxLength: s
|
|
71
|
+
}), n(this.firstBlock.data, h, this.recycleStack.pointer);
|
|
72
|
+
let p = i(e?.type ?? Uint32Array);
|
|
73
|
+
this.type = p, this.dataLength = t, this.maxChunkSize = r;
|
|
74
|
+
let b = a(p), x = this.memory.allocUI32(r * t * b);
|
|
75
|
+
this.pointerStack.push(x.pointer);
|
|
71
76
|
}
|
|
72
77
|
at(e) {
|
|
73
78
|
let t = this.getFullDataBlock(e);
|
|
@@ -78,60 +83,72 @@ var s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = cla
|
|
|
78
83
|
if (t >= n) throw Error(`${t} is out of dataLength bounds ${n}`);
|
|
79
84
|
return this.getFullDataBlock(e)[e % this.cachedMaxChunkSize * n + t];
|
|
80
85
|
}
|
|
86
|
+
set(e, t, n) {
|
|
87
|
+
let r = this.cachedDataLength;
|
|
88
|
+
if (t >= r) throw Error(`${t} is out of dataLength bounds ${r}`);
|
|
89
|
+
let i = this.getFullDataBlock(e);
|
|
90
|
+
i[e % this.cachedMaxChunkSize * r + t] = n;
|
|
91
|
+
}
|
|
92
|
+
blockFor(e) {
|
|
93
|
+
return this.getFullDataBlock(e);
|
|
94
|
+
}
|
|
95
|
+
blockOffset(e) {
|
|
96
|
+
return e % this.cachedMaxChunkSize * this.cachedDataLength;
|
|
97
|
+
}
|
|
81
98
|
push(e) {
|
|
82
|
-
let t = this.cachedDataLength, n = typeof e
|
|
99
|
+
let t = this.cachedDataLength, n = typeof e != "object";
|
|
83
100
|
if (!n && e.length > t) throw Error(`Can't insert ${e.length} array into shared list of ${t} dataLength`);
|
|
84
|
-
let r = this.recycleStack.pop();
|
|
85
|
-
r === void 0 && (r = Atomics.add(this.firstBlock.data,
|
|
101
|
+
let r = this.recycleStack.length === 0 ? void 0 : this.recycleStack.pop();
|
|
102
|
+
r === void 0 && (r = Atomics.add(this.firstBlock.data, u, 1));
|
|
86
103
|
let i = this.getFullDataBlock(r), a = t * (r % this.cachedMaxChunkSize);
|
|
87
|
-
|
|
104
|
+
if (n) i[a] = e;
|
|
105
|
+
else for (let t = 0; t < e.length; t++) i[a + t] = e[t];
|
|
106
|
+
return r;
|
|
107
|
+
}
|
|
108
|
+
reserveContiguous(e) {
|
|
109
|
+
if (!Number.isInteger(e) || e < 0) throw Error(`Can't reserve ${e} pool entries`);
|
|
110
|
+
return Atomics.add(this.firstBlock.data, u, e);
|
|
88
111
|
}
|
|
89
112
|
deleteIndex(e) {
|
|
90
113
|
this.recycleStack.push(e);
|
|
91
114
|
}
|
|
92
115
|
clear() {
|
|
93
|
-
this.firstBlock.data[
|
|
116
|
+
this.firstBlock.data[u] = 0, this.recycleStack.clear();
|
|
94
117
|
}
|
|
95
118
|
*[Symbol.iterator]() {
|
|
96
119
|
let e = {};
|
|
97
120
|
for (let t of this.recycleStack) e[t] = !0;
|
|
98
|
-
let t = this.cachedMaxChunkSize, n = Atomics.load(this.firstBlock.data,
|
|
121
|
+
let t = this.cachedMaxChunkSize, n = Atomics.load(this.firstBlock.data, u), r = this.getFullDataBlock(0), i = 0;
|
|
99
122
|
for (let a = 0; a < n; a++) if (!e[a]) {
|
|
100
123
|
let e = Math.floor(a / t);
|
|
101
124
|
e !== i && (r = this.getFullDataBlock(a), i = e), yield this.getDataBlock(r, a % t);
|
|
102
125
|
}
|
|
103
126
|
}
|
|
127
|
+
*entries() {
|
|
128
|
+
let e = {};
|
|
129
|
+
for (let t of this.recycleStack) e[t] = !0;
|
|
130
|
+
let t = this.cachedMaxChunkSize, n = Atomics.load(this.firstBlock.data, u), r = this.getFullDataBlock(0), i = 0;
|
|
131
|
+
for (let a = 0; a < n; a++) if (!e[a]) {
|
|
132
|
+
let e = Math.floor(a / t);
|
|
133
|
+
e !== i && (r = this.getFullDataBlock(a), i = e), yield [a, this.getDataBlock(r, a % t)];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
104
136
|
getFullDataBlock(t) {
|
|
105
|
-
let n = Math.floor(t / this.cachedMaxChunkSize),
|
|
106
|
-
if (
|
|
137
|
+
let n = Math.floor(t / this.cachedMaxChunkSize), i = this.cachedFullDataBlock[n];
|
|
138
|
+
if (i) return i;
|
|
107
139
|
if (n >= this.pointerStack.length) {
|
|
108
|
-
|
|
140
|
+
s(this.growLock);
|
|
109
141
|
try {
|
|
110
142
|
for (; n >= this.pointerStack.length;) {
|
|
111
143
|
let e = this.memory.allocUI32(this.cachedMaxChunkSize * this.cachedDataLength * this.cachedByteMultipler);
|
|
112
144
|
this.pointerStack.push(e.pointer);
|
|
113
145
|
}
|
|
114
146
|
} finally {
|
|
115
|
-
|
|
147
|
+
c(this.growLock);
|
|
116
148
|
}
|
|
117
149
|
}
|
|
118
|
-
let
|
|
119
|
-
|
|
120
|
-
case 1:
|
|
121
|
-
l = new Int32Array(s.data.buffer, s.bufferByteOffset, c);
|
|
122
|
-
break;
|
|
123
|
-
case 0:
|
|
124
|
-
l = new Uint32Array(s.data.buffer, s.bufferByteOffset, c);
|
|
125
|
-
break;
|
|
126
|
-
case 2:
|
|
127
|
-
l = new Float32Array(s.data.buffer, s.bufferByteOffset, c);
|
|
128
|
-
break;
|
|
129
|
-
case 3:
|
|
130
|
-
l = new Float64Array(s.data.buffer, s.bufferByteOffset, c);
|
|
131
|
-
break;
|
|
132
|
-
default: throw Error(`Unknown data block type ${this.cachedType}`);
|
|
133
|
-
}
|
|
134
|
-
return this.cachedFullDataBlock[n] = l, l;
|
|
150
|
+
let a = new r(this.memory, e(this.pointerStack.at(n), this.memory.positionBits)), l = this.cachedDataLength * this.cachedMaxChunkSize, u = o(this.cachedType, a.data.buffer, a.bufferByteOffset, l);
|
|
151
|
+
return this.cachedFullDataBlock[n] = u, u;
|
|
135
152
|
}
|
|
136
153
|
getDataBlock(e, t) {
|
|
137
154
|
let n = this.cachedDataLength, r = t * n;
|
|
@@ -139,14 +156,14 @@ var s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = cla
|
|
|
139
156
|
}
|
|
140
157
|
free() {
|
|
141
158
|
this.recycleStack.free();
|
|
142
|
-
for (let t of this.pointerStack) new r(this.memory, e(t)).free();
|
|
143
|
-
this.pointerStack.free(), this.firstBlock.free();
|
|
159
|
+
for (let t of this.pointerStack) new r(this.memory, e(t, this.memory.positionBits)).free();
|
|
160
|
+
this.pointerStack.free(), this.ownsFirstBlock && this.firstBlock.free();
|
|
144
161
|
}
|
|
145
162
|
getSharedMemory() {
|
|
146
163
|
return { firstBlock: this.firstBlock.getSharedMemory() };
|
|
147
164
|
}
|
|
148
165
|
};
|
|
149
166
|
//#endregion
|
|
150
|
-
export {
|
|
167
|
+
export { y as default };
|
|
151
168
|
|
|
152
169
|
//# sourceMappingURL=shared-pool.js.map
|
package/dist/shared-pool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-pool.js","names":[],"sources":["../src/shared-pool.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport type { TypedArrayConstructor } from './interfaces/typed-array-constructor';\nimport { lock, unlock } from './lock/simple-lock';\nimport type MemoryHeap from './memory-heap';\nimport SharedStack from './shared-stack';\nimport { getPointer, loadRawPointer, storeRawPointer } from './utils/pointer';\n\nenum TYPE {\n\tuint32,\n\tint32,\n\tfloat32,\n\tfloat64,\n}\n\nconst LENGTH_INDEX = 0;\nconst TYPE_INDEX = 1;\nconst MAX_CHUNK_SIZE_INDEX = 2;\n// Guards appending a chunk pointer so only one thread grows the pointer stack at a time\nconst GROW_LOCK_INDEX = 3;\n// Pointers to the two backing SharedStacks (their own firstBlocks): the chunk pointers and the recycled indexes\nconst POINTER_STACK_INDEX = 4;\nconst RECYCLE_STACK_INDEX = 5;\n\nconst DEFAULT_MAX_CHUNK_SIZE = 100;\nconst DEFAULT_MAX_LENGTH = 1_000_000;\nconst DEFAULT_MAX_RECYCLED_LENGTH = 100_000;\n\n// Array with stable indexes and maximum contiguous memory sizes (necessary to fit large data sets into max 1MB buffers).\n// The chunk pointers and the recycled indexes both live in SharedStacks, whose segments are never moved or freed once\n// published, so concurrent readers never touch memory that is being reclaimed.\n// https://plflib.org/colony.htm for future enhancements - it seems to be an optimized version of what we were aiming for with this\nexport default class SharedPool<T extends Uint32Array | Int32Array | Float32Array | Float64Array = Uint32Array> implements Iterable<T> {\n\tstatic readonly ALLOCATE_COUNT = 6;\n\tprivate memory: MemoryHeap;\n\n\t// Current Length, Type/DataLength, MaxChunkLength, Grow lock, Pointer stack, Recycle stack\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\tprivate growLock: Int32Array;\n\tprivate pointerStack: SharedStack;\n\tprivate recycleStack: SharedStack;\n\treadonly maxLength: number;\n\n\tprivate cachedFullDataBlock: { [key: number]: T } = {};\n\n\t// Config is written once at construction and never mutated, so it is cached in plain fields\n\tprivate readonly cachedMaxChunkSize: number;\n\tprivate readonly cachedDataLength: number;\n\tprivate readonly cachedType: number;\n\tprivate readonly cachedByteMultipler: number;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX) - this.recycleStack.length;\n\t}\n\tget maxChunkSize(): number {\n\t\treturn this.cachedMaxChunkSize;\n\t}\n\tprivate set maxChunkSize(value: number) {\n\t\tAtomics.store(this.firstBlock.data, MAX_CHUNK_SIZE_INDEX, value);\n\t}\n\n\tget type(): number {\n\t\treturn this.cachedType;\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget dataLength(): number {\n\t\treturn this.cachedDataLength;\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tget bufferLength(): number {\n\t\treturn this.cachedMaxChunkSize * this.pointerStack.length;\n\t}\n\tget byteMultipler(): number {\n\t\treturn this.cachedByteMultipler;\n\t}\n\n\t// Own internal memory (which already includes both stacks' inlined firstBlocks) plus every chunk buffer and the\n\t// segments each stack has grown. The stacks' usedMemory excludes their inlined firstBlocks, so they aren't double-counted.\n\tget usedMemory(): number {\n\t\tlet total = this.firstBlock.usedMemory;\n\t\tfor(let pointer of this.pointerStack) {\n\t\t\ttotal += new AllocatedMemory(this.memory, getPointer(pointer)).usedMemory;\n\t\t}\n\t\treturn total + this.pointerStack.usedMemory + this.recycleStack.usedMemory;\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedPoolConfig<T> | SharedPoolMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\tthis.firstBlock = new AllocatedMemory(memory, config.firstBlock);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\t\t\tthis.pointerStack = new SharedStack(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, POINTER_STACK_INDEX)),\n\t\t\t});\n\t\t\tthis.recycleStack = new SharedStack(memory, {\n\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, RECYCLE_STACK_INDEX)),\n\t\t\t});\n\t\t} else {\n\t\t\tlet dataLength = config?.dataLength ?? 1;\n\t\t\tlet maxChunkSize = config?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\t\t\tlet maxLength = config?.maxLength ?? DEFAULT_MAX_LENGTH;\n\t\t\tlet maxRecycledLength = config?.maxRecycledLength ?? DEFAULT_MAX_RECYCLED_LENGTH;\n\n\t\t\t// Each stack sizes its inlined firstBlock from its own maxLength, so compute both up front to lay them out. The\n\t\t\t// stacks cap their segments at what a buffer can hold, so size the inlined blocks against that same cap.\n\t\t\tlet maxSegmentLength = SharedStack.getMaxSegmentLength(memory.maxAllocationLength);\n\t\t\tlet pointerStackMaxLength = maxLength / maxChunkSize;\n\t\t\tlet pointerStackAllocateCount = SharedStack.getAllocateCount(pointerStackMaxLength, undefined, maxSegmentLength);\n\t\t\tlet recycleStackAllocateCount = SharedStack.getAllocateCount(maxRecycledLength, undefined, maxSegmentLength);\n\n\t\t\t// Inline both stacks' firstBlocks right after the pool header so the whole spine is one contiguous allocation\n\t\t\tthis.firstBlock = memory.allocUI32(SharedPool.ALLOCATE_COUNT + pointerStackAllocateCount + recycleStackAllocateCount);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\tthis.pointerStack = new SharedStack(memory, {\n\t\t\t\tfirstBlock: this.firstBlock.getSubAllocation(SharedPool.ALLOCATE_COUNT, pointerStackAllocateCount),\n\t\t\t\ttype: Uint32Array,\n\t\t\t\tmaxLength: pointerStackMaxLength,\n\t\t\t});\n\t\t\tstoreRawPointer(this.firstBlock.data, POINTER_STACK_INDEX, this.pointerStack.pointer);\n\t\t\tthis.recycleStack = new SharedStack(memory, {\n\t\t\t\tfirstBlock: this.firstBlock.getSubAllocation(SharedPool.ALLOCATE_COUNT + pointerStackAllocateCount, recycleStackAllocateCount),\n\t\t\t\ttype: Uint32Array,\n\t\t\t\tmaxLength: maxRecycledLength,\n\t\t\t});\n\t\t\tstoreRawPointer(this.firstBlock.data, RECYCLE_STACK_INDEX, this.recycleStack.pointer);\n\n\t\t\tconst type = config?.type ?? Uint32Array;\n\t\t\tif(type === Uint32Array) {\n\t\t\t\tthis.type = TYPE.uint32;\n\t\t\t// @ts-expect-error\n\t\t\t} else if(type === Int32Array) {\n\t\t\t\tthis.type = TYPE.int32;\n\t\t\t// @ts-expect-error\n\t\t\t} else if(type === Float32Array) {\n\t\t\t\tthis.type = TYPE.float32;\n\t\t\t// @ts-expect-error\n\t\t\t} else if(type === Float64Array) {\n\t\t\t\tthis.type = TYPE.float64;\n\t\t\t}\n\t\t\tthis.dataLength = dataLength;\n\t\t\tthis.maxChunkSize = maxChunkSize;\n\n\t\t\t// @ts-expect-error\n\t\t\tlet byteMultipler = type === Float64Array ? 2 : 1;\n\t\t\tlet firstArray = memory.allocUI32(maxChunkSize * dataLength * byteMultipler);\n\t\t\tthis.pointerStack.push(firstArray.pointer);\n\t\t}\n\n\t\tthis.cachedType = this.uint16Array[0];\n\t\tthis.cachedDataLength = Math.max(1, this.uint16Array[1]);\n\t\tthis.cachedMaxChunkSize = this.firstBlock.data[MAX_CHUNK_SIZE_INDEX];\n\t\tthis.cachedByteMultipler = this.cachedType === TYPE.float64 ? 2 : 1;\n\t\tthis.maxLength = this.cachedMaxChunkSize * this.pointerStack.maxLength;\n\n\t\tthis.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + GROW_LOCK_INDEX * Uint32Array.BYTES_PER_ELEMENT, 1);\n\t}\n\n\tat(index: number): T {\n\t\tlet dataBlock = this.getFullDataBlock(index);\n\t\treturn this.getDataBlock(dataBlock, index % this.cachedMaxChunkSize);\n\t}\n\tget(index: number, dataIndex = 0): number {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tif(dataIndex >= dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${dataLength}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(index);\n\t\treturn dataBlock[(index % this.cachedMaxChunkSize) * dataLength + dataIndex];\n\t}\n\n\tpush(values: number | Array<number>): number {\n\t\tlet dataLength = this.cachedDataLength;\n\t\tconst isSingleNumber = typeof values === 'number';\n\t\tif(!isSingleNumber && values.length > dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${dataLength} dataLength`);\n\t\t}\n\n\t\t// Reuse a recycled index if one is available. pop() can come back undefined when another thread drained the last\n\t\t// slot between our two calls, so fall through to a fresh index rather than trusting a length() read\n\t\tlet newIndex = this.recycleStack.pop();\n\t\tif(newIndex === undefined) {\n\t\t\tnewIndex = Atomics.add(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(newIndex);\n\t\tlet startIndex = dataLength * (newIndex % this.cachedMaxChunkSize);\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.recycleStack.push(index);\n\t}\n\n\tclear() {\n\t\tthis.firstBlock.data[LENGTH_INDEX] = 0;\n\t\tthis.recycleStack.clear();\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycleStack) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tconst maxChunkSize = this.cachedMaxChunkSize;\n\t\t// Snapshot the length once - iteration over a concurrently mutated pool is a snapshot anyway, and re-loading the\n\t\t// atomic every step is pure overhead\n\t\tconst length = Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < length; i++) {\n\t\t\tif(!recycledValues[i]) {\n\t\t\t\tlet newDataBlockIndex = Math.floor(i / 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 % maxChunkSize);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getFullDataBlock(index: number) {\n\t\tlet pointerIndex = Math.floor(index / this.cachedMaxChunkSize);\n\t\tlet cachedDataBlock = this.cachedFullDataBlock[pointerIndex];\n\t\tif(cachedDataBlock) {\n\t\t\treturn cachedDataBlock;\n\t\t}\n\t\tif(pointerIndex >= this.pointerStack.length) {\n\t\t\t// Only let a single thread append a new chunk at a time - otherwise two concurrent inserts landing in a new\n\t\t\t// chunk would each allocate + push a buffer, orphaning one and leaking memory\n\t\t\tlock(this.growLock);\n\t\t\ttry {\n\t\t\t\t// Re-check under the lock: another thread may have already appended the chunk while we were waiting\n\t\t\t\twhile(pointerIndex >= this.pointerStack.length) {\n\t\t\t\t\tlet newArray = this.memory.allocUI32(this.cachedMaxChunkSize * this.cachedDataLength * this.cachedByteMultipler);\n\t\t\t\t\tthis.pointerStack.push(newArray.pointer);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tunlock(this.growLock);\n\t\t\t}\n\t\t}\n\n\t\tlet array = new AllocatedMemory(this.memory, getPointer(this.pointerStack.at(pointerIndex)));\n\n\t\tlet blockLength = this.cachedDataLength * this.cachedMaxChunkSize;\n\t\tlet data: T;\n\t\tswitch(this.cachedType) {\n\t\t\tcase TYPE.int32:\n\t\t\t\tdata = new Int32Array(array.data.buffer, array.bufferByteOffset, blockLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.uint32:\n\t\t\t\tdata = new Uint32Array(array.data.buffer, array.bufferByteOffset, blockLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.float32:\n\t\t\t\tdata = new Float32Array(array.data.buffer, array.bufferByteOffset, blockLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.float64:\n\t\t\t\tdata = new Float64Array(array.data.buffer, array.bufferByteOffset, blockLength) as T;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown data block type ${this.cachedType}`);\n\t\t}\n\n\t\tthis.cachedFullDataBlock[pointerIndex] = data;\n\t\treturn data;\n\t}\n\n\tprivate getDataBlock(rawData: T, index: number): T {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tconst start = index * dataLength;\n\t\treturn rawData.subarray(start, start + dataLength) as T;\n\t}\n\n\tfree() {\n\t\tthis.recycleStack.free();\n\n\t\tfor(let pointer of this.pointerStack) {\n\t\t\tlet memory = new AllocatedMemory(this.memory, getPointer(pointer));\n\t\t\tmemory.free();\n\t\t}\n\t\tthis.pointerStack.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedPoolMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedPoolConfig<T extends Uint32Array | Int32Array | Float32Array | Float64Array> {\n\tmaxChunkSize?: number\n\tmaxLength?: number\n\tmaxRecycledLength?: number\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n}\ninterface SharedPoolMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedPoolConfig, SharedPoolMemory };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-pool.js","names":[],"sources":["../src/shared-pool.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport { lock, unlock } from './lock/simple-lock';\nimport type MemoryHeap from './memory-heap';\nimport SharedStack from './shared-stack';\nimport { getPointer, loadRawPointer, storeRawPointer } from './utils/pointer';\nimport { getArrayTypeCode, getByteMultipler, makeArrayView, type NumericArray, type NumericArrayIO, type TypedArrayConstructor } from './utils/array-type';\n\nconst LENGTH_INDEX = 0;\nconst TYPE_INDEX = 1;\nconst MAX_CHUNK_SIZE_INDEX = 2;\n// Guards appending a chunk pointer so only one thread grows the pointer stack at a time\nconst GROW_LOCK_INDEX = 3;\n// Pointers to the two backing SharedStacks (their own firstBlocks): the chunk pointers and the recycled indexes\nconst POINTER_STACK_INDEX = 4;\nconst RECYCLE_STACK_INDEX = 5;\n\nconst DEFAULT_MAX_CHUNK_SIZE = 100;\nconst DEFAULT_MAX_LENGTH = 1_000_000;\nconst DEFAULT_MAX_RECYCLED_LENGTH = 100_000;\n\n// Array with stable indexes and maximum contiguous memory sizes (necessary to fit large data sets into max 1MB buffers).\n// The chunk pointers and the recycled indexes both live in SharedStacks, whose segments are never moved or freed once\n// published, so concurrent readers never touch memory that is being reclaimed.\n// https://plflib.org/colony.htm for future enhancements - it seems to be an optimized version of what we were aiming for with this\nexport default class SharedPool<T extends NumericArray = Uint32Array> implements Iterable<T> {\n\tstatic readonly ALLOCATE_COUNT = 6;\n\n\t// u32s a pool with this config needs for its firstBlock, including both inlined stacks. Lets an owner (e.g.\n\t// SharedQuadtree) reserve one contiguous slice and hand it back through the config's firstBlock to inline the pool.\n\tstatic getAllocateCount(memory: MemoryHeap, config?: SharedPoolConfig<NumericArray>): number {\n\t\tlet maxChunkSize = config?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\t\tlet maxLength = config?.maxLength ?? DEFAULT_MAX_LENGTH;\n\t\tlet maxRecycledLength = config?.maxRecycledLength ?? DEFAULT_MAX_RECYCLED_LENGTH;\n\t\tlet maxSegmentLength = SharedStack.getMaxSegmentLength(memory.maxAllocationLength);\n\t\tlet pointerStackAllocateCount = SharedStack.getAllocateCount(maxLength / maxChunkSize, undefined, maxSegmentLength);\n\t\tlet recycleStackAllocateCount = SharedStack.getAllocateCount(maxRecycledLength, undefined, maxSegmentLength);\n\t\treturn SharedPool.ALLOCATE_COUNT + pointerStackAllocateCount + recycleStackAllocateCount;\n\t}\n\n\tprivate memory: MemoryHeap;\n\n\t// Current Length, Type/DataLength, MaxChunkLength, Grow lock, Pointer stack, Recycle stack\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\tprivate growLock: Int32Array;\n\tprivate pointerStack!: SharedStack;\n\tprivate recycleStack!: SharedStack;\n\treadonly maxLength: number;\n\n\t// False when firstBlock is a slice of another structure's memory (e.g. inlined in SharedQuadtree); that owner frees it\n\tprivate ownsFirstBlock: boolean;\n\n\t// Chunk views cached by pointer index. An array (dense, small integer keys) resolves faster than an object on the hot\n\t// get/set path and never needs rehashing.\n\tprivate cachedFullDataBlock: Array<T | undefined> = [];\n\n\t// Config is written once at construction and never mutated, so it is cached in plain fields\n\tprivate readonly cachedMaxChunkSize: number;\n\tprivate readonly cachedDataLength: number;\n\tprivate readonly cachedType: number;\n\tprivate readonly cachedByteMultipler: number;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX) - this.recycleStack.length;\n\t}\n\tget maxChunkSize(): number {\n\t\treturn this.cachedMaxChunkSize;\n\t}\n\tprivate set maxChunkSize(value: number) {\n\t\tAtomics.store(this.firstBlock.data, MAX_CHUNK_SIZE_INDEX, value);\n\t}\n\n\tget type(): number {\n\t\treturn this.cachedType;\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget dataLength(): number {\n\t\treturn this.cachedDataLength;\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tget bufferLength(): number {\n\t\treturn this.cachedMaxChunkSize * this.pointerStack.length;\n\t}\n\tget byteMultipler(): number {\n\t\treturn this.cachedByteMultipler;\n\t}\n\n\t// Own internal memory (which already includes both stacks' inlined firstBlocks) plus every chunk buffer and the\n\t// segments each stack has grown. The stacks' usedMemory excludes their inlined firstBlocks, so they aren't double-counted.\n\tget usedMemory(): number {\n\t\tlet total = this.ownsFirstBlock ? this.firstBlock.usedMemory : 0;\n\t\tfor(let pointer of this.pointerStack) {\n\t\t\ttotal += new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits)).usedMemory;\n\t\t}\n\t\treturn total + this.pointerStack.usedMemory + this.recycleStack.usedMemory;\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedPoolConfig<T> | SharedPoolMemory | SharedPoolMemory & SharedPoolConfig<T>) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\t// An AllocatedMemory instance is a caller-reserved slice (e.g. inlined in SharedQuadtree); a plain pointer is the\n\t\t\t// serialized clone path. Taking the instance directly keeps us off the pointer-resolving construction branch.\n\t\t\tthis.firstBlock = config.firstBlock instanceof AllocatedMemory ? config.firstBlock : new AllocatedMemory(memory, config.firstBlock);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\t// Memory passed together with config means the caller reserved the firstBlock slot for us to initialize in place\n\t\t\tif('type' in config || 'dataLength' in config || 'maxLength' in config || 'maxChunkSize' in config || 'maxRecycledLength' in config) {\n\t\t\t\tthis.initialize(config);\n\t\t\t\tthis.ownsFirstBlock = false;\n\t\t\t} else {\n\t\t\t\tthis.pointerStack = new SharedStack(memory, {\n\t\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, POINTER_STACK_INDEX), memory.positionBits),\n\t\t\t\t});\n\t\t\t\tthis.recycleStack = new SharedStack(memory, {\n\t\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, RECYCLE_STACK_INDEX), memory.positionBits),\n\t\t\t\t});\n\t\t\t\tthis.ownsFirstBlock = true;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.firstBlock = memory.allocUI32(SharedPool.getAllocateCount(memory, config));\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\t\t\tthis.initialize(config);\n\t\t\tthis.ownsFirstBlock = true;\n\t\t}\n\n\t\tthis.cachedType = this.uint16Array[0];\n\t\tthis.cachedDataLength = Math.max(1, this.uint16Array[1]);\n\t\tthis.cachedMaxChunkSize = this.firstBlock.data[MAX_CHUNK_SIZE_INDEX];\n\t\tthis.cachedByteMultipler = getByteMultipler(this.cachedType);\n\t\tthis.maxLength = this.cachedMaxChunkSize * this.pointerStack.maxLength;\n\n\t\tthis.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + GROW_LOCK_INDEX * Uint32Array.BYTES_PER_ELEMENT, 1);\n\t}\n\n\t// Lay out the two inlined stacks (their firstBlocks sliced from ours), record their pointers, and seed the first chunk.\n\t// firstBlock and uint16Array must already be set. Used by both the fresh-alloc path and the inline-in-place path.\n\tprivate initialize(config?: SharedPoolConfig<T>) {\n\t\tlet dataLength = config?.dataLength ?? 1;\n\t\tlet maxChunkSize = config?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\t\tlet maxLength = config?.maxLength ?? DEFAULT_MAX_LENGTH;\n\t\tlet maxRecycledLength = config?.maxRecycledLength ?? DEFAULT_MAX_RECYCLED_LENGTH;\n\n\t\t// Each stack sizes its inlined firstBlock from its own maxLength, so compute both up front to lay them out. The\n\t\t// stacks cap their segments at what a buffer can hold, so size the inlined blocks against that same cap.\n\t\tlet maxSegmentLength = SharedStack.getMaxSegmentLength(this.memory.maxAllocationLength);\n\t\tlet pointerStackMaxLength = maxLength / maxChunkSize;\n\t\tlet pointerStackAllocateCount = SharedStack.getAllocateCount(pointerStackMaxLength, undefined, maxSegmentLength);\n\t\tlet recycleStackAllocateCount = SharedStack.getAllocateCount(maxRecycledLength, undefined, maxSegmentLength);\n\n\t\t// Inline both stacks' firstBlocks right after the pool header so the whole spine is one contiguous allocation\n\t\tthis.pointerStack = new SharedStack(this.memory, {\n\t\t\tfirstBlock: this.firstBlock.getSubAllocation(SharedPool.ALLOCATE_COUNT, pointerStackAllocateCount),\n\t\t\ttype: Uint32Array,\n\t\t\tmaxLength: pointerStackMaxLength,\n\t\t});\n\t\tstoreRawPointer(this.firstBlock.data, POINTER_STACK_INDEX, this.pointerStack.pointer);\n\t\tthis.recycleStack = new SharedStack(this.memory, {\n\t\t\tfirstBlock: this.firstBlock.getSubAllocation(SharedPool.ALLOCATE_COUNT + pointerStackAllocateCount, recycleStackAllocateCount),\n\t\t\ttype: Uint32Array,\n\t\t\tmaxLength: maxRecycledLength,\n\t\t});\n\t\tstoreRawPointer(this.firstBlock.data, RECYCLE_STACK_INDEX, this.recycleStack.pointer);\n\n\t\tlet typeCode = getArrayTypeCode(config?.type ?? Uint32Array);\n\t\tthis.type = typeCode;\n\t\tthis.dataLength = dataLength;\n\t\tthis.maxChunkSize = maxChunkSize;\n\n\t\tlet byteMultipler = getByteMultipler(typeCode);\n\t\tlet firstArray = this.memory.allocUI32(maxChunkSize * dataLength * byteMultipler);\n\t\tthis.pointerStack.push(firstArray.pointer);\n\t}\n\n\tat(index: number): T {\n\t\tlet dataBlock = this.getFullDataBlock(index);\n\t\treturn this.getDataBlock(dataBlock, index % this.cachedMaxChunkSize);\n\t}\n\tget(index: number, dataIndex = 0): T[number] {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tif(dataIndex >= dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${dataLength}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(index) as NumericArrayIO;\n\t\treturn dataBlock[(index % this.cachedMaxChunkSize) * dataLength + dataIndex];\n\t}\n\tset(index: number, dataIndex: number, value: T[number]) {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tif(dataIndex >= dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${dataLength}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(index) as NumericArrayIO;\n\t\tdataBlock[(index % this.cachedMaxChunkSize) * dataLength + dataIndex] = value;\n\t}\n\n\t// Resolve the chunk view holding an index once. Callers touching several fields of the same record read/write straight\n\t// into this view at blockOffset(index) + fieldIndex, avoiding a repeated chunk lookup per field.\n\tblockFor(index: number): T {\n\t\treturn this.getFullDataBlock(index);\n\t}\n\t// Base slot of a record within the view blockFor(index) returns.\n\tblockOffset(index: number): number {\n\t\treturn (index % this.cachedMaxChunkSize) * this.cachedDataLength;\n\t}\n\n\tpush(values: T[number] | Array<T[number]>): number {\n\t\tlet dataLength = this.cachedDataLength;\n\t\tconst isSingleValue = typeof values !== 'object';\n\t\tif(!isSingleValue && values.length > dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${dataLength} dataLength`);\n\t\t}\n\n\t\t// Reuse a recycled index if one is available. pop() can come back undefined when another thread drained the last\n\t\t// slot between our two calls, so fall through to a fresh index rather than trusting a length() read\n\t\tlet newIndex = this.recycleStack.length === 0 ? undefined : this.recycleStack.pop();\n\t\tif(newIndex === undefined) {\n\t\t\tnewIndex = Atomics.add(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(newIndex) as NumericArrayIO;\n\t\tlet startIndex = dataLength * (newIndex % this.cachedMaxChunkSize);\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\treserveContiguous(count: number): number {\n\t\tif(!Number.isInteger(count) || count < 0) {\n\t\t\tthrow new Error(`Can't reserve ${count} pool entries`);\n\t\t}\n\t\treturn Atomics.add(this.firstBlock.data, LENGTH_INDEX, count);\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tthis.recycleStack.push(index);\n\t}\n\n\tclear() {\n\t\tthis.firstBlock.data[LENGTH_INDEX] = 0;\n\t\tthis.recycleStack.clear();\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycleStack) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tconst maxChunkSize = this.cachedMaxChunkSize;\n\t\t// Snapshot the length once - iteration over a concurrently mutated pool is a snapshot anyway, and re-loading the\n\t\t// atomic every step is pure overhead\n\t\tconst length = Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < length; i++) {\n\t\t\tif(!recycledValues[i]) {\n\t\t\t\tlet newDataBlockIndex = Math.floor(i / 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 % maxChunkSize);\n\t\t\t}\n\t\t}\n\t}\n\n\t*entries(): IterableIterator<[number, T]> {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycleStack) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tconst maxChunkSize = this.cachedMaxChunkSize;\n\t\tconst length = Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < length; i++) {\n\t\t\tif(!recycledValues[i]) {\n\t\t\t\tlet newDataBlockIndex = Math.floor(i / 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 [i, this.getDataBlock(dataBlock, i % maxChunkSize)];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getFullDataBlock(index: number) {\n\t\tlet pointerIndex = Math.floor(index / this.cachedMaxChunkSize);\n\t\tlet cachedDataBlock = this.cachedFullDataBlock[pointerIndex];\n\t\tif(cachedDataBlock) {\n\t\t\treturn cachedDataBlock;\n\t\t}\n\t\tif(pointerIndex >= this.pointerStack.length) {\n\t\t\t// Only let a single thread append a new chunk at a time - otherwise two concurrent inserts landing in a new\n\t\t\t// chunk would each allocate + push a buffer, orphaning one and leaking memory\n\t\t\tlock(this.growLock);\n\t\t\ttry {\n\t\t\t\t// Re-check under the lock: another thread may have already appended the chunk while we were waiting\n\t\t\t\twhile(pointerIndex >= this.pointerStack.length) {\n\t\t\t\t\tlet newArray = this.memory.allocUI32(this.cachedMaxChunkSize * this.cachedDataLength * this.cachedByteMultipler);\n\t\t\t\t\tthis.pointerStack.push(newArray.pointer);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tunlock(this.growLock);\n\t\t\t}\n\t\t}\n\n\t\tlet array = new AllocatedMemory(this.memory, getPointer(this.pointerStack.at(pointerIndex), this.memory.positionBits));\n\n\t\tlet blockLength = this.cachedDataLength * this.cachedMaxChunkSize;\n\t\tlet data = makeArrayView(this.cachedType, array.data.buffer, array.bufferByteOffset, blockLength) as T;\n\n\t\tthis.cachedFullDataBlock[pointerIndex] = data;\n\t\treturn data;\n\t}\n\n\tprivate getDataBlock(rawData: T, index: number): T {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tconst start = index * dataLength;\n\t\treturn rawData.subarray(start, start + dataLength) as T;\n\t}\n\n\tfree() {\n\t\tthis.recycleStack.free();\n\n\t\tfor(let pointer of this.pointerStack) {\n\t\t\tlet memory = new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits));\n\t\t\tmemory.free();\n\t\t}\n\t\tthis.pointerStack.free();\n\t\tif(this.ownsFirstBlock) {\n\t\t\tthis.firstBlock.free();\n\t\t}\n\t}\n\n\tgetSharedMemory(): SharedPoolMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedPoolConfig<T extends NumericArray> {\n\tmaxChunkSize?: number\n\tmaxLength?: number\n\tmaxRecycledLength?: number\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n}\ninterface SharedPoolMemory {\n\tfirstBlock: SharedAllocatedMemory | AllocatedMemory\n}\n\nexport type { SharedPoolConfig, SharedPoolMemory };\n"],"mappings":"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"}
|
package/dist/shared-stack.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { SharedAllocatedMemory } from './allocated-memory';
|
|
2
2
|
import AllocatedMemory from './allocated-memory';
|
|
3
|
-
import type { TypedArrayConstructor } from './interfaces/typed-array-constructor';
|
|
4
3
|
import type MemoryHeap from './memory-heap';
|
|
5
|
-
|
|
4
|
+
import { type NumericArray, type TypedArrayConstructor } from './utils/array-type';
|
|
5
|
+
export default class SharedStack<T extends NumericArray = Uint32Array> implements Iterable<T[number]> {
|
|
6
6
|
static readonly BASE_ALLOCATE_COUNT = 8;
|
|
7
7
|
static readonly DEFAULT_ALLOCATE_COUNT: number;
|
|
8
|
-
static getMaxSegmentLength(maxAllocationLength: number, baseSegmentLength?: number): number;
|
|
8
|
+
static getMaxSegmentLength(maxAllocationLength: number, baseSegmentLength?: number, byteMultipler?: number): number;
|
|
9
9
|
static getMaxSegments(maxLength: number, baseSegmentLength?: number, maxSegmentLength?: number): number;
|
|
10
10
|
static getCapacity(segments: number, baseSegmentLength?: number, maxSegmentLength?: number): number;
|
|
11
11
|
static getAllocateCount(maxLength: number, baseSegmentLength?: number, maxSegmentLength?: number): number;
|
|
@@ -21,6 +21,7 @@ export default class SharedStack<T extends Uint32Array | Int32Array | Float32Arr
|
|
|
21
21
|
private cachedMaxSegmentLength;
|
|
22
22
|
private cachedCapSegmentCount;
|
|
23
23
|
private cachedGeometricCapacity;
|
|
24
|
+
private cachedByteMultipler;
|
|
24
25
|
get length(): number;
|
|
25
26
|
get segmentCount(): number;
|
|
26
27
|
private set segmentCount(value);
|
|
@@ -38,16 +39,16 @@ export default class SharedStack<T extends Uint32Array | Int32Array | Float32Arr
|
|
|
38
39
|
private resolveMaxSegmentLength;
|
|
39
40
|
private resolveMaxSegments;
|
|
40
41
|
private initialize;
|
|
41
|
-
at(index: number): number;
|
|
42
|
-
push(value: number): number;
|
|
43
|
-
pop(): number | undefined;
|
|
42
|
+
at(index: number): T[number];
|
|
43
|
+
push(value: T[number]): number;
|
|
44
|
+
pop(): T[number] | undefined;
|
|
44
45
|
clear(): void;
|
|
45
|
-
[Symbol.iterator](): Generator<number, void, unknown>;
|
|
46
|
+
[Symbol.iterator](): Generator<T[number], void, unknown>;
|
|
46
47
|
private getSegment;
|
|
47
48
|
free(): void;
|
|
48
49
|
getSharedMemory(): SharedStackMemory;
|
|
49
50
|
}
|
|
50
|
-
interface SharedStackConfig<T extends
|
|
51
|
+
interface SharedStackConfig<T extends NumericArray> {
|
|
51
52
|
type?: TypedArrayConstructor<T>;
|
|
52
53
|
baseSegmentLength?: number;
|
|
53
54
|
maxLength?: number;
|
package/dist/shared-stack.js
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import { getPointer as e, storePointer as t } from "./utils/pointer.js";
|
|
2
2
|
import n from "./allocated-memory.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getArrayTypeCode as r, getByteMultipler as i, makeArrayView as a } from "./utils/array-type.js";
|
|
4
|
+
import { lock as o, unlock as s } from "./lock/simple-lock.js";
|
|
4
5
|
//#region src/shared-stack.ts
|
|
5
|
-
var
|
|
6
|
+
var c = 0, l = 1, u = 2, d = 3, f = 4, p = 5, m = 6, h = 7, g = 4, _ = 20, v = 22, y = (1 << v) - 1, b = 4194302, x = 1 << v, S = class v {
|
|
6
7
|
static BASE_ALLOCATE_COUNT = 8;
|
|
7
|
-
static DEFAULT_ALLOCATE_COUNT = this.BASE_ALLOCATE_COUNT +
|
|
8
|
-
static getMaxSegmentLength(e, t =
|
|
9
|
-
let
|
|
10
|
-
for (;
|
|
11
|
-
return
|
|
8
|
+
static DEFAULT_ALLOCATE_COUNT = this.BASE_ALLOCATE_COUNT + _;
|
|
9
|
+
static getMaxSegmentLength(e, t = g, n = 1) {
|
|
10
|
+
let r = t;
|
|
11
|
+
for (; r * 2 * (n + 1) <= e;) r *= 2;
|
|
12
|
+
return r;
|
|
12
13
|
}
|
|
13
|
-
static getMaxSegments(e, t =
|
|
14
|
+
static getMaxSegments(e, t = g, n = Infinity) {
|
|
14
15
|
let r = 0, i = 0, a = t;
|
|
15
16
|
for (; i < e;) i += a, r++, a = Math.min(a * 2, n);
|
|
16
17
|
return r;
|
|
17
18
|
}
|
|
18
|
-
static getCapacity(e, t =
|
|
19
|
+
static getCapacity(e, t = g, n = Infinity) {
|
|
19
20
|
let r = 0, i = t;
|
|
20
21
|
for (let t = 0; t < e; t++) r += i, i = Math.min(i * 2, n);
|
|
21
22
|
return r;
|
|
22
23
|
}
|
|
23
|
-
static getAllocateCount(e, t =
|
|
24
|
+
static getAllocateCount(e, t = g, n = Infinity) {
|
|
24
25
|
return this.BASE_ALLOCATE_COUNT + this.getMaxSegments(e, t, n);
|
|
25
26
|
}
|
|
26
27
|
memory;
|
|
@@ -35,14 +36,15 @@ var a = 0, o = 1, s = 2, c = 3, l = 4, u = 5, d = 6, f = 7, p = 4, m = 20, h = 2
|
|
|
35
36
|
cachedMaxSegmentLength = 0;
|
|
36
37
|
cachedCapSegmentCount = 0;
|
|
37
38
|
cachedGeometricCapacity = 0;
|
|
39
|
+
cachedByteMultipler = 1;
|
|
38
40
|
get length() {
|
|
39
|
-
return Atomics.load(this.firstBlock.data,
|
|
41
|
+
return Atomics.load(this.firstBlock.data, c) & y;
|
|
40
42
|
}
|
|
41
43
|
get segmentCount() {
|
|
42
|
-
return Atomics.load(this.firstBlock.data,
|
|
44
|
+
return Atomics.load(this.firstBlock.data, p);
|
|
43
45
|
}
|
|
44
46
|
set segmentCount(e) {
|
|
45
|
-
this.firstBlock.data[
|
|
47
|
+
this.firstBlock.data[p] = e;
|
|
46
48
|
}
|
|
47
49
|
get type() {
|
|
48
50
|
return this.uint16Array[0];
|
|
@@ -51,22 +53,22 @@ var a = 0, o = 1, s = 2, c = 3, l = 4, u = 5, d = 6, f = 7, p = 4, m = 20, h = 2
|
|
|
51
53
|
Atomics.store(this.uint16Array, 0, e);
|
|
52
54
|
}
|
|
53
55
|
get baseSegmentLength() {
|
|
54
|
-
return this.firstBlock.data[
|
|
56
|
+
return this.firstBlock.data[u];
|
|
55
57
|
}
|
|
56
58
|
set baseSegmentLength(e) {
|
|
57
|
-
this.firstBlock.data[
|
|
59
|
+
this.firstBlock.data[u] = e;
|
|
58
60
|
}
|
|
59
61
|
get maxSegments() {
|
|
60
|
-
return this.firstBlock.data[
|
|
62
|
+
return this.firstBlock.data[d];
|
|
61
63
|
}
|
|
62
64
|
set maxSegments(e) {
|
|
63
|
-
this.firstBlock.data[
|
|
65
|
+
this.firstBlock.data[d] = e;
|
|
64
66
|
}
|
|
65
67
|
get maxSegmentLength() {
|
|
66
|
-
return this.firstBlock.data[
|
|
68
|
+
return this.firstBlock.data[f];
|
|
67
69
|
}
|
|
68
70
|
set maxSegmentLength(e) {
|
|
69
|
-
this.firstBlock.data[
|
|
71
|
+
this.firstBlock.data[f] = e;
|
|
70
72
|
}
|
|
71
73
|
get pointer() {
|
|
72
74
|
return this.firstBlock.pointer;
|
|
@@ -74,37 +76,35 @@ var a = 0, o = 1, s = 2, c = 3, l = 4, u = 5, d = 6, f = 7, p = 4, m = 20, h = 2
|
|
|
74
76
|
get usedMemory() {
|
|
75
77
|
let t = this.ownsFirstBlock ? this.firstBlock.usedMemory : 0;
|
|
76
78
|
for (let r = 0; r < this.segmentCount; r++) {
|
|
77
|
-
let i = e(Atomics.load(this.firstBlock.data,
|
|
79
|
+
let i = e(Atomics.load(this.firstBlock.data, h + r), this.memory.positionBits);
|
|
78
80
|
t += new n(this.memory, i).usedMemory;
|
|
79
81
|
}
|
|
80
82
|
return t;
|
|
81
83
|
}
|
|
82
84
|
constructor(e, t) {
|
|
83
|
-
if (this.memory = e, t && "firstBlock" in t) this.firstBlock = t.firstBlock instanceof n ? t.firstBlock : new n(e, t.firstBlock), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset +
|
|
85
|
+
if (this.memory = e, t && "firstBlock" in t) this.firstBlock = t.firstBlock instanceof n ? t.firstBlock : new n(e, t.firstBlock), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + l * Uint32Array.BYTES_PER_ELEMENT, 2), "type" in t || "baseSegmentLength" in t || "maxLength" in t ? (this.initialize(t), this.ownsFirstBlock = !1) : this.ownsFirstBlock = !0;
|
|
84
86
|
else {
|
|
85
|
-
let n = t?.baseSegmentLength ??
|
|
86
|
-
this.firstBlock = e.allocUI32(
|
|
87
|
+
let n = i(r(t?.type ?? Uint32Array)), a = t?.baseSegmentLength ?? g, o = this.resolveMaxSegmentLength(a, t?.maxSegmentLength, n), s = this.resolveMaxSegments(t?.maxLength, a, o);
|
|
88
|
+
this.firstBlock = e.allocUI32(v.BASE_ALLOCATE_COUNT + s), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + l * Uint32Array.BYTES_PER_ELEMENT, 2), this.ownsFirstBlock = !0, this.initialize(t);
|
|
87
89
|
}
|
|
88
|
-
if (this.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset +
|
|
90
|
+
if (this.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + m * Uint32Array.BYTES_PER_ELEMENT, 1), this.cachedByteMultipler = i(this.type), this.cachedBaseSegmentLength = this.baseSegmentLength, this.cachedMaxSegmentLength = this.maxSegmentLength, this.cachedCapSegmentCount = 32 - Math.clz32(this.cachedMaxSegmentLength / this.cachedBaseSegmentLength | 0), this.cachedGeometricCapacity = this.cachedBaseSegmentLength * ((1 << this.cachedCapSegmentCount) - 1), this.maxLength = v.getCapacity(this.maxSegments, this.cachedBaseSegmentLength, this.cachedMaxSegmentLength), this.maxLength > b) throw Error(`SharedStack maxLength ${this.maxLength} exceeds the ${b} the versioned length counter can address`);
|
|
89
91
|
}
|
|
90
|
-
resolveMaxSegmentLength(e, t) {
|
|
91
|
-
let
|
|
92
|
+
resolveMaxSegmentLength(e, t, n = 1) {
|
|
93
|
+
let r = v.getMaxSegmentLength(this.memory.maxAllocationLength, e, n);
|
|
92
94
|
if (t) {
|
|
93
|
-
let
|
|
94
|
-
for (;
|
|
95
|
-
|
|
95
|
+
let n = e;
|
|
96
|
+
for (; n * 2 <= t;) n *= 2;
|
|
97
|
+
r = Math.min(r, n);
|
|
96
98
|
}
|
|
97
|
-
return
|
|
99
|
+
return r;
|
|
98
100
|
}
|
|
99
101
|
resolveMaxSegments(e, t, n) {
|
|
100
|
-
let r = e === void 0 ?
|
|
102
|
+
let r = e === void 0 ? _ : v.getMaxSegments(e, t, n), i = this.memory.maxAllocationLength - v.BASE_ALLOCATE_COUNT;
|
|
101
103
|
return Math.min(r, i);
|
|
102
104
|
}
|
|
103
105
|
initialize(e) {
|
|
104
|
-
let n = e?.baseSegmentLength ??
|
|
105
|
-
t(this.firstBlock.data,
|
|
106
|
-
let a = e?.type ?? Uint32Array;
|
|
107
|
-
a === Uint32Array ? this.type = 0 : a === Int32Array ? this.type = 1 : a === Float32Array && (this.type = 2);
|
|
106
|
+
let n = r(e?.type ?? Uint32Array), a = i(n), o = e?.baseSegmentLength ?? g, s = this.resolveMaxSegmentLength(o, e?.maxSegmentLength, a), c = this.memory.allocUI32(o * (a + 1));
|
|
107
|
+
t(this.firstBlock.data, h, c.bufferPosition, c.bufferByteOffset, this.memory.positionBits), this.baseSegmentLength = o, this.maxSegmentLength = s, this.maxSegments = this.resolveMaxSegments(e?.maxLength, o, s), this.segmentCount = 1, this.type = n;
|
|
108
108
|
}
|
|
109
109
|
at(e) {
|
|
110
110
|
let t = this.length;
|
|
@@ -117,46 +117,48 @@ var a = 0, o = 1, s = 2, c = 3, l = 4, u = 5, d = 6, f = 7, p = 4, m = 20, h = 2
|
|
|
117
117
|
let t = this.cachedMaxSegmentLength, a = e - n, o = a / t | 0;
|
|
118
118
|
r = this.cachedCapSegmentCount + o, i = a - o * t;
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
let a = this.cachedSegments[r] ?? this.getSegment(r), o = this.cachedSequences[r];
|
|
121
|
+
for (; !(Atomics.load(o, i) & 1););
|
|
122
|
+
return a[i];
|
|
121
123
|
}
|
|
122
124
|
push(e) {
|
|
123
125
|
let t = this.firstBlock.data, n = this.cachedGeometricCapacity;
|
|
124
126
|
for (;;) {
|
|
125
|
-
let r = t[
|
|
127
|
+
let r = t[c], i = r & y;
|
|
126
128
|
if (i >= this.maxLength) throw Error(`${i + 1} is out of bounds ${this.maxLength}`);
|
|
127
|
-
let
|
|
129
|
+
let a, o;
|
|
128
130
|
if (i < n) {
|
|
129
131
|
let e = this.cachedBaseSegmentLength;
|
|
130
|
-
|
|
132
|
+
a = 31 - Math.clz32((i / e | 0) + 1), o = i - e * ((1 << a) - 1);
|
|
131
133
|
} else {
|
|
132
134
|
let e = this.cachedMaxSegmentLength, t = i - n, r = t / e | 0;
|
|
133
|
-
|
|
135
|
+
a = this.cachedCapSegmentCount + r, o = t - r * e;
|
|
134
136
|
}
|
|
135
|
-
let
|
|
136
|
-
if (!(u & 1) && Atomics.compareExchange(t,
|
|
137
|
+
let s = this.cachedSegments[a] ?? this.getSegment(a), l = this.cachedSequences[a], u = Atomics.load(l, o);
|
|
138
|
+
if (!(u & 1) && Atomics.compareExchange(t, c, r, r + x + 1) === r) return s[o] = e, Atomics.store(l, o, u + 1), i;
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
pop() {
|
|
140
142
|
let e = this.firstBlock.data, t = this.cachedGeometricCapacity;
|
|
141
143
|
for (;;) {
|
|
142
|
-
let n = e[
|
|
144
|
+
let n = e[c], r = n & y;
|
|
143
145
|
if (r <= 0) return;
|
|
144
|
-
let i = r - 1,
|
|
146
|
+
let i = r - 1, a, o;
|
|
145
147
|
if (i < t) {
|
|
146
148
|
let e = this.cachedBaseSegmentLength;
|
|
147
|
-
|
|
149
|
+
a = 31 - Math.clz32((i / e | 0) + 1), o = i - e * ((1 << a) - 1);
|
|
148
150
|
} else {
|
|
149
151
|
let e = this.cachedMaxSegmentLength, n = i - t, r = n / e | 0;
|
|
150
|
-
|
|
152
|
+
a = this.cachedCapSegmentCount + r, o = n - r * e;
|
|
151
153
|
}
|
|
152
|
-
let
|
|
153
|
-
if (!(u & 1) || Atomics.compareExchange(e,
|
|
154
|
-
let d =
|
|
155
|
-
return Atomics.store(l,
|
|
154
|
+
let s = this.cachedSegments[a] ?? this.getSegment(a), l = this.cachedSequences[a], u = Atomics.load(l, o);
|
|
155
|
+
if (!(u & 1) || Atomics.compareExchange(e, c, n, n + x - 1) !== n) continue;
|
|
156
|
+
let d = s[o];
|
|
157
|
+
return Atomics.store(l, o, u + 1), d;
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
clear() {
|
|
159
|
-
let e = this.cachedBaseSegmentLength, t = this.cachedGeometricCapacity, n = this.cachedMaxSegmentLength, r = Atomics.load(this.firstBlock.data,
|
|
161
|
+
let e = this.cachedBaseSegmentLength, t = this.cachedGeometricCapacity, n = this.cachedMaxSegmentLength, r = Atomics.load(this.firstBlock.data, c) & y;
|
|
160
162
|
for (let i = 0; i < r; i++) {
|
|
161
163
|
let r, a;
|
|
162
164
|
if (i < t) r = 31 - Math.clz32((i / e | 0) + 1), a = i - e * ((1 << r) - 1);
|
|
@@ -167,46 +169,33 @@ var a = 0, o = 1, s = 2, c = 3, l = 4, u = 5, d = 6, f = 7, p = 4, m = 20, h = 2
|
|
|
167
169
|
let o = this.cachedSequences[r] ?? (this.getSegment(r), this.cachedSequences[r]), s = Atomics.load(o, a);
|
|
168
170
|
s & 1 && Atomics.store(o, a, s + 1);
|
|
169
171
|
}
|
|
170
|
-
Atomics.store(this.firstBlock.data,
|
|
172
|
+
Atomics.store(this.firstBlock.data, c, 0);
|
|
171
173
|
}
|
|
172
174
|
*[Symbol.iterator]() {
|
|
173
175
|
let e = this.length, t = this.cachedMaxSegmentLength, n = this.baseSegmentLength, r = 0, i = this.getSegment(r), a = 0;
|
|
174
176
|
for (let o = 0; o < e; o++) yield i[a], a++, a >= n && (r++, i = this.getSegment(r), a = 0, n = Math.min(n * 2, t));
|
|
175
177
|
}
|
|
176
|
-
getSegment(
|
|
177
|
-
if (this.cachedSegments[
|
|
178
|
-
let
|
|
179
|
-
if (
|
|
180
|
-
|
|
178
|
+
getSegment(r) {
|
|
179
|
+
if (this.cachedSegments[r]) return this.cachedSegments[r];
|
|
180
|
+
let i = r < this.cachedCapSegmentCount ? this.cachedBaseSegmentLength << r : this.cachedMaxSegmentLength, c;
|
|
181
|
+
if (r >= this.segmentCount) {
|
|
182
|
+
o(this.growLock);
|
|
181
183
|
try {
|
|
182
|
-
|
|
184
|
+
r >= this.segmentCount && (c = this.memory.allocUI32(i * (this.cachedByteMultipler + 1)), t(this.firstBlock.data, h + r, c.bufferPosition, c.bufferByteOffset, this.memory.positionBits), Atomics.add(this.firstBlock.data, p, 1));
|
|
183
185
|
} finally {
|
|
184
|
-
|
|
186
|
+
s(this.growLock);
|
|
185
187
|
}
|
|
186
188
|
}
|
|
187
|
-
if (!
|
|
188
|
-
let t = Atomics.load(this.firstBlock.data,
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
let c;
|
|
192
|
-
switch (this.type) {
|
|
193
|
-
case 1:
|
|
194
|
-
c = new Int32Array(s.data.buffer, s.bufferByteOffset, o);
|
|
195
|
-
break;
|
|
196
|
-
case 0:
|
|
197
|
-
c = new Uint32Array(s.data.buffer, s.bufferByteOffset, o);
|
|
198
|
-
break;
|
|
199
|
-
case 2:
|
|
200
|
-
c = new Float32Array(s.data.buffer, s.bufferByteOffset, o);
|
|
201
|
-
break;
|
|
202
|
-
default: throw Error(`Unknown data block type ${this.type}`);
|
|
189
|
+
if (!c) {
|
|
190
|
+
let t = Atomics.load(this.firstBlock.data, h + r), i = e(t, this.memory.positionBits);
|
|
191
|
+
c = new n(this.memory, i);
|
|
203
192
|
}
|
|
204
|
-
let l =
|
|
205
|
-
return this.cachedSequences[
|
|
193
|
+
let l = a(this.type, c.data.buffer, c.bufferByteOffset, i), u = c.bufferByteOffset + i * this.cachedByteMultipler * Uint32Array.BYTES_PER_ELEMENT;
|
|
194
|
+
return this.cachedSequences[r] = new Int32Array(c.data.buffer, u, i), this.cachedSegments[r] = l, l;
|
|
206
195
|
}
|
|
207
196
|
free() {
|
|
208
197
|
for (let t = 0; t < this.segmentCount; t++) {
|
|
209
|
-
let r = Atomics.load(this.firstBlock.data,
|
|
198
|
+
let r = Atomics.load(this.firstBlock.data, h + t), i = e(r, this.memory.positionBits);
|
|
210
199
|
new n(this.memory, i).free();
|
|
211
200
|
}
|
|
212
201
|
this.ownsFirstBlock && this.firstBlock.free();
|
|
@@ -216,6 +205,6 @@ var a = 0, o = 1, s = 2, c = 3, l = 4, u = 5, d = 6, f = 7, p = 4, m = 20, h = 2
|
|
|
216
205
|
}
|
|
217
206
|
};
|
|
218
207
|
//#endregion
|
|
219
|
-
export {
|
|
208
|
+
export { S as default };
|
|
220
209
|
|
|
221
210
|
//# sourceMappingURL=shared-stack.js.map
|