@daneren2005/shared-memory-objects 1.0.0 → 1.2.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/LICENSE +21 -0
- package/README.md +78 -55
- package/dist/{src/allocated-memory.d.ts → allocated-memory.d.ts} +5 -4
- package/dist/allocated-memory.js +45 -0
- package/dist/allocated-memory.js.map +1 -0
- package/dist/{src/cached-item-list.d.ts → cached-item-list.d.ts} +3 -3
- package/dist/cached-item-list.js +71 -0
- package/dist/cached-item-list.js.map +1 -0
- package/dist/constant-string.d.ts +15 -0
- package/dist/constant-string.js +67 -0
- package/dist/constant-string.js.map +1 -0
- package/dist/interfaces/pow2.js +0 -0
- package/dist/interfaces/typed-array-constructor.js +0 -0
- package/dist/interfaces/typed-array.js +0 -0
- package/dist/{src/local-pool.d.ts → local-pool.d.ts} +2 -2
- package/dist/local-pool.js +90 -0
- package/dist/local-pool.js.map +1 -0
- package/dist/lock/read-write-lock.js +19 -0
- package/dist/lock/read-write-lock.js.map +1 -0
- package/dist/lock/simple-lock.js +11 -0
- package/dist/lock/simple-lock.js.map +1 -0
- package/dist/{src/memory-buffer.d.ts → memory-buffer.d.ts} +4 -4
- package/dist/memory-buffer.js +267 -0
- package/dist/memory-buffer.js.map +1 -0
- package/dist/{src/memory-heap.d.ts → memory-heap.d.ts} +2 -2
- package/dist/memory-heap.js +96 -0
- package/dist/memory-heap.js.map +1 -0
- package/dist/{src/serialize-object.d.ts → serialize-object.d.ts} +2 -2
- package/dist/serialize-object.js +47 -0
- package/dist/serialize-object.js.map +1 -0
- package/dist/{src/shared-list.d.ts → shared-list.d.ts} +3 -3
- package/dist/shared-list.js +125 -0
- package/dist/shared-list.js.map +1 -0
- package/dist/{src/shared-map.d.ts → shared-map.d.ts} +2 -2
- package/dist/shared-map.js +104 -0
- package/dist/shared-map.js.map +1 -0
- package/dist/{src/shared-pointer-list.d.ts → shared-pointer-list.d.ts} +3 -3
- package/dist/shared-pointer-list.js +47 -0
- package/dist/shared-pointer-list.js.map +1 -0
- package/dist/{src/shared-pool.d.ts → shared-pool.d.ts} +11 -8
- package/dist/shared-pool.js +145 -0
- package/dist/shared-pool.js.map +1 -0
- package/dist/shared-stack.d.ts +46 -0
- package/dist/shared-stack.js +144 -0
- package/dist/shared-stack.js.map +1 -0
- package/dist/{src/shared-string.d.ts → shared-string.d.ts} +2 -2
- package/dist/shared-string.js +73 -0
- package/dist/shared-string.js.map +1 -0
- package/dist/{src/shared-vector.d.ts → shared-vector.d.ts} +4 -4
- package/dist/shared-vector.js +147 -0
- package/dist/shared-vector.js.map +1 -0
- package/dist/utils/16-from-32-array.js +18 -0
- package/dist/utils/16-from-32-array.js.map +1 -0
- package/dist/utils/16-from-64-array.js +17 -0
- package/dist/utils/16-from-64-array.js.map +1 -0
- package/dist/utils/atomic-math.js +34 -0
- package/dist/utils/atomic-math.js.map +1 -0
- package/dist/utils/float32-atomics.js +24 -0
- package/dist/utils/float32-atomics.js.map +1 -0
- package/dist/utils/float64-atomics.js +24 -0
- package/dist/utils/float64-atomics.js.map +1 -0
- package/dist/utils/pointer.js +34 -0
- package/dist/utils/pointer.js.map +1 -0
- package/dist/{src/utils → utils}/typedarray.d.ts +47 -47
- package/dist/utils/typedarray.js +39 -0
- package/dist/utils/typedarray.js.map +1 -0
- package/package.json +26 -31
- package/dist/shared-memory-objects.js +0 -1578
- package/dist/shared-memory-objects.js.map +0 -1
- package/dist/shared-memory-objects.umd.cjs +0 -2
- package/dist/shared-memory-objects.umd.cjs.map +0 -1
- package/dist/src/main.d.ts +0 -22
- /package/dist/{src/interfaces → interfaces}/pow2.d.ts +0 -0
- /package/dist/{src/interfaces → interfaces}/typed-array-constructor.d.ts +0 -0
- /package/dist/{src/interfaces → interfaces}/typed-array.d.ts +0 -0
- /package/dist/{src/lock → lock}/read-write-lock.d.ts +0 -0
- /package/dist/{src/lock → lock}/simple-lock.d.ts +0 -0
- /package/dist/{src/utils → utils}/16-from-32-array.d.ts +0 -0
- /package/dist/{src/utils → utils}/16-from-64-array.d.ts +0 -0
- /package/dist/{src/utils → utils}/atomic-math.d.ts +0 -0
- /package/dist/{src/utils → utils}/float32-atomics.d.ts +0 -0
- /package/dist/{src/utils → utils}/float64-atomics.d.ts +0 -0
- /package/dist/{src/utils → utils}/pointer.d.ts +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { getPointer as e, storePointer as t } from "./utils/pointer.js";
|
|
2
|
+
import n from "./allocated-memory.js";
|
|
3
|
+
import { lock as r, unlock as i } from "./lock/simple-lock.js";
|
|
4
|
+
//#region src/shared-stack.ts
|
|
5
|
+
var a = 0, o = 1, s = 2, c = 3, l = 4, u = 5, d = 6, f = 4, p = 20, m = 22, h = (1 << m) - 1, g = 4194302, _ = 1 << m, v = class m {
|
|
6
|
+
static BASE_ALLOCATE_COUNT = 7;
|
|
7
|
+
static DEFAULT_ALLOCATE_COUNT = this.BASE_ALLOCATE_COUNT + p;
|
|
8
|
+
memory;
|
|
9
|
+
firstBlock;
|
|
10
|
+
uint16Array;
|
|
11
|
+
growLock;
|
|
12
|
+
maxLength;
|
|
13
|
+
ownsFirstBlock;
|
|
14
|
+
cachedSegments = [];
|
|
15
|
+
cachedSequences = [];
|
|
16
|
+
cachedBaseSegmentLength = 0;
|
|
17
|
+
get length() {
|
|
18
|
+
return Atomics.load(this.firstBlock.data, a) & h;
|
|
19
|
+
}
|
|
20
|
+
get segmentCount() {
|
|
21
|
+
return Atomics.load(this.firstBlock.data, l);
|
|
22
|
+
}
|
|
23
|
+
set segmentCount(e) {
|
|
24
|
+
this.firstBlock.data[l] = e;
|
|
25
|
+
}
|
|
26
|
+
get type() {
|
|
27
|
+
return this.uint16Array[0];
|
|
28
|
+
}
|
|
29
|
+
set type(e) {
|
|
30
|
+
Atomics.store(this.uint16Array, 0, e);
|
|
31
|
+
}
|
|
32
|
+
get baseSegmentLength() {
|
|
33
|
+
return this.firstBlock.data[s];
|
|
34
|
+
}
|
|
35
|
+
set baseSegmentLength(e) {
|
|
36
|
+
this.firstBlock.data[s] = e;
|
|
37
|
+
}
|
|
38
|
+
get maxSegments() {
|
|
39
|
+
return this.firstBlock.data[c];
|
|
40
|
+
}
|
|
41
|
+
set maxSegments(e) {
|
|
42
|
+
this.firstBlock.data[c] = e;
|
|
43
|
+
}
|
|
44
|
+
get pointer() {
|
|
45
|
+
return this.firstBlock.pointer;
|
|
46
|
+
}
|
|
47
|
+
constructor(e, t) {
|
|
48
|
+
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 + o * Uint32Array.BYTES_PER_ELEMENT, 2), "type" in t || "baseSegmentLength" in t || "segmentCount" in t ? (this.initialize(t), this.ownsFirstBlock = !1) : this.ownsFirstBlock = !0;
|
|
49
|
+
else {
|
|
50
|
+
let n = t?.segmentCount ?? p;
|
|
51
|
+
this.firstBlock = e.allocUI32(m.BASE_ALLOCATE_COUNT + n), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + o * Uint32Array.BYTES_PER_ELEMENT, 2), this.ownsFirstBlock = !0, this.initialize(t);
|
|
52
|
+
}
|
|
53
|
+
if (this.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + u * Uint32Array.BYTES_PER_ELEMENT, 1), this.cachedBaseSegmentLength = this.baseSegmentLength, this.maxLength = this.cachedBaseSegmentLength * (2 ** this.maxSegments - 1), this.maxLength > g) throw Error(`SharedStack maxLength ${this.maxLength} exceeds the ${g} the versioned length counter can address`);
|
|
54
|
+
}
|
|
55
|
+
initialize(e) {
|
|
56
|
+
let n = e?.baseSegmentLength ?? f, r = this.memory.allocUI32(n * 2);
|
|
57
|
+
t(this.firstBlock.data, d, r.bufferPosition, r.bufferByteOffset), this.baseSegmentLength = n, this.maxSegments = e?.segmentCount ?? p, this.segmentCount = 1;
|
|
58
|
+
let i = e?.type ?? Uint32Array;
|
|
59
|
+
i === Uint32Array ? this.type = 0 : i === Int32Array ? this.type = 1 : i === Float32Array && (this.type = 2);
|
|
60
|
+
}
|
|
61
|
+
at(e) {
|
|
62
|
+
let t = this.length;
|
|
63
|
+
if (e >= t || e < 0) throw Error(`${e} is out of bounds ${t}`);
|
|
64
|
+
let n = this.cachedBaseSegmentLength, r = 31 - Math.clz32((e / n | 0) + 1);
|
|
65
|
+
return (this.cachedSegments[r] ?? this.getSegment(r))[e - n * ((1 << r) - 1)];
|
|
66
|
+
}
|
|
67
|
+
push(e) {
|
|
68
|
+
let t = this.firstBlock.data, n = this.cachedBaseSegmentLength;
|
|
69
|
+
for (;;) {
|
|
70
|
+
let r = t[a], i = r & h;
|
|
71
|
+
if (i >= this.maxLength) throw Error(`${i + 1} is out of bounds ${this.maxLength}`);
|
|
72
|
+
let o = 31 - Math.clz32((i / n | 0) + 1), s = i - n * ((1 << o) - 1), c = this.cachedSegments[o] ?? this.getSegment(o), l = this.cachedSequences[o], u = Atomics.load(l, s);
|
|
73
|
+
if (!(u & 1) && Atomics.compareExchange(t, a, r, r + _ + 1) === r) return c[s] = e, Atomics.store(l, s, u + 1), i;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
pop() {
|
|
77
|
+
let e = this.firstBlock.data, t = this.cachedBaseSegmentLength;
|
|
78
|
+
for (;;) {
|
|
79
|
+
let n = e[a], r = n & h;
|
|
80
|
+
if (r <= 0) return;
|
|
81
|
+
let i = r - 1, o = 31 - Math.clz32((i / t | 0) + 1), s = i - t * ((1 << o) - 1), c = this.cachedSegments[o] ?? this.getSegment(o), l = this.cachedSequences[o], u = Atomics.load(l, s);
|
|
82
|
+
if (!(u & 1) || Atomics.compareExchange(e, a, n, n + _ - 1) !== n) continue;
|
|
83
|
+
let d = c[s];
|
|
84
|
+
return Atomics.store(l, s, u + 1), d;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
clear() {
|
|
88
|
+
let e = this.cachedBaseSegmentLength, t = Atomics.load(this.firstBlock.data, a) & h;
|
|
89
|
+
for (let n = 0; n < t; n++) {
|
|
90
|
+
let t = 31 - Math.clz32((n / e | 0) + 1), r = this.cachedSequences[t] ?? (this.getSegment(t), this.cachedSequences[t]), i = n - e * ((1 << t) - 1), a = Atomics.load(r, i);
|
|
91
|
+
a & 1 && Atomics.store(r, i, a + 1);
|
|
92
|
+
}
|
|
93
|
+
Atomics.store(this.firstBlock.data, a, 0);
|
|
94
|
+
}
|
|
95
|
+
*[Symbol.iterator]() {
|
|
96
|
+
let e = this.length, t = this.baseSegmentLength, n = 0, r = this.getSegment(n), i = 0;
|
|
97
|
+
for (let a = 0; a < e; a++) yield r[i], i++, i >= t && (n++, r = this.getSegment(n), i = 0, t *= 2);
|
|
98
|
+
}
|
|
99
|
+
getSegment(a) {
|
|
100
|
+
if (this.cachedSegments[a]) return this.cachedSegments[a];
|
|
101
|
+
let o = this.cachedBaseSegmentLength * 2 ** a, s;
|
|
102
|
+
if (a >= this.segmentCount) {
|
|
103
|
+
r(this.growLock);
|
|
104
|
+
try {
|
|
105
|
+
a >= this.segmentCount && (s = this.memory.allocUI32(o * 2), t(this.firstBlock.data, d + a, s.bufferPosition, s.bufferByteOffset), Atomics.add(this.firstBlock.data, l, 1));
|
|
106
|
+
} finally {
|
|
107
|
+
i(this.growLock);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!s) {
|
|
111
|
+
let t = Atomics.load(this.firstBlock.data, d + a), r = e(t);
|
|
112
|
+
s = new n(this.memory, r);
|
|
113
|
+
}
|
|
114
|
+
let c;
|
|
115
|
+
switch (this.type) {
|
|
116
|
+
case 1:
|
|
117
|
+
c = new Int32Array(s.data.buffer, s.bufferByteOffset, o);
|
|
118
|
+
break;
|
|
119
|
+
case 0:
|
|
120
|
+
c = new Uint32Array(s.data.buffer, s.bufferByteOffset, o);
|
|
121
|
+
break;
|
|
122
|
+
case 2:
|
|
123
|
+
c = new Float32Array(s.data.buffer, s.bufferByteOffset, o);
|
|
124
|
+
break;
|
|
125
|
+
default: throw Error(`Unknown data block type ${this.type}`);
|
|
126
|
+
}
|
|
127
|
+
let u = s.bufferByteOffset + o * Uint32Array.BYTES_PER_ELEMENT;
|
|
128
|
+
return this.cachedSequences[a] = new Int32Array(s.data.buffer, u, o), this.cachedSegments[a] = c, c;
|
|
129
|
+
}
|
|
130
|
+
free() {
|
|
131
|
+
for (let t = 0; t < this.segmentCount; t++) {
|
|
132
|
+
let r = Atomics.load(this.firstBlock.data, d + t), i = e(r);
|
|
133
|
+
new n(this.memory, i).free();
|
|
134
|
+
}
|
|
135
|
+
this.ownsFirstBlock && this.firstBlock.free();
|
|
136
|
+
}
|
|
137
|
+
getSharedMemory() {
|
|
138
|
+
return { firstBlock: this.firstBlock.getSharedMemory() };
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
//#endregion
|
|
142
|
+
export { v as default };
|
|
143
|
+
|
|
144
|
+
//# sourceMappingURL=shared-stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-stack.js","names":[],"sources":["../src/shared-stack.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 { getPointer, storePointer } from './utils/pointer';\n\nenum TYPE {\n\tuint32,\n\tint32,\n\tfloat32,\n}\n\nconst LENGTH_INDEX = 0;\nconst TYPE_INDEX = 1;\nconst BASE_SEGMENT_LENGTH_INDEX = 2;\nconst MAX_SEGMENTS_INDEX = 3;\nconst SEGMENT_COUNT_INDEX = 4;\nconst GROW_LOCK_INDEX = 5;\nconst SEGMENT_START_INDEX = 6;\n\nconst DEFAULT_BASE_SEGMENT_LENGTH = 4;\nconst DEFAULT_MAX_SEGMENTS = 20;\n\n// The LENGTH word packs an ABA version counter (high bits) with the live count (low LEN_BITS). Both push and pop bump\n// the version on every successful CAS, so the CAS fails on ANY intervening op - the count can never ABA back to the\n// same value with a slot at a different generation. 22 count bits cover the default max length (4,194,300); the\n// remaining 10 version bits (1024) only need to outlast a single thread's load->CAS window.\nconst LEN_BITS = 22;\nconst LEN_MASK = (1 << LEN_BITS) - 1;\nconst MAX_COUNT = LEN_MASK - 1;\n// Adding this to the packed word bumps the version (high bits) by one. Combined with +1/-1 for the count it repacks the\n// whole word in a single add: the count is guarded from overflowing into the version bits, and a version overflow just\n// wraps harmlessly when the value is coerced back to Uint32 on the atomic store.\nconst VERSION_STEP = 1 << LEN_BITS;\n\n// Per-slot publish handshake. Each data slot has a companion sequence number: even means the slot is empty (free to\n// fill) at some lap, odd means the value is published (safe to read). It only ever increases. push/pop read the slot's\n// sequence and bail out (retry) unless it has the parity they need, then CAS the length; because the versioned CAS\n// rejects any intervening op, the sequence read stays valid all the way through the publish store below.\n\nexport default class SharedStack<T extends Uint32Array | Int32Array | Float32Array = Uint32Array> implements Iterable<number> {\n\tstatic readonly BASE_ALLOCATE_COUNT = 7;\n\tstatic readonly DEFAULT_ALLOCATE_COUNT = this.BASE_ALLOCATE_COUNT + DEFAULT_MAX_SEGMENTS;\n\tprivate memory: MemoryHeap;\n\n\t// Length, Type, Base Segment Length, Max Segments, Segment Count, Grow Lock, Segments\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\tprivate growLock: Int32Array;\n\treadonly maxLength: number;\n\n\t// False when firstBlock is a slice of another structure's memory (e.g. inlined in SharedPool); that owner frees it\n\tprivate ownsFirstBlock: boolean;\n\n\tprivate cachedSegments: T[] = [];\n\t// Parallel to cachedSegments: the per-slot publish sequences for each slot of that segment. Populated together with\n\t// the data view in getSegment, so whenever cachedSegments[i] is set cachedSequences[i] is too.\n\tprivate cachedSequences: Int32Array[] = [];\n\tprivate cachedBaseSegmentLength = 0;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX) & LEN_MASK;\n\t}\n\tget segmentCount(): number {\n\t\treturn Atomics.load(this.firstBlock.data, SEGMENT_COUNT_INDEX);\n\t}\n\tprivate set segmentCount(value: number) {\n\t\tthis.firstBlock.data[SEGMENT_COUNT_INDEX] = value;\n\t}\n\t\n\tget type(): number {\n\t\treturn this.uint16Array[0];\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\n\tget baseSegmentLength() {\n\t\treturn this.firstBlock.data[BASE_SEGMENT_LENGTH_INDEX];\n\t}\n\tprivate set baseSegmentLength(value: number) {\n\t\tthis.firstBlock.data[BASE_SEGMENT_LENGTH_INDEX] = value;\n\t}\n\tget maxSegments() {\n\t\treturn this.firstBlock.data[MAX_SEGMENTS_INDEX];\n\t}\n\tprivate set maxSegments(value: number) {\n\t\tthis.firstBlock.data[MAX_SEGMENTS_INDEX] = value;\n\t}\n\n\tget pointer() {\n\t\treturn this.firstBlock.pointer;\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedStackConfig<T> | SharedStackMemory | SharedStackMemory & SharedStackConfig<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 SharedPool); 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 || 'baseSegmentLength' in config || 'segmentCount' 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.ownsFirstBlock = true;\n\t\t\t}\n\t\t} else {\n\t\t\tlet maxSegments = config?.segmentCount ?? DEFAULT_MAX_SEGMENTS;\n\n\t\t\tthis.firstBlock = memory.allocUI32(SharedStack.BASE_ALLOCATE_COUNT + maxSegments);\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.ownsFirstBlock = true;\n\n\t\t\tthis.initialize(config);\n\t\t}\n\n\t\tthis.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + GROW_LOCK_INDEX * Uint32Array.BYTES_PER_ELEMENT, 1);\n\t\tthis.cachedBaseSegmentLength = this.baseSegmentLength;\n\t\tthis.maxLength = this.cachedBaseSegmentLength * (2 ** this.maxSegments - 1);\n\t\tif(this.maxLength > MAX_COUNT) {\n\t\t\t// The length word reserves LEN_BITS for the count and the rest for the ABA version tag\n\t\t\tthrow new Error(`SharedStack maxLength ${this.maxLength} exceeds the ${MAX_COUNT} the versioned length counter can address`);\n\t\t}\n\t}\n\n\tprivate initialize(config?: SharedStackConfig<T>) {\n\t\tlet baseSegmentLength = config?.baseSegmentLength ?? DEFAULT_BASE_SEGMENT_LENGTH;\n\t\t// Each segment block holds the data slots followed by an equal-length region of publish sequences\n\t\tlet firstSegmentBlock = this.memory.allocUI32(baseSegmentLength * 2);\n\t\tstorePointer(this.firstBlock.data, SEGMENT_START_INDEX, firstSegmentBlock.bufferPosition, firstSegmentBlock.bufferByteOffset);\n\t\tthis.baseSegmentLength = baseSegmentLength;\n\t\tthis.maxSegments = config?.segmentCount ?? DEFAULT_MAX_SEGMENTS;\n\t\tthis.segmentCount = 1;\n\n\t\tconst type = config?.type ?? Uint32Array;\n\t\tif(type === Uint32Array) {\n\t\t\tthis.type = TYPE.uint32;\n\t\t// @ts-expect-error\n\t\t} else if(type === Int32Array) {\n\t\t\tthis.type = TYPE.int32;\n\t\t// @ts-expect-error\n\t\t} else if(type === Float32Array) {\n\t\t\tthis.type = TYPE.float32;\n\t\t}\n\t}\n\n\tat(index: number): number {\n\t\tlet length = this.length;\n\t\tif(index >= length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${length}`);\n\t\t}\n\n\t\tlet baseSegmentLength = this.cachedBaseSegmentLength;\n\t\tlet segmentIndex = 31 - Math.clz32(((index / baseSegmentLength) | 0) + 1);\n\t\tlet segment = this.cachedSegments[segmentIndex] ?? this.getSegment(segmentIndex);\n\t\treturn segment[index - baseSegmentLength * ((1 << segmentIndex) - 1)];\n\t}\n\n\tpush(value: number): number {\n\t\tlet data = this.firstBlock.data;\n\t\tlet baseSegmentLength = this.cachedBaseSegmentLength;\n\t\t// eslint-disable-next-line no-constant-condition\n\t\twhile(true) {\n\t\t\t// Plain (relaxed) read is enough: it only seeds the versioned CAS below, which rejects any stale value\n\t\t\tlet packed = data[LENGTH_INDEX];\n\t\t\tlet newIndex = packed & LEN_MASK;\n\t\t\tif(newIndex >= this.maxLength) {\n\t\t\t\tthrow new Error(`${newIndex + 1} is out of bounds ${this.maxLength}`);\n\t\t\t}\n\n\t\t\tlet segmentIndex = 31 - Math.clz32(((newIndex / baseSegmentLength) | 0) + 1);\n\t\t\tlet localIndex = newIndex - baseSegmentLength * ((1 << segmentIndex) - 1);\n\t\t\tlet segment = this.cachedSegments[segmentIndex] ?? this.getSegment(segmentIndex);\n\t\t\tlet sequences = this.cachedSequences[segmentIndex];\n\n\t\t\t// The slot must be empty (even sequence) to fill. Odd means a popper hasn't finished emptying it yet - retry\n\t\t\tlet sequence = Atomics.load(sequences, localIndex);\n\t\t\tif((sequence & 1) !== 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Take the slot only if the whole versioned length word is unchanged. The version bump makes this fail on any\n\t\t\t// intervening op, so a win guarantees nothing touched the top - and our sequence read above is still valid\n\t\t\tif(Atomics.compareExchange(data, LENGTH_INDEX, packed, packed + VERSION_STEP + 1) !== packed) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tsegment[localIndex] = value;\n\t\t\t// Publish: bump to odd (full). Safe as a plain store - no other op can claim this slot until the length comes\n\t\t\t// back down to it, which can't happen (its popper is gated on an odd sequence) until this store lands\n\t\t\tAtomics.store(sequences, localIndex, sequence + 1);\n\t\t\treturn newIndex;\n\t\t}\n\t}\n\n\tpop(): number | undefined {\n\t\tlet data = this.firstBlock.data;\n\t\tlet baseSegmentLength = this.cachedBaseSegmentLength;\n\t\t// eslint-disable-next-line no-constant-condition\n\t\twhile(true) {\n\t\t\t// Plain (relaxed) read is enough: it only seeds the versioned CAS below, which rejects any stale value\n\t\t\tlet packed = data[LENGTH_INDEX];\n\t\t\tlet length = packed & LEN_MASK;\n\t\t\tif(length <= 0) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tlet oldIndex = length - 1;\n\n\t\t\tlet segmentIndex = 31 - Math.clz32(((oldIndex / baseSegmentLength) | 0) + 1);\n\t\t\tlet localIndex = oldIndex - baseSegmentLength * ((1 << segmentIndex) - 1);\n\t\t\tlet segment = this.cachedSegments[segmentIndex] ?? this.getSegment(segmentIndex);\n\t\t\tlet sequences = this.cachedSequences[segmentIndex];\n\n\t\t\t// The slot must be full (odd sequence) to read. Even means a pusher hasn't finished publishing it yet - retry\n\t\t\tlet sequence = Atomics.load(sequences, localIndex);\n\t\t\tif((sequence & 1) === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(Atomics.compareExchange(data, LENGTH_INDEX, packed, packed + VERSION_STEP - 1) !== packed) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet value = segment[localIndex];\n\t\t\t// Release the slot: bump to even (empty) so a later push may reuse it\n\t\t\tAtomics.store(sequences, localIndex, sequence + 1);\n\t\t\treturn value;\n\t\t}\n\t}\n\n\tclear() {\n\t\t// Mark every occupied slot empty (bump its odd sequence to the next even) before dropping the length, otherwise a\n\t\t// later push reusing the slot would spin forever on a stale full sequence. Not safe to call concurrently with push/pop.\n\t\tlet baseSegmentLength = this.cachedBaseSegmentLength;\n\t\tlet oldLength = Atomics.load(this.firstBlock.data, LENGTH_INDEX) & LEN_MASK;\n\t\tfor(let i = 0; i < oldLength; i++) {\n\t\t\tlet segmentIndex = 31 - Math.clz32(((i / baseSegmentLength) | 0) + 1);\n\t\t\tlet sequences = this.cachedSequences[segmentIndex] ?? (this.getSegment(segmentIndex), this.cachedSequences[segmentIndex]);\n\t\t\tlet localIndex = i - baseSegmentLength * ((1 << segmentIndex) - 1);\n\t\t\tlet sequence = Atomics.load(sequences, localIndex);\n\t\t\tif((sequence & 1) !== 0) {\n\t\t\t\tAtomics.store(sequences, localIndex, sequence + 1);\n\t\t\t}\n\t\t}\n\t\tAtomics.store(this.firstBlock.data, LENGTH_INDEX, 0);\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tlet totalDataEntries = this.length;\n\n\t\tlet segmentLength = this.baseSegmentLength;\n\t\tlet segmentIndex = 0;\n\t\tlet segment = this.getSegment(segmentIndex);\n\t\tlet segmentDataIndex = 0;\n\t\tfor(let i = 0; i < totalDataEntries; i++) {\n\t\t\tyield segment[segmentDataIndex];\n\t\t\tsegmentDataIndex++;\n\t\t\tif(segmentDataIndex >= segmentLength) {\n\t\t\t\tsegmentIndex++;\n\t\t\t\tsegment = this.getSegment(segmentIndex);\n\t\t\t\tsegmentDataIndex = 0;\n\t\t\t\tsegmentLength = segmentLength * 2;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getSegment(segmentIndex: number): T {\n\t\tif(this.cachedSegments[segmentIndex]) {\n\t\t\treturn this.cachedSegments[segmentIndex];\n\t\t}\n\n\t\tlet segmentLength = this.cachedBaseSegmentLength * 2 ** segmentIndex;\n\t\tlet segmentDataBlock: AllocatedMemory | undefined;\n\t\tif(segmentIndex >= this.segmentCount) {\n\t\t\t// Lock when growing so another thread doesn't also setup the same segment\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 segment while we were waiting\n\t\t\t\tif(segmentIndex >= this.segmentCount) {\n\t\t\t\t\t// Double length: the data slots followed by their publish sequences (calloc-zeroed = 0 = empty)\n\t\t\t\t\tsegmentDataBlock = this.memory.allocUI32(segmentLength * 2);\n\t\t\t\t\tstorePointer(this.firstBlock.data, SEGMENT_START_INDEX + segmentIndex, segmentDataBlock.bufferPosition, segmentDataBlock.bufferByteOffset);\n\t\t\t\t\tAtomics.add(this.firstBlock.data, SEGMENT_COUNT_INDEX, 1);\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\tif(!segmentDataBlock) {\n\t\t\tlet pointerNumber = Atomics.load(this.firstBlock.data, SEGMENT_START_INDEX + segmentIndex);\n\t\t\tlet pointer = getPointer(pointerNumber);\n\t\t\tsegmentDataBlock = new AllocatedMemory(this.memory, pointer);\n\t\t}\n\n\t\tlet data: T;\n\t\tswitch(this.type) {\n\t\t\tcase TYPE.int32:\n\t\t\t\tdata = new Int32Array(segmentDataBlock.data.buffer, segmentDataBlock.bufferByteOffset, segmentLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.uint32:\n\t\t\t\tdata = new Uint32Array(segmentDataBlock.data.buffer, segmentDataBlock.bufferByteOffset, segmentLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.float32:\n\t\t\t\tdata = new Float32Array(segmentDataBlock.data.buffer, segmentDataBlock.bufferByteOffset, segmentLength) as T;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown data block type ${this.type}`);\n\t\t}\n\t\t// Publish sequences live in the second half of the block, always as Int32 regardless of the data type\n\t\tlet sequenceByteOffset = segmentDataBlock.bufferByteOffset + segmentLength * Uint32Array.BYTES_PER_ELEMENT;\n\t\tthis.cachedSequences[segmentIndex] = new Int32Array(segmentDataBlock.data.buffer, sequenceByteOffset, segmentLength);\n\t\tthis.cachedSegments[segmentIndex] = data;\n\n\t\treturn data;\n\t}\n\n\tfree() {\n\t\tfor(let i = 0; i < this.segmentCount; i++) {\n\t\t\tlet pointerNumber = Atomics.load(this.firstBlock.data, SEGMENT_START_INDEX + i);\n\t\t\tlet pointer = getPointer(pointerNumber);\n\t\t\tlet rawData = new AllocatedMemory(this.memory, pointer);\n\t\t\trawData.free();\n\t\t}\n\t\tif(this.ownsFirstBlock) {\n\t\t\tthis.firstBlock.free();\n\t\t}\n\t}\n\n\tgetSharedMemory(): SharedStackMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedStackConfig<T extends Uint32Array | Int32Array | Float32Array> {\n\ttype?: TypedArrayConstructor<T>\n\n\tbaseSegmentLength?: number\n\tsegmentCount?: number\n}\ninterface SharedStackMemory {\n\tfirstBlock: SharedAllocatedMemory | AllocatedMemory\n}\n\nexport type { SharedStackConfig, SharedStackMemory };"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { SharedAllocatedMemory } from './allocated-memory';
|
|
2
|
-
import
|
|
1
|
+
import type { SharedAllocatedMemory } from './allocated-memory';
|
|
2
|
+
import type MemoryHeap from './memory-heap';
|
|
3
3
|
export default class SharedString {
|
|
4
4
|
static readonly ALLOCATE_COUNT = 4;
|
|
5
5
|
private memory;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { getPointer as e, loadPointer as t, loadRawPointer as n, storeRawPointer as r } from "./utils/pointer.js";
|
|
2
|
+
import i from "./allocated-memory.js";
|
|
3
|
+
import { lock as a, unlock as o } from "./lock/simple-lock.js";
|
|
4
|
+
//#region src/shared-string.ts
|
|
5
|
+
var s = {
|
|
6
|
+
1: Uint8Array,
|
|
7
|
+
2: Uint16Array
|
|
8
|
+
}, c = 0, l = 1, u = 2, d = 3, f = class f {
|
|
9
|
+
static ALLOCATE_COUNT = 4;
|
|
10
|
+
memory;
|
|
11
|
+
allocatedMemory;
|
|
12
|
+
lock;
|
|
13
|
+
cachedPointer;
|
|
14
|
+
cachedString;
|
|
15
|
+
constructor(e, t) {
|
|
16
|
+
this.memory = e, typeof t == "string" ? (this.allocatedMemory = this.memory.allocUI32(f.ALLOCATE_COUNT), this.lock = new Int32Array(this.allocatedMemory.data.buffer, this.allocatedMemory.bufferByteOffset + d * this.allocatedMemory.data.BYTES_PER_ELEMENT), this.updateString(t)) : (this.allocatedMemory = new i(e, t), this.lock = new Int32Array(this.allocatedMemory.data.buffer, this.allocatedMemory.bufferByteOffset + d * this.allocatedMemory.data.BYTES_PER_ELEMENT), "value" in t && this.updateString(t.value));
|
|
17
|
+
}
|
|
18
|
+
updateString(e) {
|
|
19
|
+
let t = this.createString(e);
|
|
20
|
+
a(this.lock), r(this.allocatedMemory.data, c, t.pointer), Atomics.store(this.allocatedMemory.data, l, e.length), Atomics.store(this.allocatedMemory.data, u, t.charType), o(this.lock), this.cachedPointer = t.pointer, this.cachedString = e;
|
|
21
|
+
}
|
|
22
|
+
createString(e) {
|
|
23
|
+
if (e === "") return {
|
|
24
|
+
pointer: 0,
|
|
25
|
+
charType: 1
|
|
26
|
+
};
|
|
27
|
+
let t = 0;
|
|
28
|
+
for (let n = 0; n < e.length; n++) {
|
|
29
|
+
let r = e.charCodeAt(n);
|
|
30
|
+
r > t && (t = r);
|
|
31
|
+
}
|
|
32
|
+
let n = t > 255 ? 2 : 1, r = s[n], i = this.memory.allocUI32(Math.ceil(e.length / (4 / r.BYTES_PER_ELEMENT))), a = new r(i.data.buffer, i.data.byteOffset, e.length);
|
|
33
|
+
for (let t = 0; t < e.length; t++) a[t] = e.charCodeAt(t);
|
|
34
|
+
return {
|
|
35
|
+
pointer: i.pointer,
|
|
36
|
+
charType: n
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
get value() {
|
|
40
|
+
let t = n(this.allocatedMemory.data, c);
|
|
41
|
+
if (this.cachedPointer === t && this.cachedString !== void 0) return this.cachedString;
|
|
42
|
+
if (t === 0) return "";
|
|
43
|
+
let { bufferPosition: r, bufferByteOffset: i } = e(t);
|
|
44
|
+
a(this.lock);
|
|
45
|
+
let d = s[Atomics.load(this.allocatedMemory.data, u)], f = Atomics.load(this.allocatedMemory.data, l), m = p(new d(this.memory.buffers[r].buf, i, f));
|
|
46
|
+
return o(this.lock), this.cachedPointer = t, this.cachedString = m, m;
|
|
47
|
+
}
|
|
48
|
+
set value(e) {
|
|
49
|
+
let { bufferPosition: n, bufferByteOffset: r } = t(this.allocatedMemory.data, c);
|
|
50
|
+
this.updateString(e), r && this.memory.buffers[n].free(r);
|
|
51
|
+
}
|
|
52
|
+
getSharedMemory() {
|
|
53
|
+
return this.allocatedMemory.getSharedMemory();
|
|
54
|
+
}
|
|
55
|
+
get pointer() {
|
|
56
|
+
return this.allocatedMemory.pointer;
|
|
57
|
+
}
|
|
58
|
+
free() {
|
|
59
|
+
let { bufferPosition: e, bufferByteOffset: n } = t(this.allocatedMemory.data, c);
|
|
60
|
+
n && this.memory.buffers[e].free(n), this.allocatedMemory.free();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
function p(e) {
|
|
64
|
+
let t = 8192;
|
|
65
|
+
if (e.length <= t) return String.fromCharCode.apply(null, e);
|
|
66
|
+
let n = "";
|
|
67
|
+
for (let r = 0; r < e.length; r += t) n += String.fromCharCode.apply(null, e.subarray(r, r + t));
|
|
68
|
+
return n;
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { f as default };
|
|
72
|
+
|
|
73
|
+
//# sourceMappingURL=shared-string.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-string.js","names":[],"sources":["../src/shared-string.ts"],"sourcesContent":["import AllocatedMemory from './allocated-memory';\nimport type { SharedAllocatedMemory } from './allocated-memory';\nimport { lock, unlock } from './lock/simple-lock';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer, loadPointer, loadRawPointer, storeRawPointer } from './utils/pointer';\n\nenum CHAR_TYPE {\n\tUNDEFINED,\n\tASCII,\n\tUTF16,\n}\nconst TYPED_ARRAY_MAP = {\n\t[CHAR_TYPE.ASCII]: Uint8Array,\n\t[CHAR_TYPE.UTF16]: Uint16Array,\n};\n\nconst POINTER_INDEX = 0;\nconst LENGTH_INDEX = 1;\nconst TYPE_INDEX = 2;\nconst LOCK_INDEX = 3;\nexport default class SharedString {\n\tstatic readonly ALLOCATE_COUNT = 4;\n\n\tprivate memory: MemoryHeap;\n\tprivate allocatedMemory: AllocatedMemory;\n\tprivate lock: Int32Array;\n\n\tprivate cachedPointer?: number;\n\tprivate cachedString?: string;\n\t\n\tconstructor(memory: MemoryHeap, value: string | SharedStringConfig | SharedStringMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(typeof value === 'string') {\n\t\t\tthis.allocatedMemory = this.memory.allocUI32(SharedString.ALLOCATE_COUNT);\n\t\t\tthis.lock = new Int32Array(this.allocatedMemory.data.buffer, this.allocatedMemory.bufferByteOffset + LOCK_INDEX * this.allocatedMemory.data.BYTES_PER_ELEMENT);\n\t\t\tthis.updateString(value);\n\t\t} else {\n\t\t\tthis.allocatedMemory = new AllocatedMemory(memory, value);\n\t\t\tthis.lock = new Int32Array(this.allocatedMemory.data.buffer, this.allocatedMemory.bufferByteOffset + LOCK_INDEX * this.allocatedMemory.data.BYTES_PER_ELEMENT);\n\n\t\t\t// We only allocated memory but didn't initialize the string yet\n\t\t\tif('value' in value) {\n\t\t\t\tthis.updateString(value.value);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tprivate updateString(value: string) {\n\t\tlet stringMemory = this.createString(value);\n\n\t\tlock(this.lock);\n\t\tstoreRawPointer(this.allocatedMemory.data, POINTER_INDEX, stringMemory.pointer);\n\t\tAtomics.store(this.allocatedMemory.data, LENGTH_INDEX, value.length);\n\t\tAtomics.store(this.allocatedMemory.data, TYPE_INDEX, stringMemory.charType);\n\t\tunlock(this.lock);\n\n\t\tthis.cachedPointer = stringMemory.pointer;\n\t\tthis.cachedString = value;\n\t}\n\tprivate createString(value: string) {\n\t\tif(value === '') {\n\t\t\treturn {\n\t\t\t\tpointer: 0,\n\t\t\t\tcharType: CHAR_TYPE.ASCII,\n\t\t\t};\n\t\t}\n\n\t\t// NOTE: Scan with a loop instead of Math.max(...charCodes) which blows the stack for large strings\n\t\tlet maxCharCode = 0;\n\t\tfor(let i = 0; i < value.length; i++) {\n\t\t\tlet charCode = value.charCodeAt(i);\n\t\t\tif(charCode > maxCharCode) {\n\t\t\t\tmaxCharCode = charCode;\n\t\t\t}\n\t\t}\n\t\tlet charType = maxCharCode > 255 ? CHAR_TYPE.UTF16 : CHAR_TYPE.ASCII;\n\n\t\tlet typedArray = TYPED_ARRAY_MAP[charType];\n\t\tlet allocatedMemory = this.memory.allocUI32(Math.ceil(value.length / (4 / typedArray.BYTES_PER_ELEMENT)));\n\t\tlet data = new typedArray(allocatedMemory.data.buffer as ArrayBuffer, allocatedMemory.data.byteOffset, value.length);\n\t\tfor(let i = 0; i < value.length; i++) {\n\t\t\tdata[i] = value.charCodeAt(i);\n\t\t}\n\n\t\treturn {\n\t\t\tpointer: allocatedMemory.pointer,\n\t\t\tcharType,\n\t\t};\n\t}\n\n\tget value(): string {\n\t\tlet pointer = loadRawPointer(this.allocatedMemory.data, POINTER_INDEX);\n\t\tif(this.cachedPointer === pointer && this.cachedString !== undefined) {\n\t\t\treturn this.cachedString;\n\t\t} else if(pointer === 0) {\n\t\t\treturn '';\n\t\t}\n\t\tlet { bufferPosition, bufferByteOffset } = getPointer(pointer);\n\n\t\tlock(this.lock);\n\t\tlet charType = Atomics.load(this.allocatedMemory.data, TYPE_INDEX);\n\t\t// @ts-expect-error\n\t\tlet typedArray = TYPED_ARRAY_MAP[charType];\n\t\tlet bufferLength = Atomics.load(this.allocatedMemory.data, LENGTH_INDEX);\n\n\t\tlet data = new typedArray(this.memory.buffers[bufferPosition].buf, bufferByteOffset, bufferLength);\n\t\tlet string = fromCharCodes(data);\n\t\t// NOTE: Do not unlock until after transforming the data since the second this is done it can free that memory block\n\t\tunlock(this.lock);\n\n\t\tthis.cachedPointer = pointer;\n\t\tthis.cachedString = string;\n\n\t\treturn string;\n\t}\n\tset value(value: string) {\n\t\tlet { bufferPosition: oldBufferPosition, bufferByteOffset: oldBufferByteOffset } = loadPointer(this.allocatedMemory.data, POINTER_INDEX);\n\t\tthis.updateString(value);\n\n\t\tif(oldBufferByteOffset) {\n\t\t\tthis.memory.buffers[oldBufferPosition].free(oldBufferByteOffset);\n\t\t}\n\t}\n\n\tgetSharedMemory(): SharedStringMemory {\n\t\treturn this.allocatedMemory.getSharedMemory();\n\t}\n\n\tget pointer() {\n\t\treturn this.allocatedMemory.pointer;\n\t}\n\n\tfree() {\n\t\tlet { bufferPosition, bufferByteOffset } = loadPointer(this.allocatedMemory.data, POINTER_INDEX);\n\t\tif(bufferByteOffset) {\n\t\t\tthis.memory.buffers[bufferPosition].free(bufferByteOffset);\n\t\t}\n\t\tthis.allocatedMemory.free();\n\t}\n}\n\n// String.fromCharCode.apply throws a RangeError (Maximum call stack size exceeded) when handed too many\n// arguments at once, so decode large buffers in chunks to support arbitrarily long strings\nfunction fromCharCodes(data: Uint8Array | Uint16Array): string {\n\tconst CHUNK_SIZE = 8192;\n\tif(data.length <= CHUNK_SIZE) {\n\t\treturn String.fromCharCode.apply(null, data as unknown as Array<number>);\n\t}\n\n\tlet string = '';\n\tfor(let i = 0; i < data.length; i += CHUNK_SIZE) {\n\t\tstring += String.fromCharCode.apply(null, data.subarray(i, i + CHUNK_SIZE) as unknown as Array<number>);\n\t}\n\n\treturn string;\n}\n\ninterface SharedStringConfig extends SharedStringMemory {\n\tvalue: string\n}\ntype SharedStringMemory = SharedAllocatedMemory;"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SharedAllocatedMemory } from './allocated-memory';
|
|
2
|
-
import { TypedArrayConstructor } from './interfaces/typed-array-constructor';
|
|
3
|
-
import
|
|
1
|
+
import type { SharedAllocatedMemory } from './allocated-memory';
|
|
2
|
+
import type { TypedArrayConstructor } from './interfaces/typed-array-constructor';
|
|
3
|
+
import type MemoryHeap from './memory-heap';
|
|
4
4
|
export default class SharedVector<T extends Uint32Array | Int32Array | Float32Array = Uint32Array> implements Iterable<T> {
|
|
5
5
|
static readonly ALLOCATE_COUNT = 4;
|
|
6
6
|
private memory;
|
|
@@ -16,7 +16,7 @@ export default class SharedVector<T extends Uint32Array | Int32Array | Float32Ar
|
|
|
16
16
|
get pointer(): number;
|
|
17
17
|
private cachedFullDataBlock?;
|
|
18
18
|
private cachedPointer;
|
|
19
|
-
constructor(memory: MemoryHeap, config?: SharedVectorConfig<T> | SharedVectorMemory | SharedVectorMemory & SharedVectorConfig<T>);
|
|
19
|
+
constructor(memory: MemoryHeap, config?: SharedVectorConfig<T> | SharedVectorMemory | (SharedVectorMemory & SharedVectorConfig<T>));
|
|
20
20
|
at(index: number): T;
|
|
21
21
|
get(index: number, dataIndex?: number): number;
|
|
22
22
|
push(values: number | Array<number>): number;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { getPointer as e, loadPointer as t, storePointer as n, storeRawPointer as r } from "./utils/pointer.js";
|
|
2
|
+
import i from "./allocated-memory.js";
|
|
3
|
+
//#region src/shared-vector.ts
|
|
4
|
+
var a = 0, o = 1, s = 2, c = 3, l = 4, u = class u {
|
|
5
|
+
static ALLOCATE_COUNT = 4;
|
|
6
|
+
memory;
|
|
7
|
+
firstBlock;
|
|
8
|
+
uint16Array;
|
|
9
|
+
get length() {
|
|
10
|
+
return Atomics.load(this.firstBlock.data, o);
|
|
11
|
+
}
|
|
12
|
+
get type() {
|
|
13
|
+
return this.uint16Array[0];
|
|
14
|
+
}
|
|
15
|
+
set type(e) {
|
|
16
|
+
Atomics.store(this.uint16Array, 0, e);
|
|
17
|
+
}
|
|
18
|
+
get dataLength() {
|
|
19
|
+
return this.uint16Array[1] || 1;
|
|
20
|
+
}
|
|
21
|
+
set dataLength(e) {
|
|
22
|
+
Atomics.store(this.uint16Array, 1, e);
|
|
23
|
+
}
|
|
24
|
+
get bufferLength() {
|
|
25
|
+
return Atomics.load(this.firstBlock.data, s);
|
|
26
|
+
}
|
|
27
|
+
set bufferLength(e) {
|
|
28
|
+
Atomics.store(this.firstBlock.data, s, e);
|
|
29
|
+
}
|
|
30
|
+
get pointer() {
|
|
31
|
+
return this.firstBlock.pointer;
|
|
32
|
+
}
|
|
33
|
+
cachedFullDataBlock;
|
|
34
|
+
cachedPointer;
|
|
35
|
+
constructor(e, t) {
|
|
36
|
+
if (this.memory = e, t && "firstBlock" in t) {
|
|
37
|
+
if (this.firstBlock = new i(e, t.firstBlock), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + c * Uint32Array.BYTES_PER_ELEMENT, 2), "type" in t || "dataLength" in t) {
|
|
38
|
+
let r = t.bufferLength ?? l, i = e.allocUI32(r * (t.dataLength ?? 1));
|
|
39
|
+
n(this.firstBlock.data, a, i.bufferPosition, i.bufferByteOffset), this.bufferLength = r, this.dataLength = t.dataLength ?? 1;
|
|
40
|
+
}
|
|
41
|
+
if ("type" in t) {
|
|
42
|
+
let e = t?.type ?? Uint32Array;
|
|
43
|
+
e === Uint32Array ? this.type = 0 : e === Int32Array ? this.type = 1 : e === Float32Array && (this.type = 2);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
this.firstBlock = e.allocUI32(u.ALLOCATE_COUNT), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + c * Uint32Array.BYTES_PER_ELEMENT, 2);
|
|
47
|
+
let r = t?.dataLength ?? 1, i = t?.bufferLength ?? l, o = e.allocUI32(i * r);
|
|
48
|
+
n(this.firstBlock.data, a, o.bufferPosition, o.bufferByteOffset), this.bufferLength = i;
|
|
49
|
+
let s = t?.type ?? Uint32Array;
|
|
50
|
+
s === Uint32Array ? this.type = 0 : s === Int32Array ? this.type = 1 : s === Float32Array && (this.type = 2), this.dataLength = r;
|
|
51
|
+
}
|
|
52
|
+
this.cachedPointer = this.firstBlock.data[0], this.cachedFullDataBlock = this.getFullDataBlock();
|
|
53
|
+
}
|
|
54
|
+
at(e) {
|
|
55
|
+
let t = this.length;
|
|
56
|
+
if (e >= t || e < 0) throw Error(`${e} is out of bounds ${t}`);
|
|
57
|
+
let n = this.getFullDataBlock();
|
|
58
|
+
return this.getDataBlock(n, e);
|
|
59
|
+
}
|
|
60
|
+
get(e, t = 0) {
|
|
61
|
+
if (t >= this.dataLength) throw Error(`${t} is out of dataLength bounds ${this.dataLength}`);
|
|
62
|
+
if (e >= this.length || e < 0) throw Error(`${e} is out of bounds ${this.length}`);
|
|
63
|
+
return this.getFullDataBlock()[e * this.dataLength + t];
|
|
64
|
+
}
|
|
65
|
+
push(e) {
|
|
66
|
+
let t = this.dataLength, n = typeof e == "number";
|
|
67
|
+
if (!n && e.length > t) throw Error(`Can't insert ${e.length} array into shared list of ${t} dataLength`);
|
|
68
|
+
let r = this.getFullDataBlock(), i = this.length, a = t * i;
|
|
69
|
+
return n ? r[a] = e : r.set(e, a), Atomics.add(this.firstBlock.data, o, 1) + 1 >= this.bufferLength && this.growBuffer(), i;
|
|
70
|
+
}
|
|
71
|
+
pop() {
|
|
72
|
+
let e = Atomics.sub(this.firstBlock.data, o, 1), t = this.getFullDataBlock();
|
|
73
|
+
return this.getDataBlock(t, e - 1);
|
|
74
|
+
}
|
|
75
|
+
popNumber() {
|
|
76
|
+
let e = Atomics.sub(this.firstBlock.data, o, 1);
|
|
77
|
+
return this.getFullDataBlock()[(e - 1) * this.dataLength];
|
|
78
|
+
}
|
|
79
|
+
deleteIndex(e) {
|
|
80
|
+
let t = this.length;
|
|
81
|
+
if (e >= t || e < 0) throw Error(`${e} is out of bounds ${t}`);
|
|
82
|
+
let n = this.dataLength, r = this.getFullDataBlock();
|
|
83
|
+
for (let i = e; i < t; i++) for (let e = 0; e < n; e++) r[i * n + e] = r[(i + 1) * n + e];
|
|
84
|
+
Atomics.sub(this.firstBlock.data, o, 1);
|
|
85
|
+
}
|
|
86
|
+
clear() {
|
|
87
|
+
this.firstBlock.data[o] = 0;
|
|
88
|
+
}
|
|
89
|
+
*[Symbol.iterator]() {
|
|
90
|
+
let e = this.getFullDataBlock(), t = this.dataLength, n = this.length * t;
|
|
91
|
+
for (let r = 0; r < n; r += t) yield e.subarray(r, r + t);
|
|
92
|
+
}
|
|
93
|
+
getCurrentArray() {
|
|
94
|
+
return this.getFullDataBlock().subarray(0, this.length * this.dataLength);
|
|
95
|
+
}
|
|
96
|
+
getFullDataBlock() {
|
|
97
|
+
let t = Atomics.load(this.firstBlock.data, a);
|
|
98
|
+
if (this.cachedPointer === t && this.cachedFullDataBlock) return this.cachedFullDataBlock;
|
|
99
|
+
let n = e(t), r = new i(this.memory, n), o;
|
|
100
|
+
switch (this.type) {
|
|
101
|
+
case 1:
|
|
102
|
+
o = new Int32Array(r.data.buffer, r.bufferByteOffset, this.dataLength * this.bufferLength);
|
|
103
|
+
break;
|
|
104
|
+
case 0:
|
|
105
|
+
o = new Uint32Array(r.data.buffer, r.bufferByteOffset, this.dataLength * this.bufferLength);
|
|
106
|
+
break;
|
|
107
|
+
case 2:
|
|
108
|
+
o = new Float32Array(r.data.buffer, r.bufferByteOffset, this.dataLength * this.bufferLength);
|
|
109
|
+
break;
|
|
110
|
+
default: throw Error(`Unknown data block type ${this.type}`);
|
|
111
|
+
}
|
|
112
|
+
return this.cachedPointer = t, this.cachedFullDataBlock = o, o;
|
|
113
|
+
}
|
|
114
|
+
getDataBlock(e, t) {
|
|
115
|
+
let n = t * this.dataLength;
|
|
116
|
+
return e.subarray(n, n + this.dataLength);
|
|
117
|
+
}
|
|
118
|
+
growBuffer() {
|
|
119
|
+
let e = this.bufferLength * 2, n = this.dataLength, o = t(this.firstBlock.data, a), s = new i(this.memory, o), c = this.getFullDataBlock(), l = this.memory.allocUI32(e * n), u;
|
|
120
|
+
switch (this.type) {
|
|
121
|
+
case 1:
|
|
122
|
+
u = new Int32Array(l.data.buffer, l.bufferByteOffset, n * e);
|
|
123
|
+
break;
|
|
124
|
+
case 0:
|
|
125
|
+
u = new Uint32Array(l.data.buffer, l.bufferByteOffset, n * e);
|
|
126
|
+
break;
|
|
127
|
+
case 2:
|
|
128
|
+
u = new Float32Array(l.data.buffer, l.bufferByteOffset, n * e);
|
|
129
|
+
break;
|
|
130
|
+
default: throw Error(`Unknown data block type ${this.type}`);
|
|
131
|
+
}
|
|
132
|
+
u.set(c);
|
|
133
|
+
let d = l.pointer;
|
|
134
|
+
r(this.firstBlock.data, a, d), this.bufferLength = e, s.free(), this.cachedPointer = d, this.cachedFullDataBlock = u;
|
|
135
|
+
}
|
|
136
|
+
free() {
|
|
137
|
+
let e = t(this.firstBlock.data, a);
|
|
138
|
+
new i(this.memory, e).free(), this.firstBlock.free();
|
|
139
|
+
}
|
|
140
|
+
getSharedMemory() {
|
|
141
|
+
return { firstBlock: this.firstBlock.getSharedMemory() };
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
//#endregion
|
|
145
|
+
export { u as default };
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=shared-vector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-vector.js","names":[],"sources":["../src/shared-vector.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport type { TypedArrayConstructor } from './interfaces/typed-array-constructor';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer, loadPointer, storePointer, storeRawPointer } from './utils/pointer';\n\nenum TYPE {\n\tuint32,\n\tint32,\n\tfloat32,\n}\n\nconst VECTOR_INDEX = 0;\nconst LENGTH_INDEX = 1;\nconst BUFFER_LENGTH_INDEX = 2;\nconst TYPE_INDEX = 3;\nconst DEFAULT_SIZE = 4;\nexport default class SharedVector<T extends Uint32Array | Int32Array | Float32Array = Uint32Array> implements Iterable<T> {\n\tstatic readonly ALLOCATE_COUNT = 4;\n\tprivate memory: MemoryHeap;\n\n\t// Pointer, List Length, Buffer Length, Type/DataLength\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t}\n\t\n\tget type(): number {\n\t\treturn this.uint16Array[0];\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget dataLength(): number {\n\t\t// Can technically be initialized by passing memory without actually every being called - need to make sure dataLength is always at least one\n\t\treturn this.uint16Array[1] || 1;\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tget bufferLength(): number {\n\t\treturn Atomics.load(this.firstBlock.data, BUFFER_LENGTH_INDEX);\n\t}\n\tprivate set bufferLength(value: number) {\n\t\tAtomics.store(this.firstBlock.data, BUFFER_LENGTH_INDEX, value);\n\t}\n\n\tget pointer() {\n\t\treturn this.firstBlock.pointer;\n\t}\n\n\tprivate cachedFullDataBlock?: T;\n\tprivate cachedPointer: number;\n\n\tconstructor(memory: MemoryHeap, config?: SharedVectorConfig<T> | SharedVectorMemory | SharedVectorMemory & SharedVectorConfig<T>) {\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\n\t\t\t// Pre-allocating memory and setting up in specific memory location\n\t\t\tif('type' in config || 'dataLength' in config) {\n\t\t\t\tconst bufferLength = config.bufferLength ?? DEFAULT_SIZE;\n\t\t\t\tlet dataBlock = memory.allocUI32(bufferLength * (config.dataLength ?? 1));\n\t\t\t\tstorePointer(this.firstBlock.data, VECTOR_INDEX, dataBlock.bufferPosition, dataBlock.bufferByteOffset);\n\t\t\t\tthis.bufferLength = bufferLength;\n\t\t\t\tthis.dataLength = (config.dataLength ?? 1);\n\t\t\t}\n\t\t\tif('type' in config) {\n\t\t\t\tconst type = config?.type ?? Uint32Array;\n\t\t\t\tif(type === Uint32Array) {\n\t\t\t\t\tthis.type = TYPE.uint32;\n\t\t\t\t// @ts-expect-error\n\t\t\t\t} else if(type === Int32Array) {\n\t\t\t\t\tthis.type = TYPE.int32;\n\t\t\t\t// @ts-expect-error\n\t\t\t\t} else if(type === Float32Array) {\n\t\t\t\t\tthis.type = TYPE.float32;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.firstBlock = memory.allocUI32(SharedVector.ALLOCATE_COUNT);\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\tlet dataLength = config?.dataLength ?? 1;\n\t\t\tlet bufferLength = config?.bufferLength ?? DEFAULT_SIZE;\n\t\t\tlet dataBlock = memory.allocUI32(bufferLength * dataLength);\n\t\t\tstorePointer(this.firstBlock.data, VECTOR_INDEX, dataBlock.bufferPosition, dataBlock.bufferByteOffset);\n\t\t\tthis.bufferLength = bufferLength;\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}\n\t\t\tthis.dataLength = dataLength;\n\t\t}\n\n\t\tthis.cachedPointer = this.firstBlock.data[0];\n\t\tthis.cachedFullDataBlock = this.getFullDataBlock();\n\t}\n\n\tat(index: number): T {\n\t\tlet length = this.length;\n\t\tif(index >= length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${length}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn this.getDataBlock(dataBlock, index);\n\t}\n\tget(index: number, dataIndex = 0): number {\n\t\tif(dataIndex >= this.dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${this.dataLength}`);\n\t\t} else if(index >= this.length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${this.length}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn dataBlock[index * this.dataLength + dataIndex];\n\t}\n\n\tpush(values: number | Array<number>): number {\n\t\tlet dataLength = this.dataLength;\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\tlet dataBlock = this.getFullDataBlock();\n\t\tlet currentLength = this.length;\n\t\tlet startIndex = dataLength * currentLength;\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\tlet newLength = Atomics.add(this.firstBlock.data, LENGTH_INDEX, 1) + 1;\n\t\tif(newLength >= this.bufferLength) {\n\t\t\tthis.growBuffer();\n\t\t}\n\n\t\treturn currentLength;\n\t}\n\n\tpop(): T {\n\t\tlet oldLength = Atomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn this.getDataBlock(dataBlock, oldLength - 1);\n\t}\n\n\t// Returns the first number irregardless of dataLength - faster way to pop if you don't care about the rest of the data block\n\tpopNumber(): number {\n\t\tconst oldLength = Atomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\tconst dataBlock = this.getFullDataBlock();\n\t\treturn dataBlock[(oldLength - 1) * this.dataLength];\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tlet length = this.length;\n\t\tif(index >= length || index < 0) {\n\t\t\tthrow new Error(`${index} is out of bounds ${length}`);\n\t\t}\n\n\t\tlet dataLength = this.dataLength;\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\tfor(let i = index; i < length; i++) {\n\t\t\tfor(let j = 0; j < dataLength; j++) {\n\t\t\t\tdataBlock[i * dataLength + j] = dataBlock[(i + 1) * dataLength + j];\n\t\t\t}\n\t\t}\n\n\t\tAtomics.sub(this.firstBlock.data, LENGTH_INDEX, 1);\n\t}\n\n\tclear() {\n\t\tthis.firstBlock.data[LENGTH_INDEX] = 0;\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\tlet dataLength = this.dataLength;\n\t\tlet totalDataEntries = this.length * dataLength;\n\n\t\tfor(let i = 0; i < totalDataEntries; i += dataLength) {\n\t\t\tyield dataBlock.subarray(i, i + dataLength) as T;\n\t\t}\n\t}\n\n\t// Significantly faster but won't be thread safe if anything is removing/adding to it during iteration\n\tgetCurrentArray(): T {\n\t\tlet dataBlock = this.getFullDataBlock();\n\t\treturn dataBlock.subarray(0, this.length * this.dataLength) as T;\n\t}\n\n\tprivate getFullDataBlock(): T {\n\t\tlet pointerNumber = Atomics.load(this.firstBlock.data, VECTOR_INDEX);\n\t\tif(this.cachedPointer === pointerNumber && this.cachedFullDataBlock) {\n\t\t\treturn this.cachedFullDataBlock;\n\t\t}\n\n\t\tlet pointer = getPointer(pointerNumber);\n\t\tlet rawData = new AllocatedMemory(this.memory, pointer);\n\n\t\tlet data: T;\n\t\tswitch(this.type) {\n\t\t\tcase TYPE.int32:\n\t\t\t\tdata = new Int32Array(rawData.data.buffer, rawData.bufferByteOffset, this.dataLength * this.bufferLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.uint32:\n\t\t\t\tdata = new Uint32Array(rawData.data.buffer, rawData.bufferByteOffset, this.dataLength * this.bufferLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.float32:\n\t\t\t\tdata = new Float32Array(rawData.data.buffer, rawData.bufferByteOffset, this.dataLength * this.bufferLength) as T;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown data block type ${this.type}`);\n\t\t}\n\n\t\tthis.cachedPointer = pointerNumber;\n\t\tthis.cachedFullDataBlock = data;\n\n\t\treturn data;\n\t}\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\tprivate growBuffer() {\n\t\tlet oldBufferLength = this.bufferLength;\n\t\tlet newBufferLength = oldBufferLength * 2;\n\t\tlet dataLength = this.dataLength;\n\n\t\tlet oldPointer = loadPointer(this.firstBlock.data, VECTOR_INDEX);\n\t\tlet oldDataMemory = new AllocatedMemory(this.memory, oldPointer);\n\t\tlet oldDataBlock = this.getFullDataBlock();\n\t\tlet newDataBlock = this.memory.allocUI32(newBufferLength * dataLength);\n\n\t\tlet newData: T;\n\t\tswitch(this.type) {\n\t\t\tcase TYPE.int32:\n\t\t\t\tnewData = new Int32Array(newDataBlock.data.buffer, newDataBlock.bufferByteOffset, dataLength * newBufferLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.uint32:\n\t\t\t\tnewData = new Uint32Array(newDataBlock.data.buffer, newDataBlock.bufferByteOffset, dataLength * newBufferLength) as T;\n\t\t\t\tbreak;\n\t\t\tcase TYPE.float32:\n\t\t\t\tnewData = new Float32Array(newDataBlock.data.buffer, newDataBlock.bufferByteOffset, dataLength * newBufferLength) as T;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown data block type ${this.type}`);\n\t\t}\n\n\t\t// Copy old buffer into new buffer\n\t\tnewData.set(oldDataBlock);\n\n\t\tconst newPointer = newDataBlock.pointer;\n\t\tstoreRawPointer(this.firstBlock.data, VECTOR_INDEX, newPointer);\n\t\tthis.bufferLength = newBufferLength;\n\t\toldDataMemory.free();\n\n\t\tthis.cachedPointer = newPointer;\n\t\tthis.cachedFullDataBlock = newData;\n\t}\n\n\tfree() {\n\t\tlet pointer = loadPointer(this.firstBlock.data, VECTOR_INDEX);\n\t\tlet dataMemory = new AllocatedMemory(this.memory, pointer);\n\n\t\tdataMemory.free();\n\t\tthis.firstBlock.free();\n\t}\n\n\tgetSharedMemory(): SharedVectorMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedVectorConfig<T extends Uint32Array | Int32Array | Float32Array> {\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n\n\tbufferLength?: number\n}\ninterface SharedVectorMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedVectorConfig, SharedVectorMemory };"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/utils/16-from-32-array.ts
|
|
2
|
+
var e = /* @__PURE__ */ new ArrayBuffer(4), t = new Uint32Array(e), n = new Uint16Array(e);
|
|
3
|
+
function r(e, t) {
|
|
4
|
+
return a(Atomics.load(e, t));
|
|
5
|
+
}
|
|
6
|
+
function i(e, t, n, r) {
|
|
7
|
+
Atomics.store(e, t, o(n, r));
|
|
8
|
+
}
|
|
9
|
+
function a(e) {
|
|
10
|
+
return t[0] = e, [n[0], n[1]];
|
|
11
|
+
}
|
|
12
|
+
function o(e, r) {
|
|
13
|
+
return n[0] = e, n[1] = r, t[0];
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { o as convert16To32, a as convert32To16, r as load16From32, i as store16In32 };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=16-from-32-array.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"16-from-32-array.js","names":[],"sources":["../../src/utils/16-from-32-array.ts"],"sourcesContent":["const buffer = new ArrayBuffer(4);\nconst uint32Array = new Uint32Array(buffer);\nconst uint16Array = new Uint16Array(buffer);\n\nexport function load16From32(data: Uint32Array, index: number): [number, number] {\n\treturn convert32To16(Atomics.load(data, index));\n}\n\nexport function store16In32(data: Uint32Array, index: number, value1: number, value2: number) {\n\tAtomics.store(data, index, convert16To32(value1, value2));\n}\n\nexport function convert32To16(value: number): [number, number] {\n\tuint32Array[0] = value;\n\n\treturn [uint16Array[0], uint16Array[1]];\n}\nexport function convert16To32(value1: number, value2: number): number {\n\tuint16Array[0] = value1;\n\tuint16Array[1] = value2;\n\n\treturn uint32Array[0];\n}"],"mappings":";AAAA,IAAM,oBAAS,IAAI,YAAY,CAAC,GAC1B,IAAc,IAAI,YAAY,CAAM,GACpC,IAAc,IAAI,YAAY,CAAM;AAE1C,SAAgB,EAAa,GAAmB,GAAiC;CAChF,OAAO,EAAc,QAAQ,KAAK,GAAM,CAAK,CAAC;AAC/C;AAEA,SAAgB,EAAY,GAAmB,GAAe,GAAgB,GAAgB;CAC7F,QAAQ,MAAM,GAAM,GAAO,EAAc,GAAQ,CAAM,CAAC;AACzD;AAEA,SAAgB,EAAc,GAAiC;CAG9D,OAFA,EAAY,KAAK,GAEV,CAAC,EAAY,IAAI,EAAY,EAAE;AACvC;AACA,SAAgB,EAAc,GAAgB,GAAwB;CAIrE,OAHA,EAAY,KAAK,GACjB,EAAY,KAAK,GAEV,EAAY;AACpB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/utils/16-from-64-array.ts
|
|
2
|
+
var e = /* @__PURE__ */ new ArrayBuffer(8), t = new BigUint64Array(e), n = new Uint16Array(e);
|
|
3
|
+
function r(e, r) {
|
|
4
|
+
return t[0] = Atomics.load(e, r), [
|
|
5
|
+
n[0],
|
|
6
|
+
n[1],
|
|
7
|
+
n[2],
|
|
8
|
+
n[3]
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
function i(e, r, i, a, o, s = 0) {
|
|
12
|
+
n[0] = i, n[1] = a, n[2] = o, n[3] = s, Atomics.store(e, r, t[0]);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { r as load16From64, i as store16In64 };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=16-from-64-array.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"16-from-64-array.js","names":[],"sources":["../../src/utils/16-from-64-array.ts"],"sourcesContent":["const buffer = new ArrayBuffer(8);\nconst uint64Array = new BigUint64Array(buffer);\nconst uint16Array = new Uint16Array(buffer);\n\nexport function load16From64(data: BigUint64Array, index: number): [number, number, number, number] {\n\tuint64Array[0] = Atomics.load(data, index);\n\t\n\treturn [uint16Array[0], uint16Array[1], uint16Array[2], uint16Array[3]];\n}\n\nexport function store16In64(data: BigUint64Array, index: number, value1: number, value2: number, value3: number, value4: number = 0) {\n\tuint16Array[0] = value1;\n\tuint16Array[1] = value2;\n\tuint16Array[2] = value3;\n\tuint16Array[3] = value4;\n\n\tAtomics.store(data, index, uint64Array[0]);\n}"],"mappings":";AAAA,IAAM,oBAAS,IAAI,YAAY,CAAC,GAC1B,IAAc,IAAI,eAAe,CAAM,GACvC,IAAc,IAAI,YAAY,CAAM;AAE1C,SAAgB,EAAa,GAAsB,GAAiD;CAGnG,OAFA,EAAY,KAAK,QAAQ,KAAK,GAAM,CAAK,GAElC;EAAC,EAAY;EAAI,EAAY;EAAI,EAAY;EAAI,EAAY;CAAE;AACvE;AAEA,SAAgB,EAAY,GAAsB,GAAe,GAAgB,GAAgB,GAAgB,IAAiB,GAAG;CAMpI,AALA,EAAY,KAAK,GACjB,EAAY,KAAK,GACjB,EAAY,KAAK,GACjB,EAAY,KAAK,GAEjB,QAAQ,MAAM,GAAM,GAAO,EAAY,EAAE;AAC1C"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { compareExchangeFloat32 as e, loadFloat32 as t } from "./float32-atomics.js";
|
|
2
|
+
//#region src/utils/atomic-math.ts
|
|
3
|
+
function n(e, t, n, r) {
|
|
4
|
+
let i, a;
|
|
5
|
+
do
|
|
6
|
+
i = Atomics.load(e, t), a = Math.min(i + n, r);
|
|
7
|
+
while (Atomics.compareExchange(e, t, i, a) !== i);
|
|
8
|
+
return a;
|
|
9
|
+
}
|
|
10
|
+
function r(e, t, n, r) {
|
|
11
|
+
let i, a;
|
|
12
|
+
do
|
|
13
|
+
i = Atomics.load(e, t), a = Math.max(i - n, r);
|
|
14
|
+
while (Atomics.compareExchange(e, t, i, a) !== i);
|
|
15
|
+
return a;
|
|
16
|
+
}
|
|
17
|
+
function i(n, r, i, a) {
|
|
18
|
+
let o, s;
|
|
19
|
+
do
|
|
20
|
+
o = t(n, r), s = Math.min(o + i, a);
|
|
21
|
+
while (e(n, r, o, s) !== o);
|
|
22
|
+
return s;
|
|
23
|
+
}
|
|
24
|
+
function a(n, r, i, a) {
|
|
25
|
+
let o, s;
|
|
26
|
+
do
|
|
27
|
+
o = t(n, r), s = Math.max(o - i, a);
|
|
28
|
+
while (e(n, r, o, s) !== o);
|
|
29
|
+
return s;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { i as addAtomicFloat32, n as addAtomicInt, a as subtractAtomicFloat, r as subtractAtomicInt };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=atomic-math.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomic-math.js","names":[],"sources":["../../src/utils/atomic-math.ts"],"sourcesContent":["import { compareExchangeFloat32, loadFloat32 } from './float32-atomics';\n\nexport function addAtomicInt(array: Uint32Array | Int32Array, index: number, amount: number, max: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = Atomics.load(array, index);\n\t\tnewValue = Math.min(oldValue + amount, max);\n\t} while(Atomics.compareExchange(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function subtractAtomicInt(array: Uint32Array | Int32Array, index: number, amount: number, min: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = Atomics.load(array, index);\n\t\tnewValue = Math.max(oldValue - amount, min);\n\t} while(Atomics.compareExchange(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function addAtomicFloat32(array: Float32Array, index: number, amount: number, max: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = loadFloat32(array, index);\n\t\tnewValue = Math.min(oldValue + amount, max);\n\t} while(compareExchangeFloat32(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}\n\nexport function subtractAtomicFloat(array: Float32Array, index: number, amount: number, min: number) {\n\tlet oldValue;\n\tlet newValue;\n\tdo {\n\t\toldValue = loadFloat32(array, index);\n\t\tnewValue = Math.max(oldValue - amount, min);\n\t} while(compareExchangeFloat32(array, index, oldValue, newValue) !== oldValue);\n\n\treturn newValue;\n}"],"mappings":";;AAEA,SAAgB,EAAa,GAAiC,GAAe,GAAgB,GAAa;CACzG,IAAI,GACA;CACJ;EAEC,AADA,IAAW,QAAQ,KAAK,GAAO,CAAK,GACpC,IAAW,KAAK,IAAI,IAAW,GAAQ,CAAG;QACnC,QAAQ,gBAAgB,GAAO,GAAO,GAAU,CAAQ,MAAM;CAEtE,OAAO;AACR;AAEA,SAAgB,EAAkB,GAAiC,GAAe,GAAgB,GAAa;CAC9G,IAAI,GACA;CACJ;EAEC,AADA,IAAW,QAAQ,KAAK,GAAO,CAAK,GACpC,IAAW,KAAK,IAAI,IAAW,GAAQ,CAAG;QACnC,QAAQ,gBAAgB,GAAO,GAAO,GAAU,CAAQ,MAAM;CAEtE,OAAO;AACR;AAEA,SAAgB,EAAiB,GAAqB,GAAe,GAAgB,GAAa;CACjG,IAAI,GACA;CACJ;EAEC,AADA,IAAW,EAAY,GAAO,CAAK,GACnC,IAAW,KAAK,IAAI,IAAW,GAAQ,CAAG;QACnC,EAAuB,GAAO,GAAO,GAAU,CAAQ,MAAM;CAErE,OAAO;AACR;AAEA,SAAgB,EAAoB,GAAqB,GAAe,GAAgB,GAAa;CACpG,IAAI,GACA;CACJ;EAEC,AADA,IAAW,EAAY,GAAO,CAAK,GACnC,IAAW,KAAK,IAAI,IAAW,GAAQ,CAAG;QACnC,EAAuB,GAAO,GAAO,GAAU,CAAQ,MAAM;CAErE,OAAO;AACR"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/utils/float32-atomics.ts
|
|
2
|
+
var e = /* @__PURE__ */ new ArrayBuffer(4), t = new Float32Array(e), n = new Int32Array(e);
|
|
3
|
+
function r(e, t) {
|
|
4
|
+
return e instanceof Float32Array && (e = new Int32Array(e.buffer, e.byteOffset, e.length)), a(Atomics.load(e, t));
|
|
5
|
+
}
|
|
6
|
+
function i(e, t, n) {
|
|
7
|
+
e instanceof Float32Array && (e = new Int32Array(e.buffer, e.byteOffset, e.length)), Atomics.store(e, t, o(n));
|
|
8
|
+
}
|
|
9
|
+
function a(e) {
|
|
10
|
+
return n[0] = e, t[0];
|
|
11
|
+
}
|
|
12
|
+
function o(e) {
|
|
13
|
+
return t[0] = e, n[0];
|
|
14
|
+
}
|
|
15
|
+
function s(e, t, n) {
|
|
16
|
+
return e instanceof Float32Array && (e = new Int32Array(e.buffer, e.byteOffset, e.length)), a(Atomics.exchange(e, t, o(n)));
|
|
17
|
+
}
|
|
18
|
+
function c(e, t, n, r) {
|
|
19
|
+
return e instanceof Float32Array && (e = new Int32Array(e.buffer, e.byteOffset, e.length)), a(Atomics.compareExchange(e, t, o(n), o(r)));
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { c as compareExchangeFloat32, o as convertFloat32ToInt32, a as convertInt32ToFloat32, s as exchangeFloat32, r as loadFloat32, i as storeFloat32 };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=float32-atomics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"float32-atomics.js","names":[],"sources":["../../src/utils/float32-atomics.ts"],"sourcesContent":["// For doing Atomic operations on floats in SharedArrayBuffers\nconst buffer = new ArrayBuffer(4);\nconst float32 = new Float32Array(buffer);\nconst int32 = new Int32Array(buffer);\n\nexport function loadFloat32(data: Int32Array | Uint32Array | Float32Array, index: number) {\n\tif(data instanceof Float32Array) {\n\t\tdata = new Int32Array(data.buffer, data.byteOffset, data.length);\n\t}\n\n\treturn convertInt32ToFloat32(Atomics.load(data, index));\n}\nexport function storeFloat32(data: Int32Array | Uint32Array | Float32Array, index: number, value: number) {\n\tif(data instanceof Float32Array) {\n\t\tdata = new Int32Array(data.buffer, data.byteOffset, data.length);\n\t}\n\n\tAtomics.store(data, index, convertFloat32ToInt32(value));\n}\n\nexport function convertInt32ToFloat32(value: number) {\n\tint32[0] = value;\n\n\treturn float32[0];\n}\nexport function convertFloat32ToInt32(value: number) {\n\tfloat32[0] = value;\n\n\treturn int32[0];\n}\n\nexport function exchangeFloat32(data: Int32Array | Uint32Array | Float32Array, index: number, value: number) {\n\tif(data instanceof Float32Array) {\n\t\tdata = new Int32Array(data.buffer, data.byteOffset, data.length);\n\t}\n\n\treturn convertInt32ToFloat32(Atomics.exchange(data, index, convertFloat32ToInt32(value)));\n}\n\nexport function compareExchangeFloat32(data: Int32Array | Uint32Array | Float32Array, index: number, expectedValue: number, replacementValue: number) {\n\tif(data instanceof Float32Array) {\n\t\tdata = new Int32Array(data.buffer, data.byteOffset, data.length);\n\t}\n\n\treturn convertInt32ToFloat32(Atomics.compareExchange(data, index, convertFloat32ToInt32(expectedValue), convertFloat32ToInt32(replacementValue)));\n}"],"mappings":";AACA,IAAM,oBAAS,IAAI,YAAY,CAAC,GAC1B,IAAU,IAAI,aAAa,CAAM,GACjC,IAAQ,IAAI,WAAW,CAAM;AAEnC,SAAgB,EAAY,GAA+C,GAAe;CAKzF,OAJG,aAAgB,iBAClB,IAAO,IAAI,WAAW,EAAK,QAAQ,EAAK,YAAY,EAAK,MAAM,IAGzD,EAAsB,QAAQ,KAAK,GAAM,CAAK,CAAC;AACvD;AACA,SAAgB,EAAa,GAA+C,GAAe,GAAe;CAKzG,AAJG,aAAgB,iBAClB,IAAO,IAAI,WAAW,EAAK,QAAQ,EAAK,YAAY,EAAK,MAAM,IAGhE,QAAQ,MAAM,GAAM,GAAO,EAAsB,CAAK,CAAC;AACxD;AAEA,SAAgB,EAAsB,GAAe;CAGpD,OAFA,EAAM,KAAK,GAEJ,EAAQ;AAChB;AACA,SAAgB,EAAsB,GAAe;CAGpD,OAFA,EAAQ,KAAK,GAEN,EAAM;AACd;AAEA,SAAgB,EAAgB,GAA+C,GAAe,GAAe;CAK5G,OAJG,aAAgB,iBAClB,IAAO,IAAI,WAAW,EAAK,QAAQ,EAAK,YAAY,EAAK,MAAM,IAGzD,EAAsB,QAAQ,SAAS,GAAM,GAAO,EAAsB,CAAK,CAAC,CAAC;AACzF;AAEA,SAAgB,EAAuB,GAA+C,GAAe,GAAuB,GAA0B;CAKrJ,OAJG,aAAgB,iBAClB,IAAO,IAAI,WAAW,EAAK,QAAQ,EAAK,YAAY,EAAK,MAAM,IAGzD,EAAsB,QAAQ,gBAAgB,GAAM,GAAO,EAAsB,CAAa,GAAG,EAAsB,CAAgB,CAAC,CAAC;AACjJ"}
|