@daneren2005/shared-memory-objects 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,25 +1,40 @@
1
1
  import { type SharedAllocatedMemory } from './allocated-memory';
2
2
  import type MemoryHeap from './memory-heap';
3
- export default class SharedMap<K extends string | number> {
4
- static readonly ALLOCATE_COUNT = 4;
3
+ import { type NumericArray, type TypedArrayConstructor } from './utils/array-type';
4
+ export default class SharedMap<K extends string | number, V extends NumericArray = Uint32Array> {
5
+ static readonly ALLOCATE_COUNT = 6;
5
6
  private memory;
6
7
  private pointerMemory;
7
8
  private lock;
8
- private get hashMemory();
9
+ private cachedType;
10
+ private cachedValueUnits;
11
+ private cachedTablePointer;
12
+ private cachedTableMemory?;
13
+ private cachedSlots?;
14
+ private cachedValues?;
15
+ private cachedCapacity;
16
+ private ensureTable;
17
+ private makeValuesView;
18
+ private tableLength;
9
19
  get length(): number;
20
+ get capacity(): number;
10
21
  get maxHash(): number;
11
- constructor(memory: MemoryHeap, clone?: SharedMapMemory);
12
- set(key: K, value: number): void;
13
- private setHashKey;
14
- get(key: K): number | undefined;
22
+ get type(): number;
23
+ constructor(memory: MemoryHeap, config?: SharedMapConfig<V> | SharedMapMemory);
24
+ set(key: K, value: V[number]): void;
25
+ update(key: K, updater: (current: V[number] | undefined) => V[number]): V[number];
26
+ get(key: K): V[number] | undefined;
15
27
  has(key: K): boolean;
16
28
  delete(key: K): boolean;
17
- private growHashTable;
18
- private hash;
29
+ [Symbol.iterator](): IterableIterator<[number, V[number]]>;
30
+ private resize;
19
31
  free(): void;
20
32
  getSharedMemory(): SharedMapMemory;
21
33
  }
34
+ interface SharedMapConfig<V extends NumericArray> {
35
+ type?: TypedArrayConstructor<V>;
36
+ }
22
37
  interface SharedMapMemory {
23
38
  firstBlock: SharedAllocatedMemory;
24
39
  }
25
- export type { SharedMapMemory };
40
+ export type { SharedMapConfig, SharedMapMemory };
@@ -1,107 +1,167 @@
1
- import { loadPointer as e, storePointer as t } from "./utils/pointer.js";
1
+ import { getPointer as e, storeRawPointer as t } from "./utils/pointer.js";
2
2
  import n from "./allocated-memory.js";
3
- import r from "./shared-list.js";
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";
5
+ import { get32BitHash as c, mix32 as l } from "./utils/hash.js";
4
6
  //#region src/shared-map.ts
5
- var i = 10, a = class a {
6
- static ALLOCATE_COUNT = 4;
7
+ var u = 0, d = 1, f = 2, p = 16, m = 3, h = 4, g = 0, _ = 1, v = 2, y = 3, b = 4, x = 5, S = class S {
8
+ static ALLOCATE_COUNT = 6;
7
9
  memory;
8
10
  pointerMemory;
9
11
  lock;
10
- get hashMemory() {
11
- return new n(this.memory, e(this.pointerMemory.data, 0));
12
+ cachedType;
13
+ cachedValueUnits = 1;
14
+ cachedTablePointer = 0;
15
+ cachedTableMemory;
16
+ cachedSlots;
17
+ cachedValues;
18
+ cachedCapacity = 0;
19
+ ensureTable() {
20
+ let t = this.pointerMemory.data, r = t[g], i = t[b];
21
+ if (r === this.cachedTablePointer && i === this.cachedCapacity && this.cachedSlots) return;
22
+ let a = new n(this.memory, e(r));
23
+ this.cachedTableMemory = a, this.cachedSlots = a.data, this.cachedValues = this.makeValuesView(a, i), this.cachedCapacity = i, this.cachedTablePointer = r;
24
+ }
25
+ makeValuesView(e, t) {
26
+ let n = e.bufferByteOffset + t * 2 * Uint32Array.BYTES_PER_ELEMENT;
27
+ return a(this.cachedType, e.data.buffer, n, t);
28
+ }
29
+ tableLength(e) {
30
+ return e * (2 + this.cachedValueUnits);
12
31
  }
13
32
  get length() {
14
- return Atomics.load(this.pointerMemory.data, 2);
33
+ return Atomics.load(this.pointerMemory.data, v);
34
+ }
35
+ get capacity() {
36
+ return Atomics.load(this.pointerMemory.data, b);
15
37
  }
16
38
  get maxHash() {
17
- return Atomics.load(this.pointerMemory.data, 3);
39
+ return this.capacity;
40
+ }
41
+ get type() {
42
+ return this.cachedType;
18
43
  }
19
- constructor(e, r) {
20
- if (this.memory = e, r) this.pointerMemory = new n(e, r.firstBlock);
44
+ constructor(e, a) {
45
+ if (this.memory = e, a && "firstBlock" in a) this.pointerMemory = new n(e, a.firstBlock);
21
46
  else {
22
- this.pointerMemory = e.allocUI32(a.ALLOCATE_COUNT);
23
- let n = e.allocUI32(i);
24
- t(this.pointerMemory.data, 0, n.bufferPosition, n.bufferByteOffset), Atomics.store(this.pointerMemory.data, 3, i);
47
+ this.pointerMemory = e.allocUI32(S.ALLOCATE_COUNT);
48
+ let n = r(a?.type ?? Uint32Array);
49
+ this.cachedValueUnits = i(n);
50
+ let o = e.allocUI32(p * (2 + this.cachedValueUnits));
51
+ t(this.pointerMemory.data, g, o.pointer), Atomics.store(this.pointerMemory.data, b, p), Atomics.store(this.pointerMemory.data, x, n);
25
52
  }
26
- this.lock = new Int32Array(this.pointerMemory.data.buffer, this.pointerMemory.bufferByteOffset + Uint32Array.BYTES_PER_ELEMENT, 1);
53
+ this.lock = new Int32Array(this.pointerMemory.data.buffer, this.pointerMemory.bufferByteOffset + _ * Uint32Array.BYTES_PER_ELEMENT, 1), this.cachedType = Atomics.load(this.pointerMemory.data, x), this.cachedValueUnits = i(this.cachedType);
27
54
  }
28
55
  set(e, t) {
29
- this.length >= this.maxHash * 2 && this.growHashTable();
30
- let n = o(e);
31
- this.setHashKey(this.hashMemory, this.maxHash, n, t) && Atomics.add(this.pointerMemory.data, 2, 1);
32
- }
33
- setHashKey(n, i, a, o) {
34
- let s = this.hash(a, i), c, l = e(n.data, s);
35
- if (l.bufferByteOffset === 0) {
36
- c = new r(this.memory, { dataLength: 2 });
37
- let e = c.getSharedMemory();
38
- t(n.data, s, e.firstBlock.bufferPosition, e.firstBlock.bufferByteOffset);
39
- } else c = new r(this.memory, { firstBlock: l });
40
- let u = !0;
41
- return c.deleteValue(a) && (u = !1), c.insert([a, o]), u || c.compact(), u;
42
- }
43
- get(t) {
44
- let n = o(t), i = this.hash(n, this.maxHash), a = e(this.hashMemory.data, i);
45
- if (a.bufferByteOffset === 0) return;
46
- let s = new r(this.memory, { firstBlock: a });
47
- for (let { data: e } of s) if (e[0] === n) return e[1];
48
- }
49
- has(t) {
50
- let n = o(t), i = this.hash(n, this.maxHash), a = e(this.hashMemory.data, i);
51
- if (a.bufferByteOffset === 0) return !1;
52
- let s = new r(this.memory, { firstBlock: a });
53
- for (let { data: e } of s) if (e[0] === n) return !0;
54
- return !1;
55
- }
56
- delete(t) {
57
- let n = o(t), i = this.hash(n, this.maxHash), a = e(this.hashMemory.data, i);
58
- if (a.bufferByteOffset === 0) return !1;
59
- let s = new r(this.memory, { firstBlock: a }), c = !1;
60
- for (let { data: e, deleteCurrent: t } of s) if (e[0] === n) {
61
- t(), Atomics.sub(this.pointerMemory.data, 2, 1), c = !0;
62
- break;
56
+ let n = c(e);
57
+ o(this.lock);
58
+ try {
59
+ let e = this.pointerMemory.data;
60
+ (e[v] + e[y] + 1) * h > e[b] * m && this.resize(), this.ensureTable();
61
+ let r = this.cachedSlots, i = this.cachedValues, a = this.cachedCapacity, o = a - 1, s = a, c = l(n) & o, p = -1;
62
+ for (;;) {
63
+ let a = r[c];
64
+ if (a === u) {
65
+ let a = p >= 0 ? p : c;
66
+ r[a] = d, r[s + a] = n, i[a] = t, e[v]++, p >= 0 && e[y]--;
67
+ return;
68
+ }
69
+ if (a === f) p < 0 && (p = c);
70
+ else if (r[s + c] === n) {
71
+ i[c] = t;
72
+ return;
73
+ }
74
+ c = c + 1 & o;
75
+ }
76
+ } finally {
77
+ s(this.lock);
63
78
  }
64
- return c && s.compact(), c;
65
- }
66
- growHashTable() {
67
- let n = this.maxHash, i = n * 2, a = this.memory.allocUI32(i), o = this.hashMemory;
68
- for (let t = 0; t < n; t++) {
69
- let n = e(o.data, t);
70
- if (n.bufferByteOffset === 0) continue;
71
- let s = new r(this.memory, { firstBlock: n });
72
- for (let { data: e } of s) this.setHashKey(a, i, e[0], e[1]);
73
- s.free();
79
+ }
80
+ update(e, t) {
81
+ let n = c(e);
82
+ o(this.lock);
83
+ try {
84
+ let e = this.pointerMemory.data;
85
+ (e[v] + e[y] + 1) * h > e[b] * m && this.resize(), this.ensureTable();
86
+ let r = this.cachedSlots, i = this.cachedValues, a = this.cachedCapacity, o = a - 1, s = a, c = l(n) & o, p = -1;
87
+ for (;;) {
88
+ let a = r[c];
89
+ if (a === u) {
90
+ let a = t(void 0), o = p >= 0 ? p : c;
91
+ return r[o] = d, r[s + o] = n, i[o] = a, e[v]++, p >= 0 && e[y]--, a;
92
+ }
93
+ if (a === f) p < 0 && (p = c);
94
+ else if (r[s + c] === n) {
95
+ let e = t(i[c]);
96
+ return i[c] = e, e;
97
+ }
98
+ c = c + 1 & o;
99
+ }
100
+ } finally {
101
+ s(this.lock);
74
102
  }
75
- t(this.pointerMemory.data, 0, a.bufferPosition, a.bufferByteOffset), Atomics.store(this.pointerMemory.data, 3, i), o.free();
76
103
  }
77
- hash(e, t) {
78
- return e % t;
104
+ get(e) {
105
+ let t = c(e);
106
+ o(this.lock);
107
+ try {
108
+ this.ensureTable();
109
+ let e = this.cachedSlots, n = this.cachedValues, r = this.cachedCapacity, i = r - 1, a = r, o = l(t) & i;
110
+ for (;;) {
111
+ let r = e[o];
112
+ if (r === u) return;
113
+ if (r === d && e[a + o] === t) return n[o];
114
+ o = o + 1 & i;
115
+ }
116
+ } finally {
117
+ s(this.lock);
118
+ }
79
119
  }
80
- free() {
81
- for (let t = 0; t < this.maxHash; t++) {
82
- let n = e(this.hashMemory.data, t);
83
- n.bufferByteOffset !== 0 && new r(this.memory, { firstBlock: n }).free();
120
+ has(e) {
121
+ return this.get(e) !== void 0;
122
+ }
123
+ delete(e) {
124
+ let t = c(e);
125
+ o(this.lock);
126
+ try {
127
+ this.ensureTable();
128
+ let e = this.pointerMemory.data, n = this.cachedSlots, r = this.cachedCapacity, i = r - 1, a = r, o = l(t) & i;
129
+ for (;;) {
130
+ let r = n[o];
131
+ if (r === u) return !1;
132
+ if (r === d && n[a + o] === t) return n[o] = f, e[v]--, e[y]++, !0;
133
+ o = o + 1 & i;
134
+ }
135
+ } finally {
136
+ s(this.lock);
137
+ }
138
+ }
139
+ *[Symbol.iterator]() {
140
+ this.ensureTable();
141
+ let e = this.cachedSlots, t = this.cachedValues, n = this.cachedCapacity, r = n;
142
+ for (let i = 0; i < n; i++) e[i] === d && (yield [e[r + i], t[i]]);
143
+ }
144
+ resize() {
145
+ this.ensureTable();
146
+ let e = this.cachedTableMemory, n = this.cachedSlots, r = this.cachedValues, i = this.cachedCapacity, a = i, o = Atomics.load(this.pointerMemory.data, v), s = i;
147
+ (o + 1) * h > i * m && (s = i * 2);
148
+ let c = this.memory.allocUI32(this.tableLength(s)), f = c.data, p = this.makeValuesView(c, s), _ = s - 1, x = s;
149
+ for (let e = 0; e < i; e++) {
150
+ if (n[e] !== d) continue;
151
+ let t = n[a + e], i = r[e], o = l(t) & _;
152
+ for (; f[o] !== u;) o = o + 1 & _;
153
+ f[o] = d, f[x + o] = t, p[o] = i;
84
154
  }
85
- this.hashMemory.free(), this.pointerMemory.free();
155
+ t(this.pointerMemory.data, g, c.pointer), Atomics.store(this.pointerMemory.data, b, s), Atomics.store(this.pointerMemory.data, y, 0), this.cachedTablePointer = 0, this.cachedSlots = void 0, e.free();
156
+ }
157
+ free() {
158
+ this.ensureTable(), this.cachedTableMemory.free(), this.pointerMemory.free();
86
159
  }
87
160
  getSharedMemory() {
88
161
  return { firstBlock: this.pointerMemory.getSharedMemory() };
89
162
  }
90
163
  };
91
- function o(e) {
92
- return typeof e == "number" ? e : typeof e == "string" ? s(e) : e;
93
- }
94
- function s(e) {
95
- let t = e.length, n = 17 ^ t, r = 0, i;
96
- for (; t >= 4;) i = e.charCodeAt(r) & 255 | (e.charCodeAt(++r) & 255) << 8 | (e.charCodeAt(++r) & 255) << 16 | (e.charCodeAt(++r) & 255) << 14, i = (i & 65535) * 1540483477 + (((i >>> 16) * 1540483477 & 65535) << 16), i ^= i >>> 14, i = (i & 65535) * 1540483477 + (((i >>> 16) * 1540483477 & 65535) << 16), n = (n & 65535) * 1540483477 + (((n >>> 16) * 1540483477 & 65535) << 16) ^ i, t -= 4, ++r;
97
- switch (t) {
98
- case 3: n ^= (e.charCodeAt(r + 2) & 255) << 16;
99
- case 2: n ^= (e.charCodeAt(r + 1) & 255) << 8;
100
- case 1: n ^= e.charCodeAt(r) & 255, n = (n & 65535) * 1540483477 + (((n >>> 16) * 1540483477 & 65535) << 16);
101
- }
102
- return n ^= n >>> 13, n = (n & 65535) * 1540483477 + (((n >>> 16) * 1540483477 & 65535) << 16), n ^= n >>> 15, n >>>= 0, n;
103
- }
104
164
  //#endregion
105
- export { a as default };
165
+ export { S as default };
106
166
 
107
167
  //# sourceMappingURL=shared-map.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-map.js","names":[],"sources":["../src/shared-map.ts"],"sourcesContent":["import AllocatedMemory, { type SharedAllocatedMemory } from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport SharedList from './shared-list';\nimport { loadPointer, storePointer } from './utils/pointer';\n\n// TODO: Grow hashMemory\n// TODO: Add iterator\n// TODO: Add read/write locks\nconst DEFAULT_HASH_SIZE = 10;\nexport default class SharedMap<K extends string | number> {\n\tstatic readonly ALLOCATE_COUNT = 4;\n\n\tprivate memory: MemoryHeap;\n\t// Memory order: Pointer, Lock, Length, MaxHash\n\tprivate pointerMemory: AllocatedMemory;\n\tprivate lock: Int32Array;\n\tprivate get hashMemory(): AllocatedMemory {\n\t\treturn new AllocatedMemory(this.memory, loadPointer(this.pointerMemory.data, 0));\n\t}\n\n\tget length(): number {\n\t\treturn Atomics.load(this.pointerMemory.data, 2);\n\t}\n\tget maxHash(): number {\n\t\treturn Atomics.load(this.pointerMemory.data, 3);\n\t}\n\n\tconstructor(memory: MemoryHeap, clone?: SharedMapMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(clone) {\n\t\t\tthis.pointerMemory = new AllocatedMemory(memory, clone.firstBlock);\n\t\t} else {\n\t\t\tthis.pointerMemory = memory.allocUI32(SharedMap.ALLOCATE_COUNT);\n\t\t\tlet hashMemory = memory.allocUI32(DEFAULT_HASH_SIZE);\n\t\t\tstorePointer(this.pointerMemory.data, 0, hashMemory.bufferPosition, hashMemory.bufferByteOffset);\n\t\t\tAtomics.store(this.pointerMemory.data, 3, DEFAULT_HASH_SIZE);\n\t\t}\n\t\tthis.lock = new Int32Array(this.pointerMemory.data.buffer, this.pointerMemory.bufferByteOffset + Uint32Array.BYTES_PER_ELEMENT, 1);\n\t}\n\n\tset(key: K, value: number) {\n\t\tif(this.length >= this.maxHash * 2) {\n\t\t\tthis.growHashTable();\n\t\t}\n\n\t\tlet fullHashKey = get32BitHash(key);\n\t\tif(this.setHashKey(this.hashMemory, this.maxHash, fullHashKey, value)) {\n\t\t\tAtomics.add(this.pointerMemory.data, 2, 1);\n\t\t}\n\t}\n\tprivate setHashKey(hashMemory: AllocatedMemory, maxHash: number, fullHashKey: number, value: number) {\n\t\tlet hashKey = this.hash(fullHashKey, maxHash);\n\t\t\n\t\tlet list: SharedList;\n\t\tlet pointer = loadPointer(hashMemory.data, hashKey);\n\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\t// Initialize a list here\n\t\t\tlist = new SharedList(this.memory, {\n\t\t\t\tdataLength: 2,\n\t\t\t});\n\n\t\t\tlet listMemory = list.getSharedMemory();\n\t\t\tstorePointer(hashMemory.data, hashKey, listMemory.firstBlock.bufferPosition, listMemory.firstBlock.bufferByteOffset);\n\t\t} else {\n\t\t\tlist = new SharedList(this.memory, {\n\t\t\t\tfirstBlock: pointer,\n\t\t\t});\n\t\t}\n\n\t\t// Check if any other items in list have the same key and delete them\n\t\tlet inserted = true;\n\t\tif(list.deleteValue(fullHashKey)) {\n\t\t\tinserted = false;\n\t\t}\n\t\tlist.insert([fullHashKey, value]);\n\t\t// An overwrite leaves a tombstone behind - reclaim it so buckets don't grow on repeated updates\n\t\tif(!inserted) {\n\t\t\tlist.compact();\n\t\t}\n\n\t\treturn inserted;\n\t}\n\n\tget(key: K): number | undefined {\n\t\tlet fullHashKey = get32BitHash(key);\n\t\tlet hashKey = this.hash(fullHashKey, this.maxHash);\n\n\t\tlet pointer = loadPointer(this.hashMemory.data, hashKey);\n\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tlet list = new SharedList(this.memory, {\n\t\t\tfirstBlock: pointer,\n\t\t});\n\n\t\tfor(let { data } of list) {\n\t\t\tif(data[0] === fullHashKey) {\n\t\t\t\treturn data[1];\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\thas(key: K): boolean {\n\t\tlet fullHashKey = get32BitHash(key);\n\t\tlet hashKey = this.hash(fullHashKey, this.maxHash);\n\n\t\tlet pointer = loadPointer(this.hashMemory.data, hashKey);\n\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet list = new SharedList(this.memory, {\n\t\t\tfirstBlock: pointer,\n\t\t});\n\n\t\tfor(let { data } of list) {\n\t\t\tif(data[0] === fullHashKey) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tdelete(key: K): boolean {\n\t\tlet fullHashKey = get32BitHash(key);\n\t\tlet hashKey = this.hash(fullHashKey, this.maxHash);\n\n\t\tlet pointer = loadPointer(this.hashMemory.data, hashKey);\n\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet list = new SharedList(this.memory, {\n\t\t\tfirstBlock: pointer,\n\t\t});\n\n\t\tlet deleted = false;\n\t\tfor(let { data, deleteCurrent } of list) {\n\t\t\tif(data[0] === fullHashKey) {\n\t\t\t\tdeleteCurrent();\n\n\t\t\t\tAtomics.sub(this.pointerMemory.data, 2, 1);\n\t\t\t\tdeleted = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// compact only after iteration finishes - unlinking/freeing mid-iteration would corrupt the walk\n\t\tif(deleted) {\n\t\t\tlist.compact();\n\t\t}\n\n\t\treturn deleted;\n\t}\n\n\tprivate growHashTable() {\n\t\tlet oldMaxHash = this.maxHash;\n\t\tlet newMaxHash = oldMaxHash * 2;\n\t\tlet newHashMemory = this.memory.allocUI32(newMaxHash);\n\t\tlet oldHashMemory = this.hashMemory;\n\n\t\t// Copy each old hash value into new hash memory\n\t\tfor(let i = 0; i < oldMaxHash; i++) {\n\t\t\tlet pointer = loadPointer(oldHashMemory.data, i);\n\t\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet list = new SharedList(this.memory, {\n\t\t\t\tfirstBlock: pointer,\n\t\t\t});\n\t\t\tfor(let { data } of list) {\n\t\t\t\tthis.setHashKey(newHashMemory, newMaxHash, data[0], data[1]);\n\t\t\t}\n\n\t\t\t// The entries have been copied into freshly allocated lists in the new hash table so the old list can be freed\n\t\t\tlist.free();\n\t\t}\n\n\t\tstorePointer(this.pointerMemory.data, 0, newHashMemory.bufferPosition, newHashMemory.bufferByteOffset);\n\t\tAtomics.store(this.pointerMemory.data, 3, newMaxHash);\n\n\t\t// pointerMemory now references newHashMemory so the old hash table memory can be freed\n\t\toldHashMemory.free();\n\t}\n\n\tprivate hash(key: number, maxHash: number) {\n\t\treturn key % maxHash;\n\t}\n\n\tfree() {\n\t\t// Loop through and free lists in hash table first\n\t\tfor(let i = 0; i < this.maxHash; i++) {\n\t\t\tlet pointer = loadPointer(this.hashMemory.data, i);\n\t\t\tif(pointer.bufferByteOffset === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet list = new SharedList(this.memory, {\n\t\t\t\tfirstBlock: pointer,\n\t\t\t});\n\t\t\tlist.free();\n\t\t}\n\n\t\tthis.hashMemory.free();\n\t\tthis.pointerMemory.free();\n\t}\n\n\tgetSharedMemory(): SharedMapMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.pointerMemory.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedMapMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nfunction get32BitHash<K extends string | number>(key: K): number {\n\tif(typeof key === 'number') {\n\t\treturn key;\n\t} else if(typeof key === 'string') {\n\t\treturn hashString(key);\n\t} else {\n\t\treturn key;\n\t}\n}\n\n// Copied from https://github.com/mmomtchev/SharedMap/blob/master/index.js - MurmurHash2\nfunction hashString(str: string): number {\n\tlet\n\t\tl = str.length,\n\t\th = 17 ^ l,\n\t\ti = 0,\n\t\tk;\n\twhile(l >= 4) {\n\t\tk =\n\t\t\t((str.charCodeAt(i) & 0xff)) |\n\t\t\t((str.charCodeAt(++i) & 0xff) << 8) |\n\t\t\t((str.charCodeAt(++i) & 0xff) << 16) |\n\t\t\t((str.charCodeAt(++i) & 0xff) << 14);\n\t\tk = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\t\tk ^= k >>> 14;\n\t\tk = (((k & 0xffff) * 0x5bd1e995) + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\t\th = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ k;\n\t\tl -= 4;\n\t\t++i;\n\t}\n\t/* eslint-disable no-fallthrough */\n\tswitch(l) {\n\t\tcase 3: h ^= (str.charCodeAt(i + 2) & 0xff) << 16;\n\t\tcase 2: h ^= (str.charCodeAt(i + 1) & 0xff) << 8;\n\t\tcase 1: h ^= (str.charCodeAt(i) & 0xff);\n\t\t\th = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\t}\n\t/* eslint-enable no-fallthrough */\n\th ^= h >>> 13;\n\th = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));\n\th ^= h >>> 15;\n\th = h >>> 0;\n\treturn h;\n}\n\nexport type { SharedMapMemory };"],"mappings":"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"}
1
+ {"version":3,"file":"shared-map.js","names":[],"sources":["../src/shared-map.ts"],"sourcesContent":["import AllocatedMemory, { type SharedAllocatedMemory } from './allocated-memory';\nimport type MemoryHeap from './memory-heap';\nimport { getPointer, storeRawPointer } from './utils/pointer';\nimport { get32BitHash, mix32 } from './utils/hash';\nimport { lock, unlock, SIMPLE_LOCK_ALLOCATE_COUNT } from './lock/simple-lock';\nimport { getArrayTypeCode, getByteMultipler, makeArrayView, type NumericArray, type NumericArrayIO, type TypedArrayConstructor } from './utils/array-type';\n\n// Open-addressing hash map with linear probing, held in one contiguous table (no per-bucket lists, no per-operation\n// allocation). A single exclusive lock guards the table so slot reads/writes inside the critical section can be plain\n// memory access instead of per-slot Atomics; the lock's acquire/release provides the cross-thread happens-before.\n//\n// The table uses a Structure-of-Arrays layout: three contiguous regions - states | keys | values - so probing touches\n// the dense states and keys regions (more candidates per cache line) and iteration walks values densely. capacity is\n// always a power of two, so slot = mix(key) & (capacity - 1). state distinguishes EMPTY/FULL/TOMBSTONE, so key 0 and\n// value 0 need no sentinel.\n//\n// Keys are always stored as the 32-bit hash (a numeric key is its own hash); values are stored in the typed array the\n// map was created with (Uint32Array by default, or Int32Array / Float32Array). Iteration is a best-effort scan that is\n// not lock-guarded, so it must not run concurrently with mutation from another thread. A single allocation can't span\n// buffers, so the table is bounded by MemoryHeap.maxAllocationLength.\n\nconst EMPTY = 0;\nconst FULL = 1;\nconst TOMBSTONE = 2;\n\nconst DEFAULT_CAPACITY = 16;\n// Grow when (occupied + tombstones) / capacity exceeds this. Kept as a fraction to avoid floating point in the hot path.\nconst LOAD_NUMERATOR = 3;\nconst LOAD_DENOMINATOR = 4;\n\n// Metadata block layout (pointerMemory)\nconst TABLE_POINTER_INDEX = 0;\nconst LOCK_INDEX = 1;\nconst LENGTH_INDEX = 2;\nconst TOMBSTONE_INDEX = 3;\nconst CAPACITY_INDEX = 4;\nconst TYPE_INDEX = 5;\n\nexport default class SharedMap<K extends string | number, V extends NumericArray = Uint32Array> {\n\tstatic readonly ALLOCATE_COUNT = 6;\n\n\tprivate memory: MemoryHeap;\n\tprivate pointerMemory: AllocatedMemory;\n\tprivate lock: Int32Array;\n\t// Value type is written once at creation and never changes, so resolve it once instead of reading metadata per op\n\tprivate cachedType: number;\n\t// u32 units per value slot: 1 for 32-bit types, 2 for 64-bit (float64/int64/uint64). The values region and every\n\t// table allocation scale by this.\n\tprivate cachedValueUnits = 1;\n\n\t// Cache the resolved views so most operations avoid rebuilding them. Rebuild whenever the table pointer OR the capacity\n\t// changes: the pointer alone is not enough because the allocator recycles freed addresses (split:false), so a rehash can\n\t// land a differently-sized table at the same address (ABA). The cached views are plain windows into shared memory, so\n\t// they always reflect the current bytes at that address; only the derived capacity (mask/offsets) can go stale, and the\n\t// capacity check catches exactly that.\n\tprivate cachedTablePointer = 0;\n\tprivate cachedTableMemory?: AllocatedMemory;\n\tprivate cachedSlots?: Uint32Array; // whole block as u32: states region, then keys region\n\tprivate cachedValues?: V; // typed view over the values region\n\tprivate cachedCapacity = 0;\n\t// Callers hold the lock, so the acquire fence already published the latest pointer/capacity - plain reads are enough\n\t// and avoid two Atomics.load per operation on the hot path.\n\tprivate ensureTable() {\n\t\tlet data = this.pointerMemory.data;\n\t\tlet pointer = data[TABLE_POINTER_INDEX];\n\t\tlet capacity = data[CAPACITY_INDEX];\n\t\tif(pointer === this.cachedTablePointer && capacity === this.cachedCapacity && this.cachedSlots) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet table = new AllocatedMemory(this.memory, getPointer(pointer));\n\t\tthis.cachedTableMemory = table;\n\t\tthis.cachedSlots = table.data;\n\t\tthis.cachedValues = this.makeValuesView(table, capacity);\n\t\tthis.cachedCapacity = capacity;\n\t\tthis.cachedTablePointer = pointer;\n\t}\n\tprivate makeValuesView(table: AllocatedMemory, capacity: number): V {\n\t\t// states and keys each take one u32 per slot, so the values region starts after 2 * capacity u32s\n\t\tlet byteOffset = table.bufferByteOffset + capacity * 2 * Uint32Array.BYTES_PER_ELEMENT;\n\t\treturn makeArrayView(this.cachedType, table.data.buffer, byteOffset, capacity) as V;\n\t}\n\t// u32s a table of this capacity needs: states + keys (one each per slot) plus the values region, which is\n\t// cachedValueUnits u32s per slot.\n\tprivate tableLength(capacity: number): number {\n\t\treturn capacity * (2 + this.cachedValueUnits);\n\t}\n\n\tget length(): number {\n\t\treturn Atomics.load(this.pointerMemory.data, LENGTH_INDEX);\n\t}\n\tget capacity(): number {\n\t\treturn Atomics.load(this.pointerMemory.data, CAPACITY_INDEX);\n\t}\n\tget maxHash(): number {\n\t\treturn this.capacity;\n\t}\n\tget type(): number {\n\t\treturn this.cachedType;\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedMapConfig<V> | SharedMapMemory) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\tthis.pointerMemory = new AllocatedMemory(memory, config.firstBlock);\n\t\t} else {\n\t\t\tthis.pointerMemory = memory.allocUI32(SharedMap.ALLOCATE_COUNT);\n\t\t\tlet typeCode = getArrayTypeCode(config?.type ?? Uint32Array);\n\t\t\tthis.cachedValueUnits = getByteMultipler(typeCode);\n\t\t\tlet table = memory.allocUI32(DEFAULT_CAPACITY * (2 + this.cachedValueUnits));\n\t\t\tstoreRawPointer(this.pointerMemory.data, TABLE_POINTER_INDEX, table.pointer);\n\t\t\tAtomics.store(this.pointerMemory.data, CAPACITY_INDEX, DEFAULT_CAPACITY);\n\t\t\tAtomics.store(this.pointerMemory.data, TYPE_INDEX, typeCode);\n\t\t}\n\t\tthis.lock = new Int32Array(this.pointerMemory.data.buffer, this.pointerMemory.bufferByteOffset + LOCK_INDEX * Uint32Array.BYTES_PER_ELEMENT, SIMPLE_LOCK_ALLOCATE_COUNT);\n\t\tthis.cachedType = Atomics.load(this.pointerMemory.data, TYPE_INDEX);\n\t\tthis.cachedValueUnits = getByteMultipler(this.cachedType);\n\t}\n\n\tset(key: K, value: V[number]) {\n\t\tlet fullHashKey = get32BitHash(key);\n\n\t\tlock(this.lock);\n\t\ttry {\n\t\t\tlet data = this.pointerMemory.data;\n\t\t\tlet length = data[LENGTH_INDEX];\n\t\t\tlet tombstones = data[TOMBSTONE_INDEX];\n\t\t\tif((length + tombstones + 1) * LOAD_DENOMINATOR > data[CAPACITY_INDEX] * LOAD_NUMERATOR) {\n\t\t\t\tthis.resize();\n\t\t\t}\n\n\t\t\tthis.ensureTable();\n\t\t\tlet slots = this.cachedSlots!;\n\t\t\tlet values = this.cachedValues! as NumericArrayIO;\n\t\t\tlet capacity = this.cachedCapacity;\n\t\t\tlet mask = capacity - 1;\n\t\t\tlet keysBase = capacity;\n\t\t\tlet idx = mix32(fullHashKey) & mask;\n\t\t\tlet firstTomb = -1;\n\t\t\t// eslint-disable-next-line no-constant-condition\n\t\t\twhile(true) {\n\t\t\t\tlet state = slots[idx];\n\t\t\t\tif(state === EMPTY) {\n\t\t\t\t\tlet target = firstTomb >= 0 ? firstTomb : idx;\n\t\t\t\t\tslots[target] = FULL;\n\t\t\t\t\tslots[keysBase + target] = fullHashKey;\n\t\t\t\t\tvalues[target] = value;\n\t\t\t\t\tdata[LENGTH_INDEX]++;\n\t\t\t\t\t// Reusing a tombstone slot reclaims it\n\t\t\t\t\tif(firstTomb >= 0) {\n\t\t\t\t\t\tdata[TOMBSTONE_INDEX]--;\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t} else if(state === TOMBSTONE) {\n\t\t\t\t\tif(firstTomb < 0) {\n\t\t\t\t\t\tfirstTomb = idx;\n\t\t\t\t\t}\n\t\t\t\t} else if(slots[keysBase + idx] === fullHashKey) {\n\t\t\t\t\tvalues[idx] = value;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tidx = (idx + 1) & mask;\n\t\t\t}\n\t\t} finally {\n\t\t\tunlock(this.lock);\n\t\t}\n\t}\n\n\t// Atomic read-modify-write under the table lock: resolves the current value (undefined if the key is\n\t// absent), calls updater, and stores the result - so two threads mutating the same key never lose an\n\t// update the way a separate get() + set() can. updater runs inside the lock and must be synchronous and\n\t// must not touch this same map (the lock is not reentrant).\n\tupdate(key: K, updater: (current: V[number] | undefined) => V[number]): V[number] {\n\t\tlet fullHashKey = get32BitHash(key);\n\n\t\tlock(this.lock);\n\t\ttry {\n\t\t\tlet data = this.pointerMemory.data;\n\t\t\tlet length = data[LENGTH_INDEX];\n\t\t\tlet tombstones = data[TOMBSTONE_INDEX];\n\t\t\tif((length + tombstones + 1) * LOAD_DENOMINATOR > data[CAPACITY_INDEX] * LOAD_NUMERATOR) {\n\t\t\t\tthis.resize();\n\t\t\t}\n\n\t\t\tthis.ensureTable();\n\t\t\tlet slots = this.cachedSlots!;\n\t\t\tlet values = this.cachedValues! as NumericArrayIO;\n\t\t\tlet capacity = this.cachedCapacity;\n\t\t\tlet mask = capacity - 1;\n\t\t\tlet keysBase = capacity;\n\t\t\tlet idx = mix32(fullHashKey) & mask;\n\t\t\tlet firstTomb = -1;\n\t\t\t// eslint-disable-next-line no-constant-condition\n\t\t\twhile(true) {\n\t\t\t\tlet state = slots[idx];\n\t\t\t\tif(state === EMPTY) {\n\t\t\t\t\tlet newValue = updater(undefined);\n\t\t\t\t\tlet target = firstTomb >= 0 ? firstTomb : idx;\n\t\t\t\t\tslots[target] = FULL;\n\t\t\t\t\tslots[keysBase + target] = fullHashKey;\n\t\t\t\t\tvalues[target] = newValue;\n\t\t\t\t\tdata[LENGTH_INDEX]++;\n\t\t\t\t\tif(firstTomb >= 0) {\n\t\t\t\t\t\tdata[TOMBSTONE_INDEX]--;\n\t\t\t\t\t}\n\t\t\t\t\treturn newValue;\n\t\t\t\t} else if(state === TOMBSTONE) {\n\t\t\t\t\tif(firstTomb < 0) {\n\t\t\t\t\t\tfirstTomb = idx;\n\t\t\t\t\t}\n\t\t\t\t} else if(slots[keysBase + idx] === fullHashKey) {\n\t\t\t\t\tlet newValue = updater(values[idx]);\n\t\t\t\t\tvalues[idx] = newValue;\n\t\t\t\t\treturn newValue;\n\t\t\t\t}\n\n\t\t\t\tidx = (idx + 1) & mask;\n\t\t\t}\n\t\t} finally {\n\t\t\tunlock(this.lock);\n\t\t}\n\t}\n\n\tget(key: K): V[number] | undefined {\n\t\tlet fullHashKey = get32BitHash(key);\n\n\t\tlock(this.lock);\n\t\ttry {\n\t\t\tthis.ensureTable();\n\t\t\tlet slots = this.cachedSlots!;\n\t\t\tlet values = this.cachedValues! as NumericArrayIO;\n\t\t\tlet capacity = this.cachedCapacity;\n\t\t\tlet mask = capacity - 1;\n\t\t\tlet keysBase = capacity;\n\t\t\tlet idx = mix32(fullHashKey) & mask;\n\t\t\t// eslint-disable-next-line no-constant-condition\n\t\t\twhile(true) {\n\t\t\t\tlet state = slots[idx];\n\t\t\t\tif(state === EMPTY) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tif(state === FULL && slots[keysBase + idx] === fullHashKey) {\n\t\t\t\t\treturn values[idx];\n\t\t\t\t}\n\t\t\t\tidx = (idx + 1) & mask;\n\t\t\t}\n\t\t} finally {\n\t\t\tunlock(this.lock);\n\t\t}\n\t}\n\thas(key: K): boolean {\n\t\treturn this.get(key) !== undefined;\n\t}\n\n\tdelete(key: K): boolean {\n\t\tlet fullHashKey = get32BitHash(key);\n\n\t\tlock(this.lock);\n\t\ttry {\n\t\t\tthis.ensureTable();\n\t\t\tlet data = this.pointerMemory.data;\n\t\t\tlet slots = this.cachedSlots!;\n\t\t\tlet capacity = this.cachedCapacity;\n\t\t\tlet mask = capacity - 1;\n\t\t\tlet keysBase = capacity;\n\t\t\tlet idx = mix32(fullHashKey) & mask;\n\t\t\t// eslint-disable-next-line no-constant-condition\n\t\t\twhile(true) {\n\t\t\t\tlet state = slots[idx];\n\t\t\t\tif(state === EMPTY) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif(state === FULL && slots[keysBase + idx] === fullHashKey) {\n\t\t\t\t\tslots[idx] = TOMBSTONE;\n\t\t\t\t\tdata[LENGTH_INDEX]--;\n\t\t\t\t\tdata[TOMBSTONE_INDEX]++;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tidx = (idx + 1) & mask;\n\t\t\t}\n\t\t} finally {\n\t\t\tunlock(this.lock);\n\t\t}\n\t}\n\n\t// Best-effort scan (see class note): not lock-guarded, so must not run concurrently with writes from another thread.\n\t*[Symbol.iterator](): IterableIterator<[number, V[number]]> {\n\t\tthis.ensureTable();\n\t\tlet slots = this.cachedSlots!;\n\t\tlet values = this.cachedValues! as NumericArrayIO;\n\t\tlet capacity = this.cachedCapacity;\n\t\tlet keysBase = capacity;\n\t\tfor(let i = 0; i < capacity; i++) {\n\t\t\tif(slots[i] === FULL) {\n\t\t\t\tyield [slots[keysBase + i], values[i]];\n\t\t\t}\n\t\t}\n\t}\n\n\t// Rehash into a fresh table. Doubles capacity when live entries are crowding the table; when tombstones are the cause,\n\t// a same-size table already reclaims them. Caller must hold the lock.\n\tprivate resize() {\n\t\tthis.ensureTable();\n\t\tlet oldTable = this.cachedTableMemory!;\n\t\tlet oldSlots = this.cachedSlots!;\n\t\tlet oldValues = this.cachedValues! as NumericArrayIO;\n\t\tlet oldCapacity = this.cachedCapacity;\n\t\tlet oldKeysBase = oldCapacity;\n\t\tlet length = Atomics.load(this.pointerMemory.data, LENGTH_INDEX);\n\n\t\tlet newCapacity = oldCapacity;\n\t\tif((length + 1) * LOAD_DENOMINATOR > oldCapacity * LOAD_NUMERATOR) {\n\t\t\tnewCapacity = oldCapacity * 2;\n\t\t}\n\t\tlet newTable = this.memory.allocUI32(this.tableLength(newCapacity));\n\t\tlet newSlots = newTable.data;\n\t\tlet newValues = this.makeValuesView(newTable, newCapacity) as NumericArrayIO;\n\t\tlet mask = newCapacity - 1;\n\t\tlet newKeysBase = newCapacity;\n\n\t\tfor(let i = 0; i < oldCapacity; i++) {\n\t\t\tif(oldSlots[i] !== FULL) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet key = oldSlots[oldKeysBase + i];\n\t\t\tlet value = oldValues[i];\n\t\t\tlet idx = mix32(key) & mask;\n\t\t\t// Fresh table has no tombstones, so probe straight to the first empty slot\n\t\t\twhile(newSlots[idx] !== EMPTY) {\n\t\t\t\tidx = (idx + 1) & mask;\n\t\t\t}\n\t\t\tnewSlots[idx] = FULL;\n\t\t\tnewSlots[newKeysBase + idx] = key;\n\t\t\tnewValues[idx] = value;\n\t\t}\n\n\t\tstoreRawPointer(this.pointerMemory.data, TABLE_POINTER_INDEX, newTable.pointer);\n\t\tAtomics.store(this.pointerMemory.data, CAPACITY_INDEX, newCapacity);\n\t\tAtomics.store(this.pointerMemory.data, TOMBSTONE_INDEX, 0);\n\t\t// Invalidate the cached views so the next access rebuilds against the new table\n\t\tthis.cachedTablePointer = 0;\n\t\tthis.cachedSlots = undefined;\n\t\toldTable.free();\n\t}\n\n\tfree() {\n\t\tthis.ensureTable();\n\t\tthis.cachedTableMemory!.free();\n\t\tthis.pointerMemory.free();\n\t}\n\n\tgetSharedMemory(): SharedMapMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.pointerMemory.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedMapConfig<V extends NumericArray> {\n\ttype?: TypedArrayConstructor<V>\n}\ninterface SharedMapMemory {\n\tfirstBlock: SharedAllocatedMemory\n}\n\nexport type { SharedMapConfig, SharedMapMemory };\n"],"mappings":";;;;;;AAqBA,IAAM,IAAQ,GACR,IAAO,GACP,IAAY,GAEZ,IAAmB,IAEnB,IAAiB,GACjB,IAAmB,GAGnB,IAAsB,GACtB,IAAa,GACb,IAAe,GACf,IAAkB,GAClB,IAAiB,GACjB,IAAa,GAEE,IAArB,MAAqB,EAA2E;CAC/F,OAAgB,iBAAiB;CAEjC;CACA;CACA;CAEA;CAGA,mBAA2B;CAO3B,qBAA6B;CAC7B;CACA;CACA;CACA,iBAAyB;CAGzB,cAAsB;EACrB,IAAI,IAAO,KAAK,cAAc,MAC1B,IAAU,EAAK,IACf,IAAW,EAAK;EACpB,IAAG,MAAY,KAAK,sBAAsB,MAAa,KAAK,kBAAkB,KAAK,aAClF;EAGD,IAAI,IAAQ,IAAI,EAAgB,KAAK,QAAQ,EAAW,CAAO,CAAC;EAKhE,AAJA,KAAK,oBAAoB,GACzB,KAAK,cAAc,EAAM,MACzB,KAAK,eAAe,KAAK,eAAe,GAAO,CAAQ,GACvD,KAAK,iBAAiB,GACtB,KAAK,qBAAqB;CAC3B;CACA,eAAuB,GAAwB,GAAqB;EAEnE,IAAI,IAAa,EAAM,mBAAmB,IAAW,IAAI,YAAY;EACrE,OAAO,EAAc,KAAK,YAAY,EAAM,KAAK,QAAQ,GAAY,CAAQ;CAC9E;CAGA,YAAoB,GAA0B;EAC7C,OAAO,KAAY,IAAI,KAAK;CAC7B;CAEA,IAAI,SAAiB;EACpB,OAAO,QAAQ,KAAK,KAAK,cAAc,MAAM,CAAY;CAC1D;CACA,IAAI,WAAmB;EACtB,OAAO,QAAQ,KAAK,KAAK,cAAc,MAAM,CAAc;CAC5D;CACA,IAAI,UAAkB;EACrB,OAAO,KAAK;CACb;CACA,IAAI,OAAe;EAClB,OAAO,KAAK;CACb;CAEA,YAAY,GAAoB,GAA+C;EAG9E,IAFA,KAAK,SAAS,GAEX,KAAU,gBAAgB,GAC5B,KAAK,gBAAgB,IAAI,EAAgB,GAAQ,EAAO,UAAU;OAC5D;GACN,KAAK,gBAAgB,EAAO,UAAU,EAAU,cAAc;GAC9D,IAAI,IAAW,EAAiB,GAAQ,QAAQ,WAAW;GAC3D,KAAK,mBAAmB,EAAiB,CAAQ;GACjD,IAAI,IAAQ,EAAO,UAAU,KAAoB,IAAI,KAAK,iBAAiB;GAG3E,AAFA,EAAgB,KAAK,cAAc,MAAM,GAAqB,EAAM,OAAO,GAC3E,QAAQ,MAAM,KAAK,cAAc,MAAM,GAAgB,CAAgB,GACvE,QAAQ,MAAM,KAAK,cAAc,MAAM,GAAY,CAAQ;EAC5D;EAGA,AAFA,KAAK,OAAO,IAAI,WAAW,KAAK,cAAc,KAAK,QAAQ,KAAK,cAAc,mBAAmB,IAAa,YAAY,mBAAA,CAA6C,GACvK,KAAK,aAAa,QAAQ,KAAK,KAAK,cAAc,MAAM,CAAU,GAClE,KAAK,mBAAmB,EAAiB,KAAK,UAAU;CACzD;CAEA,IAAI,GAAQ,GAAkB;EAC7B,IAAI,IAAc,EAAa,CAAG;EAElC,EAAK,KAAK,IAAI;EACd,IAAI;GACH,IAAI,IAAO,KAAK,cAAc;GAO9B,CANa,EAAK,KACD,EAAK,KACI,KAAK,IAAmB,EAAK,KAAkB,KACxE,KAAK,OAAO,GAGb,KAAK,YAAY;GACjB,IAAI,IAAQ,KAAK,aACb,IAAS,KAAK,cACd,IAAW,KAAK,gBAChB,IAAO,IAAW,GAClB,IAAW,GACX,IAAM,EAAM,CAAW,IAAI,GAC3B,IAAY;GAEhB,SAAY;IACX,IAAI,IAAQ,EAAM;IAClB,IAAG,MAAU,GAAO;KACnB,IAAI,IAAS,KAAa,IAAI,IAAY;KAM1C,AALA,EAAM,KAAU,GAChB,EAAM,IAAW,KAAU,GAC3B,EAAO,KAAU,GACjB,EAAK,EAAa,IAEf,KAAa,KACf,EAAK,EAAgB;KAEtB;IACD;IAAO,IAAG,MAAU,GAChB,AAAA,IAAY,MACd,IAAY;SAEP,IAAG,EAAM,IAAW,OAAS,GAAa;KAChD,EAAO,KAAO;KACd;IACD;IAEA,IAAO,IAAM,IAAK;GACnB;EACD,UAAU;GACT,EAAO,KAAK,IAAI;EACjB;CACD;CAMA,OAAO,GAAQ,GAAmE;EACjF,IAAI,IAAc,EAAa,CAAG;EAElC,EAAK,KAAK,IAAI;EACd,IAAI;GACH,IAAI,IAAO,KAAK,cAAc;GAO9B,CANa,EAAK,KACD,EAAK,KACI,KAAK,IAAmB,EAAK,KAAkB,KACxE,KAAK,OAAO,GAGb,KAAK,YAAY;GACjB,IAAI,IAAQ,KAAK,aACb,IAAS,KAAK,cACd,IAAW,KAAK,gBAChB,IAAO,IAAW,GAClB,IAAW,GACX,IAAM,EAAM,CAAW,IAAI,GAC3B,IAAY;GAEhB,SAAY;IACX,IAAI,IAAQ,EAAM;IAClB,IAAG,MAAU,GAAO;KACnB,IAAI,IAAW,EAAQ,KAAA,CAAS,GAC5B,IAAS,KAAa,IAAI,IAAY;KAQ1C,OAPA,EAAM,KAAU,GAChB,EAAM,IAAW,KAAU,GAC3B,EAAO,KAAU,GACjB,EAAK,EAAa,IACf,KAAa,KACf,EAAK,EAAgB,IAEf;IACR;IAAO,IAAG,MAAU,GAChB,AAAA,IAAY,MACd,IAAY;SAEP,IAAG,EAAM,IAAW,OAAS,GAAa;KAChD,IAAI,IAAW,EAAQ,EAAO,EAAI;KAElC,OADA,EAAO,KAAO,GACP;IACR;IAEA,IAAO,IAAM,IAAK;GACnB;EACD,UAAU;GACT,EAAO,KAAK,IAAI;EACjB;CACD;CAEA,IAAI,GAA+B;EAClC,IAAI,IAAc,EAAa,CAAG;EAElC,EAAK,KAAK,IAAI;EACd,IAAI;GACH,KAAK,YAAY;GACjB,IAAI,IAAQ,KAAK,aACb,IAAS,KAAK,cACd,IAAW,KAAK,gBAChB,IAAO,IAAW,GAClB,IAAW,GACX,IAAM,EAAM,CAAW,IAAI;GAE/B,SAAY;IACX,IAAI,IAAQ,EAAM;IAClB,IAAG,MAAU,GACZ;IAED,IAAG,MAAU,KAAQ,EAAM,IAAW,OAAS,GAC9C,OAAO,EAAO;IAEf,IAAO,IAAM,IAAK;GACnB;EACD,UAAU;GACT,EAAO,KAAK,IAAI;EACjB;CACD;CACA,IAAI,GAAiB;EACpB,OAAO,KAAK,IAAI,CAAG,MAAM,KAAA;CAC1B;CAEA,OAAO,GAAiB;EACvB,IAAI,IAAc,EAAa,CAAG;EAElC,EAAK,KAAK,IAAI;EACd,IAAI;GACH,KAAK,YAAY;GACjB,IAAI,IAAO,KAAK,cAAc,MAC1B,IAAQ,KAAK,aACb,IAAW,KAAK,gBAChB,IAAO,IAAW,GAClB,IAAW,GACX,IAAM,EAAM,CAAW,IAAI;GAE/B,SAAY;IACX,IAAI,IAAQ,EAAM;IAClB,IAAG,MAAU,GACZ,OAAO;IAER,IAAG,MAAU,KAAQ,EAAM,IAAW,OAAS,GAI9C,OAHA,EAAM,KAAO,GACb,EAAK,EAAa,IAClB,EAAK,EAAgB,IACd;IAER,IAAO,IAAM,IAAK;GACnB;EACD,UAAU;GACT,EAAO,KAAK,IAAI;EACjB;CACD;CAGA,EAAE,OAAO,YAAmD;EAC3D,KAAK,YAAY;EACjB,IAAI,IAAQ,KAAK,aACb,IAAS,KAAK,cACd,IAAW,KAAK,gBAChB,IAAW;EACf,KAAI,IAAI,IAAI,GAAG,IAAI,GAAU,KAC5B,AAAG,EAAM,OAAO,MACf,MAAM,CAAC,EAAM,IAAW,IAAI,EAAO,EAAE;CAGxC;CAIA,SAAiB;EAChB,KAAK,YAAY;EACjB,IAAI,IAAW,KAAK,mBAChB,IAAW,KAAK,aAChB,IAAY,KAAK,cACjB,IAAc,KAAK,gBACnB,IAAc,GACd,IAAS,QAAQ,KAAK,KAAK,cAAc,MAAM,CAAY,GAE3D,IAAc;EAClB,CAAI,IAAS,KAAK,IAAmB,IAAc,MAClD,IAAc,IAAc;EAE7B,IAAI,IAAW,KAAK,OAAO,UAAU,KAAK,YAAY,CAAW,CAAC,GAC9D,IAAW,EAAS,MACpB,IAAY,KAAK,eAAe,GAAU,CAAW,GACrD,IAAO,IAAc,GACrB,IAAc;EAElB,KAAI,IAAI,IAAI,GAAG,IAAI,GAAa,KAAK;GACpC,IAAG,EAAS,OAAO,GAClB;GAGD,IAAI,IAAM,EAAS,IAAc,IAC7B,IAAQ,EAAU,IAClB,IAAM,EAAM,CAAG,IAAI;GAEvB,OAAM,EAAS,OAAS,IACvB,IAAO,IAAM,IAAK;GAInB,AAFA,EAAS,KAAO,GAChB,EAAS,IAAc,KAAO,GAC9B,EAAU,KAAO;EAClB;EAQA,AANA,EAAgB,KAAK,cAAc,MAAM,GAAqB,EAAS,OAAO,GAC9E,QAAQ,MAAM,KAAK,cAAc,MAAM,GAAgB,CAAW,GAClE,QAAQ,MAAM,KAAK,cAAc,MAAM,GAAiB,CAAC,GAEzD,KAAK,qBAAqB,GAC1B,KAAK,cAAc,KAAA,GACnB,EAAS,KAAK;CACf;CAEA,OAAO;EAGN,AAFA,KAAK,YAAY,GACjB,KAAK,kBAAmB,KAAK,GAC7B,KAAK,cAAc,KAAK;CACzB;CAEA,kBAAmC;EAClC,OAAO,EACN,YAAY,KAAK,cAAc,gBAAgB,EAChD;CACD;AACD"}
@@ -1,7 +1,7 @@
1
1
  import type { SharedAllocatedMemory } from './allocated-memory';
2
- import type { TypedArrayConstructor } from './interfaces/typed-array-constructor';
3
2
  import type MemoryHeap from './memory-heap';
4
- export default class SharedPool<T extends Uint32Array | Int32Array | Float32Array | Float64Array = Uint32Array> implements Iterable<T> {
3
+ import { type NumericArray, type TypedArrayConstructor } from './utils/array-type';
4
+ export default class SharedPool<T extends NumericArray = Uint32Array> implements Iterable<T> {
5
5
  static readonly ALLOCATE_COUNT = 6;
6
6
  private memory;
7
7
  private firstBlock;
@@ -27,8 +27,8 @@ export default class SharedPool<T extends Uint32Array | Int32Array | Float32Arra
27
27
  get usedMemory(): number;
28
28
  constructor(memory: MemoryHeap, config?: SharedPoolConfig<T> | SharedPoolMemory);
29
29
  at(index: number): T;
30
- get(index: number, dataIndex?: number): number;
31
- push(values: number | Array<number>): number;
30
+ get(index: number, dataIndex?: number): T[number];
31
+ push(values: T[number] | Array<T[number]>): number;
32
32
  deleteIndex(index: number): void;
33
33
  clear(): void;
34
34
  [Symbol.iterator](): Generator<T, void, unknown>;
@@ -37,7 +37,7 @@ export default class SharedPool<T extends Uint32Array | Int32Array | Float32Arra
37
37
  free(): void;
38
38
  getSharedMemory(): SharedPoolMemory;
39
39
  }
40
- interface SharedPoolConfig<T extends Uint32Array | Int32Array | Float32Array | Float64Array> {
40
+ interface SharedPoolConfig<T extends NumericArray> {
41
41
  maxChunkSize?: number;
42
42
  maxLength?: number;
43
43
  maxRecycledLength?: number;
@@ -1,9 +1,10 @@
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 { lock as i, unlock as a } from "./lock/simple-lock.js";
4
- import o from "./shared-stack.js";
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 s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = class g {
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;
8
9
  memory;
9
10
  firstBlock;
@@ -18,13 +19,13 @@ var s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = cla
18
19
  cachedType;
19
20
  cachedByteMultipler;
20
21
  get length() {
21
- return Atomics.load(this.firstBlock.data, s) - this.recycleStack.length;
22
+ return Atomics.load(this.firstBlock.data, u) - this.recycleStack.length;
22
23
  }
23
24
  get maxChunkSize() {
24
25
  return this.cachedMaxChunkSize;
25
26
  }
26
27
  set maxChunkSize(e) {
27
- Atomics.store(this.firstBlock.data, l, e);
28
+ Atomics.store(this.firstBlock.data, f, e);
28
29
  }
29
30
  get type() {
30
31
  return this.cachedType;
@@ -49,25 +50,25 @@ var s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = cla
49
50
  for (let n of this.pointerStack) t += new r(this.memory, e(n)).usedMemory;
50
51
  return t + this.pointerStack.usedMemory + this.recycleStack.usedMemory;
51
52
  }
52
- constructor(i, a) {
53
- if (this.memory = i, a && "firstBlock" in a) this.firstBlock = new r(i, a.firstBlock), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + c * Uint32Array.BYTES_PER_ELEMENT, 2), this.pointerStack = new o(i, { firstBlock: e(t(this.firstBlock.data, d)) }), this.recycleStack = new o(i, { firstBlock: e(t(this.firstBlock.data, f)) });
53
+ constructor(o, s) {
54
+ if (this.memory = o, s && "firstBlock" in s) this.firstBlock = new r(o, s.firstBlock), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + d * Uint32Array.BYTES_PER_ELEMENT, 2), this.pointerStack = new l(o, { firstBlock: e(t(this.firstBlock.data, m)) }), this.recycleStack = new l(o, { firstBlock: e(t(this.firstBlock.data, h)) });
54
55
  else {
55
- let e = a?.dataLength ?? 1, t = a?.maxChunkSize ?? p, r = a?.maxLength ?? m, s = a?.maxRecycledLength ?? h, l = o.getMaxSegmentLength(i.maxAllocationLength), u = r / t, _ = o.getAllocateCount(u, void 0, l), v = o.getAllocateCount(s, void 0, l);
56
- this.firstBlock = i.allocUI32(g.ALLOCATE_COUNT + _ + v), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + c * Uint32Array.BYTES_PER_ELEMENT, 2), this.pointerStack = new o(i, {
57
- firstBlock: this.firstBlock.getSubAllocation(g.ALLOCATE_COUNT, _),
56
+ let e = s?.dataLength ?? 1, t = s?.maxChunkSize ?? g, r = s?.maxLength ?? _, c = s?.maxRecycledLength ?? v, u = l.getMaxSegmentLength(o.maxAllocationLength), f = r / t, p = l.getAllocateCount(f, void 0, u), b = l.getAllocateCount(c, void 0, u);
57
+ this.firstBlock = o.allocUI32(y.ALLOCATE_COUNT + p + b), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + d * Uint32Array.BYTES_PER_ELEMENT, 2), this.pointerStack = new l(o, {
58
+ firstBlock: this.firstBlock.getSubAllocation(y.ALLOCATE_COUNT, p),
58
59
  type: Uint32Array,
59
- maxLength: u
60
- }), n(this.firstBlock.data, d, this.pointerStack.pointer), this.recycleStack = new o(i, {
61
- firstBlock: this.firstBlock.getSubAllocation(g.ALLOCATE_COUNT + _, v),
60
+ maxLength: f
61
+ }), n(this.firstBlock.data, m, this.pointerStack.pointer), this.recycleStack = new l(o, {
62
+ firstBlock: this.firstBlock.getSubAllocation(y.ALLOCATE_COUNT + p, b),
62
63
  type: Uint32Array,
63
- maxLength: s
64
- }), n(this.firstBlock.data, f, this.recycleStack.pointer);
65
- let y = a?.type ?? Uint32Array;
66
- y === Uint32Array ? this.type = 0 : y === Int32Array ? this.type = 1 : y === Float32Array ? this.type = 2 : y === Float64Array && (this.type = 3), this.dataLength = e, this.maxChunkSize = t;
67
- let b = y === Float64Array ? 2 : 1, x = i.allocUI32(t * e * b);
68
- this.pointerStack.push(x.pointer);
64
+ maxLength: c
65
+ }), n(this.firstBlock.data, h, this.recycleStack.pointer);
66
+ let x = i(s?.type ?? Uint32Array);
67
+ this.type = x, this.dataLength = e, this.maxChunkSize = t;
68
+ let S = a(x), C = o.allocUI32(t * e * S);
69
+ this.pointerStack.push(C.pointer);
69
70
  }
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);
71
+ 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);
71
72
  }
72
73
  at(e) {
73
74
  let t = this.getFullDataBlock(e);
@@ -79,59 +80,46 @@ var s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = cla
79
80
  return this.getFullDataBlock(e)[e % this.cachedMaxChunkSize * n + t];
80
81
  }
81
82
  push(e) {
82
- let t = this.cachedDataLength, n = typeof e == "number";
83
+ let t = this.cachedDataLength, n = typeof e != "object";
83
84
  if (!n && e.length > t) throw Error(`Can't insert ${e.length} array into shared list of ${t} dataLength`);
84
85
  let r = this.recycleStack.pop();
85
- r === void 0 && (r = Atomics.add(this.firstBlock.data, s, 1));
86
+ r === void 0 && (r = Atomics.add(this.firstBlock.data, u, 1));
86
87
  let i = this.getFullDataBlock(r), a = t * (r % this.cachedMaxChunkSize);
87
- return n ? i[a] = e : i.set(e, a), r;
88
+ if (n) i[a] = e;
89
+ else for (let t = 0; t < e.length; t++) i[a + t] = e[t];
90
+ return r;
88
91
  }
89
92
  deleteIndex(e) {
90
93
  this.recycleStack.push(e);
91
94
  }
92
95
  clear() {
93
- this.firstBlock.data[s] = 0, this.recycleStack.clear();
96
+ this.firstBlock.data[u] = 0, this.recycleStack.clear();
94
97
  }
95
98
  *[Symbol.iterator]() {
96
99
  let e = {};
97
100
  for (let t of this.recycleStack) e[t] = !0;
98
- let t = this.cachedMaxChunkSize, n = Atomics.load(this.firstBlock.data, s), r = this.getFullDataBlock(0), i = 0;
101
+ let t = this.cachedMaxChunkSize, n = Atomics.load(this.firstBlock.data, u), r = this.getFullDataBlock(0), i = 0;
99
102
  for (let a = 0; a < n; a++) if (!e[a]) {
100
103
  let e = Math.floor(a / t);
101
104
  e !== i && (r = this.getFullDataBlock(a), i = e), yield this.getDataBlock(r, a % t);
102
105
  }
103
106
  }
104
107
  getFullDataBlock(t) {
105
- let n = Math.floor(t / this.cachedMaxChunkSize), o = this.cachedFullDataBlock[n];
106
- if (o) return o;
108
+ let n = Math.floor(t / this.cachedMaxChunkSize), i = this.cachedFullDataBlock[n];
109
+ if (i) return i;
107
110
  if (n >= this.pointerStack.length) {
108
- i(this.growLock);
111
+ s(this.growLock);
109
112
  try {
110
113
  for (; n >= this.pointerStack.length;) {
111
114
  let e = this.memory.allocUI32(this.cachedMaxChunkSize * this.cachedDataLength * this.cachedByteMultipler);
112
115
  this.pointerStack.push(e.pointer);
113
116
  }
114
117
  } finally {
115
- a(this.growLock);
118
+ c(this.growLock);
116
119
  }
117
120
  }
118
- let s = new r(this.memory, e(this.pointerStack.at(n))), c = this.cachedDataLength * this.cachedMaxChunkSize, l;
119
- switch (this.cachedType) {
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;
121
+ let a = new r(this.memory, e(this.pointerStack.at(n))), l = this.cachedDataLength * this.cachedMaxChunkSize, u = o(this.cachedType, a.data.buffer, a.bufferByteOffset, l);
122
+ return this.cachedFullDataBlock[n] = u, u;
135
123
  }
136
124
  getDataBlock(e, t) {
137
125
  let n = this.cachedDataLength, r = t * n;
@@ -147,6 +135,6 @@ var s = 0, c = 1, l = 2, u = 3, d = 4, f = 5, p = 100, m = 1e6, h = 1e5, g = cla
147
135
  }
148
136
  };
149
137
  //#endregion
150
- export { g as default };
138
+ export { y as default };
151
139
 
152
140
  //# sourceMappingURL=shared-pool.js.map