@daneren2005/shared-memory-objects 1.6.1 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +3 -2
  2. package/dist/allocated-memory.js +1 -2
  3. package/dist/cached-item-list.js +1 -2
  4. package/dist/constant-string.js +13 -14
  5. package/dist/local-pool.js +5 -6
  6. package/dist/lock/read-write-lock.js +0 -1
  7. package/dist/lock/simple-lock.js +0 -1
  8. package/dist/memory-buffer.js +1 -2
  9. package/dist/memory-heap.js +24 -25
  10. package/dist/serialize-object.js +4 -5
  11. package/dist/shared-list.js +43 -44
  12. package/dist/shared-map.js +74 -75
  13. package/dist/shared-pointer-list.js +15 -16
  14. package/dist/shared-pool.d.ts +1 -0
  15. package/dist/shared-pool.js +36 -32
  16. package/dist/shared-pool.js.map +1 -1
  17. package/dist/shared-stack.js +33 -34
  18. package/dist/shared-string.js +19 -20
  19. package/dist/shared-vector.js +23 -24
  20. package/dist/spatial/shared-quadtree.js +81 -82
  21. package/dist/spatial/shared-quadtree.js.map +1 -1
  22. package/dist/spatial/shared-spatial-grid.js +104 -110
  23. package/dist/spatial/shared-spatial-grid.js.map +1 -1
  24. package/dist/spatial/shared-spatial-map.d.ts +2 -0
  25. package/dist/spatial/shared-spatial-map.js +205 -202
  26. package/dist/spatial/shared-spatial-map.js.map +1 -1
  27. package/dist/spatial/spatial-entity.js +1 -2
  28. package/dist/spatial/spatial-neighbors.js +1 -2
  29. package/dist/utils/16-from-32-array.js +1 -2
  30. package/dist/utils/16-from-32-float.js +1 -2
  31. package/dist/utils/16-from-32-int.js +1 -2
  32. package/dist/utils/16-from-32-uint.js +1 -2
  33. package/dist/utils/16-from-64-array.js +1 -2
  34. package/dist/utils/16-from-64-float.js +1 -2
  35. package/dist/utils/16-from-64-int.js +1 -2
  36. package/dist/utils/16-from-64-uint.js +1 -2
  37. package/dist/utils/32-from-64-float.js +1 -2
  38. package/dist/utils/32-from-64-int.js +1 -2
  39. package/dist/utils/32-from-64-uint.js +1 -2
  40. package/dist/utils/array-type.js +1 -2
  41. package/dist/utils/atomic-math.js +1 -2
  42. package/dist/utils/float32-atomics.js +1 -2
  43. package/dist/utils/float64-atomics.js +1 -2
  44. package/dist/utils/hash.js +1 -2
  45. package/dist/utils/pointer.js +1 -2
  46. package/dist/utils/typedarray.js +1 -2
  47. package/package.json +11 -11
@@ -1,9 +1,9 @@
1
- import { getPointer as e, storeRawPointer as t } from "./utils/pointer.js";
2
- import n from "./allocated-memory.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";
6
- //#region src/shared-map.ts
1
+ import e from "./allocated-memory.js";
2
+ import { getPointer as t, storeRawPointer as n } from "./utils/pointer.js";
3
+ import { get32BitHash as r, mix32 as i } from "./utils/hash.js";
4
+ import { lock as a, unlock as o } from "./lock/simple-lock.js";
5
+ import { getArrayTypeCode as s, getByteMultipler as c, makeArrayView as l } from "./utils/array-type.js";
6
+ // src/shared-map.ts
7
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
8
  static ALLOCATE_COUNT = 6;
9
9
  memory;
@@ -19,14 +19,14 @@ var u = 0, d = 1, f = 2, p = 16, m = 3, h = 4, g = 0, _ = 1, v = 2, y = 3, b = 4
19
19
  cachedValues;
20
20
  cachedCapacity = 0;
21
21
  ensureTable() {
22
- let t = this.pointerMemory.data, r = t[g], i = t[b];
22
+ let n = this.pointerMemory.data, r = n[g], i = n[b];
23
23
  if (r === this.cachedTablePointer && i === this.cachedCapacity && this.cachedSlots) return;
24
- let a = new n(this.memory, e(r, this.memory.positionBits));
24
+ let a = new e(this.memory, t(r, this.memory.positionBits));
25
25
  this.cachedTableMemory = a, this.cachedSlots = a.data, this.cachedValues = this.makeValuesView(a, i), this.cachedCapacity = i, this.cachedTablePointer = r;
26
26
  }
27
27
  makeValuesView(e, t) {
28
28
  let n = e.bufferByteOffset + t * 2 * Uint32Array.BYTES_PER_ELEMENT;
29
- return a(this.cachedType, e.data.buffer, n, t);
29
+ return l(this.cachedType, e.data.buffer, n, t);
30
30
  }
31
31
  tableLength(e) {
32
32
  return e * (2 + this.cachedValueUnits);
@@ -44,39 +44,39 @@ var u = 0, d = 1, f = 2, p = 16, m = 3, h = 4, g = 0, _ = 1, v = 2, y = 3, b = 4
44
44
  return this.cachedType;
45
45
  }
46
46
  get usedMemory() {
47
- o(this.lock);
47
+ a(this.lock);
48
48
  try {
49
49
  return this.ensureTable(), (this.ownsFirstBlock ? this.pointerMemory.usedMemory : 0) + this.cachedTableMemory.usedMemory;
50
50
  } finally {
51
- s(this.lock);
51
+ o(this.lock);
52
52
  }
53
53
  }
54
- constructor(e, t) {
55
- this.memory = e, t && "firstBlock" in t ? t.firstBlock instanceof n ? (this.pointerMemory = t.firstBlock, this.initialize(t), this.ownsFirstBlock = !1) : this.pointerMemory = new n(e, {
54
+ constructor(t, n) {
55
+ this.memory = t, n && "firstBlock" in n ? n.firstBlock instanceof e ? (this.pointerMemory = n.firstBlock, this.initialize(n), this.ownsFirstBlock = !1) : this.pointerMemory = new e(t, {
56
56
  length: S.ALLOCATE_COUNT,
57
- ...t.firstBlock
58
- }) : (this.pointerMemory = e.allocUI32(S.ALLOCATE_COUNT), this.initialize(t)), 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), this.maxTableCapacity = 2 ** Math.floor(Math.log2(this.memory.maxAllocationLength / (2 + this.cachedValueUnits)));
57
+ ...n.firstBlock
58
+ }) : (this.pointerMemory = t.allocUI32(S.ALLOCATE_COUNT), this.initialize(n)), 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 = c(this.cachedType), this.maxTableCapacity = 2 ** Math.floor(Math.log2(this.memory.maxAllocationLength / (2 + this.cachedValueUnits)));
59
59
  }
60
60
  initialize(e) {
61
- let n = e && "type" in e ? e.type : void 0, a = r(n ?? Uint32Array);
62
- this.cachedValueUnits = i(a);
63
- let o = e && "capacity" in e ? e.capacity : void 0, s = p;
64
- for (; s < (o ?? p);) s *= 2;
65
- if (s * (2 + this.cachedValueUnits) > this.memory.maxAllocationLength) throw Error(`SharedMap capacity ${s} exceeds the largest contiguous allocation`);
66
- let c = this.memory.allocUI32(s * (2 + this.cachedValueUnits));
67
- t(this.pointerMemory.data, g, c.pointer), Atomics.store(this.pointerMemory.data, b, s), Atomics.store(this.pointerMemory.data, x, a);
61
+ let t = e && "type" in e ? e.type : void 0, r = s(t ?? Uint32Array);
62
+ this.cachedValueUnits = c(r);
63
+ let i = e && "capacity" in e ? e.capacity : void 0, a = p;
64
+ for (; a < (i ?? p);) a *= 2;
65
+ if (a * (2 + this.cachedValueUnits) > this.memory.maxAllocationLength) throw Error(`SharedMap capacity ${a} exceeds the largest contiguous allocation`);
66
+ let o = this.memory.allocUI32(a * (2 + this.cachedValueUnits));
67
+ n(this.pointerMemory.data, g, o.pointer), Atomics.store(this.pointerMemory.data, b, a), Atomics.store(this.pointerMemory.data, x, r);
68
68
  }
69
69
  set(e, t) {
70
- o(this.lock);
70
+ a(this.lock);
71
71
  try {
72
72
  this.setNoLock(e, t);
73
73
  } finally {
74
- s(this.lock);
74
+ o(this.lock);
75
75
  }
76
76
  }
77
77
  setAll(e) {
78
78
  let t = Array.from(e);
79
- o(this.lock);
79
+ a(this.lock);
80
80
  try {
81
81
  let e = this.pointerMemory.data, n = e[v] + e[y] + t.length;
82
82
  if (n * h > e[b] * m) {
@@ -86,18 +86,18 @@ var u = 0, d = 1, f = 2, p = 16, m = 3, h = 4, g = 0, _ = 1, v = 2, y = 3, b = 4
86
86
  }
87
87
  for (let [e, n] of t) this.setNoLock(e, n);
88
88
  } finally {
89
- s(this.lock);
89
+ o(this.lock);
90
90
  }
91
91
  }
92
92
  setNoLock(e, t) {
93
- let n = c(e), r = this.pointerMemory.data;
94
- (r[v] + r[y] + 1) * h > r[b] * m && this.resizeForInsert(e), this.ensureTable();
95
- let i = this.cachedSlots, a = this.cachedValues, o = this.cachedCapacity, s = o - 1, p = o, g = l(n) & s, _ = -1;
93
+ let n = r(e), a = this.pointerMemory.data;
94
+ (a[v] + a[y] + 1) * h > a[b] * m && this.resizeForInsert(e), this.ensureTable();
95
+ let o = this.cachedSlots, s = this.cachedValues, c = this.cachedCapacity, l = c - 1, p = c, g = i(n) & l, _ = -1;
96
96
  for (;;) {
97
- let e = i[g];
97
+ let e = o[g];
98
98
  if (e === u) {
99
99
  let e = _ >= 0 ? _ : g;
100
- i[e] = d, i[p + e] = n, a[e] = t, r[v]++, _ >= 0 && r[y]--;
100
+ o[e] = d, o[p + e] = n, s[e] = t, a[v]++, _ >= 0 && a[y]--;
101
101
  return;
102
102
  }
103
103
  if (e === f) {
@@ -106,37 +106,37 @@ var u = 0, d = 1, f = 2, p = 16, m = 3, h = 4, g = 0, _ = 1, v = 2, y = 3, b = 4
106
106
  this.reuseTombstone(g, n, t);
107
107
  return;
108
108
  }
109
- } else if (i[p + g] === n) {
110
- a[g] = t;
109
+ } else if (o[p + g] === n) {
110
+ s[g] = t;
111
111
  return;
112
112
  }
113
- g = g + 1 & s;
113
+ g = g + 1 & l;
114
114
  }
115
115
  }
116
116
  update(e, t) {
117
- let n = c(e);
118
- o(this.lock);
117
+ let n = r(e);
118
+ a(this.lock);
119
119
  try {
120
120
  let r = this.pointerMemory.data;
121
121
  (r[v] + r[y] + 1) * h > r[b] * m && this.resizeForInsert(e), this.ensureTable();
122
- let i = this.cachedSlots, a = this.cachedValues, o = this.cachedCapacity, s = o - 1, c = l(n) & s, p = -1;
122
+ let a = this.cachedSlots, o = this.cachedValues, s = this.cachedCapacity, c = s - 1, l = i(n) & c, p = -1;
123
123
  for (;;) {
124
- let e = i[c];
124
+ let e = a[l];
125
125
  if (e === u) {
126
- let e = t(void 0), s = p >= 0 ? p : c;
127
- return i[s] = d, i[o + s] = n, a[s] = e, r[v]++, p >= 0 && r[y]--, e;
126
+ let e = t(void 0), i = p >= 0 ? p : l;
127
+ return a[i] = d, a[s + i] = n, o[i] = e, r[v]++, p >= 0 && r[y]--, e;
128
128
  }
129
129
  if (e === f) {
130
- if (c === p) return this.reuseTombstone(c, n, t);
131
- p < 0 && (p = c);
132
- } else if (i[o + c] === n) {
133
- let e = t(a[c]);
134
- return a[c] = e, e;
130
+ if (l === p) return this.reuseTombstone(l, n, t);
131
+ p < 0 && (p = l);
132
+ } else if (a[s + l] === n) {
133
+ let e = t(o[l]);
134
+ return o[l] = e, e;
135
135
  }
136
- c = c + 1 & s;
136
+ l = l + 1 & c;
137
137
  }
138
138
  } finally {
139
- s(this.lock);
139
+ o(this.lock);
140
140
  }
141
141
  }
142
142
  resizeForInsert(e) {
@@ -149,52 +149,52 @@ var u = 0, d = 1, f = 2, p = 16, m = 3, h = 4, g = 0, _ = 1, v = 2, y = 3, b = 4
149
149
  return i[e] = d, i[this.cachedCapacity + e] = t, a[e] = r, this.pointerMemory.data[v]++, this.pointerMemory.data[y]--, r;
150
150
  }
151
151
  get(e) {
152
- o(this.lock);
152
+ a(this.lock);
153
153
  try {
154
154
  return this.getNoLock(e);
155
155
  } finally {
156
- s(this.lock);
156
+ o(this.lock);
157
157
  }
158
158
  }
159
159
  getAll(e) {
160
- o(this.lock);
160
+ a(this.lock);
161
161
  try {
162
162
  let t = [];
163
163
  for (let n of e) t.push(this.getNoLock(n));
164
164
  return t;
165
165
  } finally {
166
- s(this.lock);
166
+ o(this.lock);
167
167
  }
168
168
  }
169
169
  getNoLock(e) {
170
- let t = c(e);
170
+ let t = r(e);
171
171
  this.ensureTable();
172
- let n = this.cachedSlots, r = this.cachedValues, i = this.cachedCapacity, a = i - 1, o = i, s = l(t) & a, f = s;
172
+ let n = this.cachedSlots, a = this.cachedValues, o = this.cachedCapacity, s = o - 1, c = o, l = i(t) & s, f = l;
173
173
  do {
174
- let e = n[s];
174
+ let e = n[l];
175
175
  if (e === u) return;
176
- if (e === d && n[o + s] === t) return r[s];
177
- s = s + 1 & a;
178
- } while (s !== f);
176
+ if (e === d && n[c + l] === t) return a[l];
177
+ l = l + 1 & s;
178
+ } while (l !== f);
179
179
  }
180
180
  has(e) {
181
181
  return this.get(e) !== void 0;
182
182
  }
183
183
  delete(e) {
184
- let t = c(e);
185
- o(this.lock);
184
+ let t = r(e);
185
+ a(this.lock);
186
186
  try {
187
187
  this.ensureTable();
188
- let e = this.pointerMemory.data, n = this.cachedSlots, r = this.cachedCapacity, i = r - 1, a = r, o = l(t) & i, s = o;
188
+ let e = this.pointerMemory.data, n = this.cachedSlots, r = this.cachedCapacity, a = r - 1, o = r, s = i(t) & a, c = s;
189
189
  do {
190
- let r = n[o];
190
+ let r = n[s];
191
191
  if (r === u) return !1;
192
- if (r === d && n[a + o] === t) return n[o] = f, e[v]--, e[y]++, !0;
193
- o = o + 1 & i;
194
- } while (o !== s);
192
+ if (r === d && n[o + s] === t) return n[s] = f, e[v]--, e[y]++, !0;
193
+ s = s + 1 & a;
194
+ } while (s !== c);
195
195
  return !1;
196
196
  } finally {
197
- s(this.lock);
197
+ o(this.lock);
198
198
  }
199
199
  }
200
200
  *[Symbol.iterator]() {
@@ -204,19 +204,19 @@ var u = 0, d = 1, f = 2, p = 16, m = 3, h = 4, g = 0, _ = 1, v = 2, y = 3, b = 4
204
204
  }
205
205
  resize(e) {
206
206
  this.ensureTable();
207
- let n = this.cachedTableMemory, r = this.cachedSlots, i = this.cachedValues, a = this.cachedCapacity, o = a, s = Atomics.load(this.pointerMemory.data, v), c = e ?? a;
208
- if (e === void 0 && (s + 1) * h > a * m && (c = a * 2), this.tableLength(c) > this.memory.maxAllocationLength) {
207
+ let t = this.cachedTableMemory, r = this.cachedSlots, a = this.cachedValues, o = this.cachedCapacity, s = o, c = Atomics.load(this.pointerMemory.data, v), l = e ?? o;
208
+ if (e === void 0 && (c + 1) * h > o * m && (l = o * 2), this.tableLength(l) > this.memory.maxAllocationLength) {
209
209
  let e = Math.floor(this.memory.maxAllocationLength / (2 + this.cachedValueUnits) * m / h);
210
- throw Error(`SharedMap can't grow to capacity ${c}: its table would exceed the largest contiguous allocation (${this.memory.maxAllocationLength} u32s, ~${e} entries). Use larger buffers or shard across multiple maps.`);
210
+ throw Error(`SharedMap can't grow to capacity ${l}: its table would exceed the largest contiguous allocation (${this.memory.maxAllocationLength} u32s, ~${e} entries). Use larger buffers or shard across multiple maps.`);
211
211
  }
212
- let f = this.memory.allocUI32(this.tableLength(c)), p = f.data, _ = this.makeValuesView(f, c), x = c - 1, S = c;
213
- for (let e = 0; e < a; e++) {
212
+ let f = this.memory.allocUI32(this.tableLength(l)), p = f.data, _ = this.makeValuesView(f, l), x = l - 1, S = l;
213
+ for (let e = 0; e < o; e++) {
214
214
  if (r[e] !== d) continue;
215
- let t = r[o + e], n = i[e], a = l(t) & x;
216
- for (; p[a] !== u;) a = a + 1 & x;
217
- p[a] = d, p[S + a] = t, _[a] = n;
215
+ let t = r[s + e], n = a[e], o = i(t) & x;
216
+ for (; p[o] !== u;) o = o + 1 & x;
217
+ p[o] = d, p[S + o] = t, _[o] = n;
218
218
  }
219
- t(this.pointerMemory.data, g, f.pointer), Atomics.store(this.pointerMemory.data, b, c), Atomics.store(this.pointerMemory.data, y, 0), this.cachedTablePointer = 0, this.cachedSlots = void 0, n.free();
219
+ n(this.pointerMemory.data, g, f.pointer), Atomics.store(this.pointerMemory.data, b, l), Atomics.store(this.pointerMemory.data, y, 0), this.cachedTablePointer = 0, this.cachedSlots = void 0, t.free();
220
220
  }
221
221
  free() {
222
222
  this.ensureTable(), this.cachedTableMemory.free(), this.ownsFirstBlock && this.pointerMemory.free();
@@ -225,7 +225,6 @@ var u = 0, d = 1, f = 2, p = 16, m = 3, h = 4, g = 0, _ = 1, v = 2, y = 3, b = 4
225
225
  return { firstBlock: this.pointerMemory.getSharedMemory() };
226
226
  }
227
227
  };
228
- //#endregion
229
228
  export { S as default };
230
229
 
231
230
  //# sourceMappingURL=shared-map.js.map
@@ -1,31 +1,31 @@
1
- import { createPointer as e, loadPointer as t } from "./utils/pointer.js";
2
- import n from "./allocated-memory.js";
3
- import r from "./shared-list.js";
4
- //#region src/shared-pointer-list.ts
1
+ import e from "./allocated-memory.js";
2
+ import t from "./shared-list.js";
3
+ import { createPointer as n, loadPointer as r } from "./utils/pointer.js";
4
+ // src/shared-pointer-list.ts
5
5
  var i = class {
6
6
  memory;
7
7
  list;
8
- constructor(e, t) {
9
- this.memory = e, this.list = t ? new r(e, t) : new r(e);
8
+ constructor(e, n) {
9
+ this.memory = e, this.list = n ? new t(e, n) : new t(e);
10
10
  }
11
11
  get length() {
12
12
  return this.list.length;
13
13
  }
14
- insert(t) {
15
- this.list.insert(e(t.memory.bufferPosition, t.memory.bufferByteOffset, this.memory.positionBits));
14
+ insert(e) {
15
+ this.list.insert(n(e.memory.bufferPosition, e.memory.bufferByteOffset, this.memory.positionBits));
16
16
  }
17
- delete(t) {
18
- let n = this.list.deleteValue(e(t.memory.bufferPosition, t.memory.bufferByteOffset, this.memory.positionBits));
19
- return this.list.compact(), n;
17
+ delete(e) {
18
+ let t = this.list.deleteValue(n(e.memory.bufferPosition, e.memory.bufferByteOffset, this.memory.positionBits));
19
+ return this.list.compact(), t;
20
20
  }
21
21
  compact() {
22
22
  this.list.compact();
23
23
  }
24
24
  *[Symbol.iterator]() {
25
- let e = this.list[Symbol.iterator]();
26
- for (let { data: r } of e) {
27
- let { bufferPosition: e, bufferByteOffset: i } = t(r, 0, this.memory.positionBits), a = new n(this.memory, {
28
- bufferPosition: e,
25
+ let t = this.list[Symbol.iterator]();
26
+ for (let { data: n } of t) {
27
+ let { bufferPosition: t, bufferByteOffset: i } = r(n, 0, this.memory.positionBits), a = new e(this.memory, {
28
+ bufferPosition: t,
29
29
  bufferByteOffset: i
30
30
  });
31
31
  yield this.createItem(a);
@@ -45,7 +45,6 @@ var i = class {
45
45
  this.list.free();
46
46
  }
47
47
  };
48
- //#endregion
49
48
  export { i as default };
50
49
 
51
50
  //# sourceMappingURL=shared-pointer-list.js.map
@@ -39,6 +39,7 @@ export default class SharedPool<T extends NumericArray = Uint32Array> implements
39
39
  reserveContiguous(count: number): number;
40
40
  deleteIndex(index: number): void;
41
41
  clear(): void;
42
+ getRecycledMask(): Uint8Array;
42
43
  [Symbol.iterator](): Generator<T, void, unknown>;
43
44
  entries(): IterableIterator<[number, T]>;
44
45
  private getFullDataBlock;
@@ -1,14 +1,14 @@
1
- import { getPointer as e, loadRawPointer as t, storeRawPointer as n } from "./utils/pointer.js";
2
- import r from "./allocated-memory.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";
6
- //#region src/shared-pool.ts
1
+ import e from "./allocated-memory.js";
2
+ import { lock as t, unlock as n } from "./lock/simple-lock.js";
3
+ import r from "./shared-stack.js";
4
+ import { getPointer as i, loadRawPointer as a, storeRawPointer as o } from "./utils/pointer.js";
5
+ import { getArrayTypeCode as s, getByteMultipler as c, makeArrayView as l } from "./utils/array-type.js";
6
+ // src/shared-pool.ts
7
7
  var u = 0, d = 1, f = 2, p = 3, m = 4, h = 5, g = 100, _ = 1e6, v = 1e5, y = class y {
8
8
  static ALLOCATE_COUNT = 6;
9
9
  static getAllocateCount(e, t) {
10
- let n = t?.maxChunkSize ?? g, r = t?.maxLength ?? _, i = t?.maxRecycledLength ?? v, a = l.getMaxSegmentLength(e.maxAllocationLength), o = l.getAllocateCount(r / n, void 0, a), s = l.getAllocateCount(i, void 0, a);
11
- return y.ALLOCATE_COUNT + o + s;
10
+ let n = t?.maxChunkSize ?? g, i = t?.maxLength ?? _, a = t?.maxRecycledLength ?? v, o = r.getMaxSegmentLength(e.maxAllocationLength), s = r.getAllocateCount(i / n, void 0, o), c = r.getAllocateCount(a, void 0, o);
11
+ return y.ALLOCATE_COUNT + s + c;
12
12
  }
13
13
  memory;
14
14
  firstBlock;
@@ -52,29 +52,29 @@ var u = 0, d = 1, f = 2, p = 3, m = 4, h = 5, g = 100, _ = 1e6, v = 1e5, y = cla
52
52
  }
53
53
  get usedMemory() {
54
54
  let t = this.ownsFirstBlock ? this.firstBlock.usedMemory : 0;
55
- for (let n of this.pointerStack) t += new r(this.memory, e(n, this.memory.positionBits)).usedMemory;
55
+ for (let n of this.pointerStack) t += new e(this.memory, i(n, this.memory.positionBits)).usedMemory;
56
56
  return t + this.pointerStack.usedMemory + this.recycleStack.usedMemory;
57
57
  }
58
- constructor(n, i) {
59
- this.memory = n, i && "firstBlock" in i ? (this.firstBlock = i.firstBlock instanceof r ? i.firstBlock : new r(n, {
58
+ constructor(t, n) {
59
+ this.memory = t, n && "firstBlock" in n ? (this.firstBlock = n.firstBlock instanceof e ? n.firstBlock : new e(t, {
60
60
  length: y.ALLOCATE_COUNT,
61
- ...i.firstBlock
62
- }), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + d * Uint32Array.BYTES_PER_ELEMENT, 2), "type" in i || "dataLength" in i || "maxLength" in i || "maxChunkSize" in i || "maxRecycledLength" in i ? (this.initialize(i), this.ownsFirstBlock = !1) : (this.pointerStack = new l(n, { firstBlock: e(t(this.firstBlock.data, m), n.positionBits) }), this.recycleStack = new l(n, { firstBlock: e(t(this.firstBlock.data, h), n.positionBits) }), this.ownsFirstBlock = !0)) : (this.firstBlock = n.allocUI32(y.getAllocateCount(n, i)), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + d * Uint32Array.BYTES_PER_ELEMENT, 2), this.initialize(i), this.ownsFirstBlock = !0), this.cachedType = this.uint16Array[0], this.cachedDataLength = Math.max(1, this.uint16Array[1]), this.cachedMaxChunkSize = this.firstBlock.data[f], this.cachedByteMultipler = a(this.cachedType), this.maxLength = this.cachedMaxChunkSize * this.pointerStack.maxLength, this.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + p * Uint32Array.BYTES_PER_ELEMENT, 1);
61
+ ...n.firstBlock
62
+ }), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + d * Uint32Array.BYTES_PER_ELEMENT, 2), "type" in n || "dataLength" in n || "maxLength" in n || "maxChunkSize" in n || "maxRecycledLength" in n ? (this.initialize(n), this.ownsFirstBlock = !1) : (this.pointerStack = new r(t, { firstBlock: i(a(this.firstBlock.data, m), t.positionBits) }), this.recycleStack = new r(t, { firstBlock: i(a(this.firstBlock.data, h), t.positionBits) }), this.ownsFirstBlock = !0)) : (this.firstBlock = t.allocUI32(y.getAllocateCount(t, n)), this.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + d * Uint32Array.BYTES_PER_ELEMENT, 2), this.initialize(n), this.ownsFirstBlock = !0), this.cachedType = this.uint16Array[0], this.cachedDataLength = Math.max(1, this.uint16Array[1]), this.cachedMaxChunkSize = this.firstBlock.data[f], this.cachedByteMultipler = c(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);
63
63
  }
64
64
  initialize(e) {
65
- let t = e?.dataLength ?? 1, r = e?.maxChunkSize ?? g, o = e?.maxLength ?? _, s = e?.maxRecycledLength ?? v, c = l.getMaxSegmentLength(this.memory.maxAllocationLength), u = o / r, d = l.getAllocateCount(u, void 0, c), f = l.getAllocateCount(s, void 0, c);
66
- this.pointerStack = new l(this.memory, {
65
+ let t = e?.dataLength ?? 1, n = e?.maxChunkSize ?? g, i = e?.maxLength ?? _, a = e?.maxRecycledLength ?? v, l = r.getMaxSegmentLength(this.memory.maxAllocationLength), u = i / n, d = r.getAllocateCount(u, void 0, l), f = r.getAllocateCount(a, void 0, l);
66
+ this.pointerStack = new r(this.memory, {
67
67
  firstBlock: this.firstBlock.getSubAllocation(y.ALLOCATE_COUNT, d),
68
68
  type: Uint32Array,
69
69
  maxLength: u
70
- }), n(this.firstBlock.data, m, this.pointerStack.pointer), this.recycleStack = new l(this.memory, {
70
+ }), o(this.firstBlock.data, m, this.pointerStack.pointer), this.recycleStack = new r(this.memory, {
71
71
  firstBlock: this.firstBlock.getSubAllocation(y.ALLOCATE_COUNT + d, f),
72
72
  type: Uint32Array,
73
- maxLength: s
74
- }), n(this.firstBlock.data, h, this.recycleStack.pointer);
75
- let p = i(e?.type ?? Uint32Array);
76
- this.type = p, this.dataLength = t, this.maxChunkSize = r;
77
- let b = a(p), x = this.memory.allocUI32(r * t * b);
73
+ maxLength: a
74
+ }), o(this.firstBlock.data, h, this.recycleStack.pointer);
75
+ let p = s(e?.type ?? Uint32Array);
76
+ this.type = p, this.dataLength = t, this.maxChunkSize = n;
77
+ let b = c(p), x = this.memory.allocUI32(n * t * b);
78
78
  this.pointerStack.push(x.pointer);
79
79
  }
80
80
  at(e) {
@@ -118,6 +118,11 @@ var u = 0, d = 1, f = 2, p = 3, m = 4, h = 5, g = 100, _ = 1e6, v = 1e5, y = cla
118
118
  clear() {
119
119
  this.firstBlock.data[u] = 0, this.recycleStack.clear();
120
120
  }
121
+ getRecycledMask() {
122
+ let e = Atomics.load(this.firstBlock.data, u), t = new Uint8Array(e);
123
+ for (let n of this.recycleStack) n < e && (t[n] = 1);
124
+ return t;
125
+ }
121
126
  *[Symbol.iterator]() {
122
127
  let e = {};
123
128
  for (let t of this.recycleStack) e[t] = !0;
@@ -136,22 +141,22 @@ var u = 0, d = 1, f = 2, p = 3, m = 4, h = 5, g = 100, _ = 1e6, v = 1e5, y = cla
136
141
  e !== i && (r = this.getFullDataBlock(a), i = e), yield [a, this.getDataBlock(r, a % t)];
137
142
  }
138
143
  }
139
- getFullDataBlock(t) {
140
- let n = Math.floor(t / this.cachedMaxChunkSize), i = this.cachedFullDataBlock[n];
141
- if (i) return i;
142
- if (n >= this.pointerStack.length) {
143
- s(this.growLock);
144
+ getFullDataBlock(r) {
145
+ let a = Math.floor(r / this.cachedMaxChunkSize), o = this.cachedFullDataBlock[a];
146
+ if (o) return o;
147
+ if (a >= this.pointerStack.length) {
148
+ t(this.growLock);
144
149
  try {
145
- for (; n >= this.pointerStack.length;) {
150
+ for (; a >= this.pointerStack.length;) {
146
151
  let e = this.memory.allocUI32(this.cachedMaxChunkSize * this.cachedDataLength * this.cachedByteMultipler);
147
152
  this.pointerStack.push(e.pointer);
148
153
  }
149
154
  } finally {
150
- c(this.growLock);
155
+ n(this.growLock);
151
156
  }
152
157
  }
153
- let a = new r(this.memory, e(this.pointerStack.at(n), this.memory.positionBits)), l = this.cachedDataLength * this.cachedMaxChunkSize, u = o(this.cachedType, a.data.buffer, a.bufferByteOffset, l);
154
- return this.cachedFullDataBlock[n] = u, u;
158
+ let s = new e(this.memory, i(this.pointerStack.at(a), this.memory.positionBits)), c = this.cachedDataLength * this.cachedMaxChunkSize, u = l(this.cachedType, s.data.buffer, s.bufferByteOffset, c);
159
+ return this.cachedFullDataBlock[a] = u, u;
155
160
  }
156
161
  getDataBlock(e, t) {
157
162
  let n = this.cachedDataLength, r = t * n;
@@ -159,14 +164,13 @@ var u = 0, d = 1, f = 2, p = 3, m = 4, h = 5, g = 100, _ = 1e6, v = 1e5, y = cla
159
164
  }
160
165
  free() {
161
166
  this.recycleStack.free();
162
- for (let t of this.pointerStack) new r(this.memory, e(t, this.memory.positionBits)).free();
167
+ for (let t of this.pointerStack) new e(this.memory, i(t, this.memory.positionBits)).free();
163
168
  this.pointerStack.free(), this.ownsFirstBlock && this.firstBlock.free();
164
169
  }
165
170
  getSharedMemory() {
166
171
  return { firstBlock: this.firstBlock.getSharedMemory() };
167
172
  }
168
173
  };
169
- //#endregion
170
174
  export { y as default };
171
175
 
172
176
  //# sourceMappingURL=shared-pool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-pool.js","names":["AllocatedMemory","SharedStack","LENGTH_INDEX","TYPE_INDEX","MAX_CHUNK_SIZE_INDEX","GROW_LOCK_INDEX","POINTER_STACK_INDEX","RECYCLE_STACK_INDEX","DEFAULT_MAX_CHUNK_SIZE","DEFAULT_MAX_LENGTH","DEFAULT_MAX_RECYCLED_LENGTH","SharedPool","maxChunkSize","config","maxLength","maxRecycledLength","maxSegmentLength","memory","pointerStackAllocateCount","recycleStackAllocateCount","value","total","pointer","getPointer","loadRawPointer","getByteMultipler","dataLength","pointerStackMaxLength","storeRawPointer","typeCode","getArrayTypeCode","byteMultipler","firstArray","dataBlock","index","dataIndex","isSingleValue","values","newIndex","startIndex","i","count","recycledValues","length","dataBlockIndex","newDataBlockIndex","pointerIndex","cachedDataBlock","newArray","array","blockLength","data","makeArrayView","start","rawData"],"sources":["../src/shared-pool.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport { lock, unlock } from './lock/simple-lock';\nimport type MemoryHeap from './memory-heap';\nimport SharedStack from './shared-stack';\nimport { getPointer, loadRawPointer, storeRawPointer } from './utils/pointer';\nimport { getArrayTypeCode, getByteMultipler, makeArrayView, type NumericArray, type NumericArrayIO, type TypedArrayConstructor } from './utils/array-type';\n\nconst LENGTH_INDEX = 0;\nconst TYPE_INDEX = 1;\nconst MAX_CHUNK_SIZE_INDEX = 2;\n// Guards appending a chunk pointer so only one thread grows the pointer stack at a time\nconst GROW_LOCK_INDEX = 3;\n// Pointers to the two backing SharedStacks (their own firstBlocks): the chunk pointers and the recycled indexes\nconst POINTER_STACK_INDEX = 4;\nconst RECYCLE_STACK_INDEX = 5;\n\nconst DEFAULT_MAX_CHUNK_SIZE = 100;\nconst DEFAULT_MAX_LENGTH = 1_000_000;\nconst DEFAULT_MAX_RECYCLED_LENGTH = 100_000;\n\n// Array with stable indexes and maximum contiguous memory sizes (necessary to fit large data sets into max 1MB buffers).\n// The chunk pointers and the recycled indexes both live in SharedStacks, whose segments are never moved or freed once\n// published, so concurrent readers never touch memory that is being reclaimed.\n// https://plflib.org/colony.htm for future enhancements - it seems to be an optimized version of what we were aiming for with this\nexport default class SharedPool<T extends NumericArray = Uint32Array> implements Iterable<T> {\n\tstatic readonly ALLOCATE_COUNT = 6;\n\n\t// u32s a pool with this config needs for its firstBlock, including both inlined stacks. Lets an owner (e.g.\n\t// SharedQuadtree) reserve one contiguous slice and hand it back through the config's firstBlock to inline the pool.\n\tstatic getAllocateCount(memory: MemoryHeap, config?: SharedPoolConfig<NumericArray>): number {\n\t\tlet maxChunkSize = config?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\t\tlet maxLength = config?.maxLength ?? DEFAULT_MAX_LENGTH;\n\t\tlet maxRecycledLength = config?.maxRecycledLength ?? DEFAULT_MAX_RECYCLED_LENGTH;\n\t\tlet maxSegmentLength = SharedStack.getMaxSegmentLength(memory.maxAllocationLength);\n\t\tlet pointerStackAllocateCount = SharedStack.getAllocateCount(maxLength / maxChunkSize, undefined, maxSegmentLength);\n\t\tlet recycleStackAllocateCount = SharedStack.getAllocateCount(maxRecycledLength, undefined, maxSegmentLength);\n\t\treturn SharedPool.ALLOCATE_COUNT + pointerStackAllocateCount + recycleStackAllocateCount;\n\t}\n\n\tprivate memory: MemoryHeap;\n\n\t// Current Length, Type/DataLength, MaxChunkLength, Grow lock, Pointer stack, Recycle stack\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\tprivate growLock: Int32Array;\n\tprivate pointerStack!: SharedStack;\n\tprivate recycleStack!: SharedStack;\n\treadonly maxLength: number;\n\n\t// False when firstBlock is a slice of another structure's memory (e.g. inlined in SharedQuadtree); that owner frees it\n\tprivate ownsFirstBlock: boolean;\n\n\t// Chunk views cached by pointer index. An array (dense, small integer keys) resolves faster than an object on the hot\n\t// get/set path and never needs rehashing.\n\tprivate cachedFullDataBlock: Array<T | undefined> = [];\n\n\t// Config is written once at construction and never mutated, so it is cached in plain fields\n\tprivate readonly cachedMaxChunkSize: number;\n\tprivate readonly cachedDataLength: number;\n\tprivate readonly cachedType: number;\n\tprivate readonly cachedByteMultipler: number;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX) - this.recycleStack.length;\n\t}\n\tget maxChunkSize(): number {\n\t\treturn this.cachedMaxChunkSize;\n\t}\n\tprivate set maxChunkSize(value: number) {\n\t\tAtomics.store(this.firstBlock.data, MAX_CHUNK_SIZE_INDEX, value);\n\t}\n\n\tget type(): number {\n\t\treturn this.cachedType;\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget dataLength(): number {\n\t\treturn this.cachedDataLength;\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tget bufferLength(): number {\n\t\treturn this.cachedMaxChunkSize * this.pointerStack.length;\n\t}\n\tget byteMultipler(): number {\n\t\treturn this.cachedByteMultipler;\n\t}\n\n\t// Own internal memory (which already includes both stacks' inlined firstBlocks) plus every chunk buffer and the\n\t// segments each stack has grown. The stacks' usedMemory excludes their inlined firstBlocks, so they aren't double-counted.\n\tget usedMemory(): number {\n\t\tlet total = this.ownsFirstBlock ? this.firstBlock.usedMemory : 0;\n\t\tfor(let pointer of this.pointerStack) {\n\t\t\ttotal += new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits)).usedMemory;\n\t\t}\n\t\treturn total + this.pointerStack.usedMemory + this.recycleStack.usedMemory;\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedPoolConfig<T> | SharedPoolMemory | SharedPoolMemory & SharedPoolConfig<T>) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\t// An AllocatedMemory instance is a caller-reserved slice (e.g. inlined in SharedQuadtree); a plain pointer is the\n\t\t\t// serialized clone path. Taking the instance directly keeps us off the pointer-resolving construction branch.\n\t\t\tthis.firstBlock = config.firstBlock instanceof AllocatedMemory\n\t\t\t\t? config.firstBlock\n\t\t\t\t: new AllocatedMemory(memory, { length: SharedPool.ALLOCATE_COUNT, ...config.firstBlock });\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\t// Memory passed together with config means the caller reserved the firstBlock slot for us to initialize in place\n\t\t\tif('type' in config || 'dataLength' in config || 'maxLength' in config || 'maxChunkSize' in config || 'maxRecycledLength' in config) {\n\t\t\t\tthis.initialize(config);\n\t\t\t\tthis.ownsFirstBlock = false;\n\t\t\t} else {\n\t\t\t\tthis.pointerStack = new SharedStack(memory, {\n\t\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, POINTER_STACK_INDEX), memory.positionBits),\n\t\t\t\t});\n\t\t\t\tthis.recycleStack = new SharedStack(memory, {\n\t\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, RECYCLE_STACK_INDEX), memory.positionBits),\n\t\t\t\t});\n\t\t\t\tthis.ownsFirstBlock = true;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.firstBlock = memory.allocUI32(SharedPool.getAllocateCount(memory, config));\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\t\t\tthis.initialize(config);\n\t\t\tthis.ownsFirstBlock = true;\n\t\t}\n\n\t\tthis.cachedType = this.uint16Array[0];\n\t\tthis.cachedDataLength = Math.max(1, this.uint16Array[1]);\n\t\tthis.cachedMaxChunkSize = this.firstBlock.data[MAX_CHUNK_SIZE_INDEX];\n\t\tthis.cachedByteMultipler = getByteMultipler(this.cachedType);\n\t\tthis.maxLength = this.cachedMaxChunkSize * this.pointerStack.maxLength;\n\n\t\tthis.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + GROW_LOCK_INDEX * Uint32Array.BYTES_PER_ELEMENT, 1);\n\t}\n\n\t// Lay out the two inlined stacks (their firstBlocks sliced from ours), record their pointers, and seed the first chunk.\n\t// firstBlock and uint16Array must already be set. Used by both the fresh-alloc path and the inline-in-place path.\n\tprivate initialize(config?: SharedPoolConfig<T>) {\n\t\tlet dataLength = config?.dataLength ?? 1;\n\t\tlet maxChunkSize = config?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\t\tlet maxLength = config?.maxLength ?? DEFAULT_MAX_LENGTH;\n\t\tlet maxRecycledLength = config?.maxRecycledLength ?? DEFAULT_MAX_RECYCLED_LENGTH;\n\n\t\t// Each stack sizes its inlined firstBlock from its own maxLength, so compute both up front to lay them out. The\n\t\t// stacks cap their segments at what a buffer can hold, so size the inlined blocks against that same cap.\n\t\tlet maxSegmentLength = SharedStack.getMaxSegmentLength(this.memory.maxAllocationLength);\n\t\tlet pointerStackMaxLength = maxLength / maxChunkSize;\n\t\tlet pointerStackAllocateCount = SharedStack.getAllocateCount(pointerStackMaxLength, undefined, maxSegmentLength);\n\t\tlet recycleStackAllocateCount = SharedStack.getAllocateCount(maxRecycledLength, undefined, maxSegmentLength);\n\n\t\t// Inline both stacks' firstBlocks right after the pool header so the whole spine is one contiguous allocation\n\t\tthis.pointerStack = new SharedStack(this.memory, {\n\t\t\tfirstBlock: this.firstBlock.getSubAllocation(SharedPool.ALLOCATE_COUNT, pointerStackAllocateCount),\n\t\t\ttype: Uint32Array,\n\t\t\tmaxLength: pointerStackMaxLength,\n\t\t});\n\t\tstoreRawPointer(this.firstBlock.data, POINTER_STACK_INDEX, this.pointerStack.pointer);\n\t\tthis.recycleStack = new SharedStack(this.memory, {\n\t\t\tfirstBlock: this.firstBlock.getSubAllocation(SharedPool.ALLOCATE_COUNT + pointerStackAllocateCount, recycleStackAllocateCount),\n\t\t\ttype: Uint32Array,\n\t\t\tmaxLength: maxRecycledLength,\n\t\t});\n\t\tstoreRawPointer(this.firstBlock.data, RECYCLE_STACK_INDEX, this.recycleStack.pointer);\n\n\t\tlet typeCode = getArrayTypeCode(config?.type ?? Uint32Array);\n\t\tthis.type = typeCode;\n\t\tthis.dataLength = dataLength;\n\t\tthis.maxChunkSize = maxChunkSize;\n\n\t\tlet byteMultipler = getByteMultipler(typeCode);\n\t\tlet firstArray = this.memory.allocUI32(maxChunkSize * dataLength * byteMultipler);\n\t\tthis.pointerStack.push(firstArray.pointer);\n\t}\n\n\tat(index: number): T {\n\t\tlet dataBlock = this.getFullDataBlock(index);\n\t\treturn this.getDataBlock(dataBlock, index % this.cachedMaxChunkSize);\n\t}\n\tget(index: number, dataIndex = 0): T[number] {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tif(dataIndex >= dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${dataLength}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(index) as NumericArrayIO;\n\t\treturn dataBlock[(index % this.cachedMaxChunkSize) * dataLength + dataIndex];\n\t}\n\tset(index: number, dataIndex: number, value: T[number]) {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tif(dataIndex >= dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${dataLength}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(index) as NumericArrayIO;\n\t\tdataBlock[(index % this.cachedMaxChunkSize) * dataLength + dataIndex] = value;\n\t}\n\n\t// Resolve the chunk view holding an index once. Callers touching several fields of the same record read/write straight\n\t// into this view at blockOffset(index) + fieldIndex, avoiding a repeated chunk lookup per field.\n\tblockFor(index: number): T {\n\t\treturn this.getFullDataBlock(index);\n\t}\n\t// Base slot of a record within the view blockFor(index) returns.\n\tblockOffset(index: number): number {\n\t\treturn (index % this.cachedMaxChunkSize) * this.cachedDataLength;\n\t}\n\n\tpush(values: T[number] | Array<T[number]>): number {\n\t\tlet dataLength = this.cachedDataLength;\n\t\tconst isSingleValue = typeof values !== 'object';\n\t\tif(!isSingleValue && values.length > dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${dataLength} dataLength`);\n\t\t}\n\n\t\t// Reuse a recycled index if one is available. pop() can come back undefined when another thread drained the last\n\t\t// slot between our two calls, so fall through to a fresh index rather than trusting a length() read\n\t\tlet newIndex = this.recycleStack.length === 0 ? undefined : this.recycleStack.pop();\n\t\tif(newIndex === undefined) {\n\t\t\tnewIndex = Atomics.add(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(newIndex) as NumericArrayIO;\n\t\tlet startIndex = dataLength * (newIndex % this.cachedMaxChunkSize);\n\t\tif(isSingleValue) {\n\t\t\tdataBlock[startIndex] = values;\n\t\t} else {\n\t\t\tfor(let i = 0; i < values.length; i++) {\n\t\t\t\tdataBlock[startIndex + i] = values[i];\n\t\t\t}\n\t\t}\n\n\t\treturn newIndex;\n\t}\n\n\treserveContiguous(count: number): number {\n\t\tif(!Number.isInteger(count) || count < 0) {\n\t\t\tthrow new Error(`Can't reserve ${count} pool entries`);\n\t\t}\n\t\treturn Atomics.add(this.firstBlock.data, LENGTH_INDEX, count);\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tthis.recycleStack.push(index);\n\t}\n\n\tclear() {\n\t\tthis.firstBlock.data[LENGTH_INDEX] = 0;\n\t\tthis.recycleStack.clear();\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycleStack) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tconst maxChunkSize = this.cachedMaxChunkSize;\n\t\t// Snapshot the length once - iteration over a concurrently mutated pool is a snapshot anyway, and re-loading the\n\t\t// atomic every step is pure overhead\n\t\tconst length = Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < length; i++) {\n\t\t\tif(!recycledValues[i]) {\n\t\t\t\tlet newDataBlockIndex = Math.floor(i / maxChunkSize);\n\t\t\t\tif(newDataBlockIndex !== dataBlockIndex) {\n\t\t\t\t\tdataBlock = this.getFullDataBlock(i);\n\t\t\t\t\tdataBlockIndex = newDataBlockIndex;\n\t\t\t\t}\n\t\t\t\tyield this.getDataBlock(dataBlock, i % maxChunkSize);\n\t\t\t}\n\t\t}\n\t}\n\n\t*entries(): IterableIterator<[number, T]> {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycleStack) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tconst maxChunkSize = this.cachedMaxChunkSize;\n\t\tconst length = Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < length; i++) {\n\t\t\tif(!recycledValues[i]) {\n\t\t\t\tlet newDataBlockIndex = Math.floor(i / maxChunkSize);\n\t\t\t\tif(newDataBlockIndex !== dataBlockIndex) {\n\t\t\t\t\tdataBlock = this.getFullDataBlock(i);\n\t\t\t\t\tdataBlockIndex = newDataBlockIndex;\n\t\t\t\t}\n\t\t\t\tyield [i, this.getDataBlock(dataBlock, i % maxChunkSize)];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getFullDataBlock(index: number) {\n\t\tlet pointerIndex = Math.floor(index / this.cachedMaxChunkSize);\n\t\tlet cachedDataBlock = this.cachedFullDataBlock[pointerIndex];\n\t\tif(cachedDataBlock) {\n\t\t\treturn cachedDataBlock;\n\t\t}\n\t\tif(pointerIndex >= this.pointerStack.length) {\n\t\t\t// Only let a single thread append a new chunk at a time - otherwise two concurrent inserts landing in a new\n\t\t\t// chunk would each allocate + push a buffer, orphaning one and leaking memory\n\t\t\tlock(this.growLock);\n\t\t\ttry {\n\t\t\t\t// Re-check under the lock: another thread may have already appended the chunk while we were waiting\n\t\t\t\twhile(pointerIndex >= this.pointerStack.length) {\n\t\t\t\t\tlet newArray = this.memory.allocUI32(this.cachedMaxChunkSize * this.cachedDataLength * this.cachedByteMultipler);\n\t\t\t\t\tthis.pointerStack.push(newArray.pointer);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tunlock(this.growLock);\n\t\t\t}\n\t\t}\n\n\t\tlet array = new AllocatedMemory(this.memory, getPointer(this.pointerStack.at(pointerIndex), this.memory.positionBits));\n\n\t\tlet blockLength = this.cachedDataLength * this.cachedMaxChunkSize;\n\t\tlet data = makeArrayView(this.cachedType, array.data.buffer, array.bufferByteOffset, blockLength) as T;\n\n\t\tthis.cachedFullDataBlock[pointerIndex] = data;\n\t\treturn data;\n\t}\n\n\tprivate getDataBlock(rawData: T, index: number): T {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tconst start = index * dataLength;\n\t\treturn rawData.subarray(start, start + dataLength) as T;\n\t}\n\n\tfree() {\n\t\tthis.recycleStack.free();\n\n\t\tfor(let pointer of this.pointerStack) {\n\t\t\tlet memory = new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits));\n\t\t\tmemory.free();\n\t\t}\n\t\tthis.pointerStack.free();\n\t\tif(this.ownsFirstBlock) {\n\t\t\tthis.firstBlock.free();\n\t\t}\n\t}\n\n\tgetSharedMemory(): SharedPoolMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedPoolConfig<T extends NumericArray> {\n\tmaxChunkSize?: number\n\tmaxLength?: number\n\tmaxRecycledLength?: number\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n}\ninterface SharedPoolMemory {\n\tfirstBlock: SharedAllocatedMemory | AllocatedMemory\n}\n\nexport type { SharedPoolConfig, SharedPoolMemory };\n"],"mappings":";;;;;;AAQA,IAAME,IAAe,GACfC,IAAa,GACbC,IAAuB,GAEvBC,IAAkB,GAElBC,IAAsB,GACtBC,IAAsB,GAEtBC,IAAyB,KACzBC,IAAqB,KACrBC,IAA8B,KAMfC,IAArB,MAAqBA,EAAwE;CAC5F,OAAgB,iBAAiB;CAIjC,OAAO,iBAAiB,GAAoB,GAAiD;EAC5F,IAAIC,IAAeC,GAAQ,gBAAgBL,GACvCM,IAAYD,GAAQ,aAAaJ,GACjCM,IAAoBF,GAAQ,qBAAqBH,GACjDM,IAAmBf,EAAY,oBAAoBgB,EAAO,mBAAmB,GAC7EC,IAA4BjB,EAAY,iBAAiBa,IAAYF,GAAc,KAAA,GAAWI,CAAgB,GAC9GG,IAA4BlB,EAAY,iBAAiBc,GAAmB,KAAA,GAAWC,CAAgB;EAC3G,OAAOL,EAAW,iBAAiBO,IAA4BC;CAChE;CAEA;CAGA;CACA;CACA;CACA;CACA;CACA;CAGA;CAIA,sBAAoD,CAAC;CAGrD;CACA;CACA;CACA;CAEA,IAAI,SAAiB;EACpB,OAAO,QAAQ,KAAK,KAAK,WAAW,MAAMjB,CAAY,IAAI,KAAK,aAAa;CAC7E;CACA,IAAI,eAAuB;EAC1B,OAAO,KAAK;CACb;CACA,IAAY,aAAa,GAAe;EACvC,QAAQ,MAAM,KAAK,WAAW,MAAME,GAAsBgB,CAAK;CAChE;CAEA,IAAI,OAAe;EAClB,OAAO,KAAK;CACb;CACA,IAAY,KAAK,GAAe;EAC/B,QAAQ,MAAM,KAAK,aAAa,GAAGA,CAAK;CACzC;CACA,IAAI,aAAqB;EACxB,OAAO,KAAK;CACb;CACA,IAAY,WAAW,GAAe;EACrC,QAAQ,MAAM,KAAK,aAAa,GAAGA,CAAK;CACzC;CAEA,IAAI,eAAuB;EAC1B,OAAO,KAAK,qBAAqB,KAAK,aAAa;CACpD;CACA,IAAI,gBAAwB;EAC3B,OAAO,KAAK;CACb;CAIA,IAAI,aAAqB;EACxB,IAAIC,IAAQ,KAAK,iBAAiB,KAAK,WAAW,aAAa;EAC/D,KAAI,IAAIC,KAAW,KAAK,cACvB,KAAS,IAAItB,EAAgB,KAAK,QAAQuB,EAAWD,GAAS,KAAK,OAAO,YAAY,CAAC,CAAC,CAAC;EAE1F,OAAOD,IAAQ,KAAK,aAAa,aAAa,KAAK,aAAa;CACjE;CAEA,YAAY,GAAoB,GAA0F;EAqCzH,AApCA,KAAK,SAASJ,GAEXJ,KAAU,gBAAgBA,KAG5B,KAAK,aAAaA,EAAO,sBAAsBb,IAC5Ca,EAAO,aACP,IAAIb,EAAgBiB,GAAQ;GAAE,QAAQN,EAAW;GAAgB,GAAGE,EAAO;EAAW,CAAC,GAC1F,KAAK,cAAc,IAAI,YAAY,KAAK,WAAW,KAAK,QAAQ,KAAK,WAAW,mBAAmBV,IAAa,YAAY,mBAAmB,CAAC,GAG7I,UAAUU,KAAU,gBAAgBA,KAAU,eAAeA,KAAU,kBAAkBA,KAAU,uBAAuBA,KAC5H,KAAK,WAAWA,CAAM,GACtB,KAAK,iBAAiB,OAEtB,KAAK,eAAe,IAAIZ,EAAYgB,GAAQ,EAC3C,YAAYM,EAAWC,EAAe,KAAK,WAAW,MAAMlB,CAAmB,GAAGW,EAAO,YAAY,EACtG,CAAC,GACD,KAAK,eAAe,IAAIhB,EAAYgB,GAAQ,EAC3C,YAAYM,EAAWC,EAAe,KAAK,WAAW,MAAMjB,CAAmB,GAAGU,EAAO,YAAY,EACtG,CAAC,GACD,KAAK,iBAAiB,QAGvB,KAAK,aAAaA,EAAO,UAAUN,EAAW,iBAAiBM,GAAQJ,CAAM,CAAC,GAC9E,KAAK,cAAc,IAAI,YAAY,KAAK,WAAW,KAAK,QAAQ,KAAK,WAAW,mBAAmBV,IAAa,YAAY,mBAAmB,CAAC,GAChJ,KAAK,WAAWU,CAAM,GACtB,KAAK,iBAAiB,KAGvB,KAAK,aAAa,KAAK,YAAY,IACnC,KAAK,mBAAmB,KAAK,IAAI,GAAG,KAAK,YAAY,EAAE,GACvD,KAAK,qBAAqB,KAAK,WAAW,KAAKT,IAC/C,KAAK,sBAAsBqB,EAAiB,KAAK,UAAU,GAC3D,KAAK,YAAY,KAAK,qBAAqB,KAAK,aAAa,WAE7D,KAAK,WAAW,IAAI,WAAW,KAAK,WAAW,KAAK,QAAQ,KAAK,WAAW,mBAAmBpB,IAAkB,YAAY,mBAAmB,CAAC;CAClJ;CAIA,WAAmB,GAA8B;EAChD,IAAIqB,IAAab,GAAQ,cAAc,GACnCD,IAAeC,GAAQ,gBAAgBL,GACvCM,IAAYD,GAAQ,aAAaJ,GACjCM,IAAoBF,GAAQ,qBAAqBH,GAIjDM,IAAmBf,EAAY,oBAAoB,KAAK,OAAO,mBAAmB,GAClF0B,IAAwBb,IAAYF,GACpCM,IAA4BjB,EAAY,iBAAiB0B,GAAuB,KAAA,GAAWX,CAAgB,GAC3GG,IAA4BlB,EAAY,iBAAiBc,GAAmB,KAAA,GAAWC,CAAgB;EAc3G,AAXA,KAAK,eAAe,IAAIf,EAAY,KAAK,QAAQ;GAChD,YAAY,KAAK,WAAW,iBAAiBU,EAAW,gBAAgBO,CAAyB;GACjG,MAAM;GACN,WAAWS;EACZ,CAAC,GACDC,EAAgB,KAAK,WAAW,MAAMtB,GAAqB,KAAK,aAAa,OAAO,GACpF,KAAK,eAAe,IAAIL,EAAY,KAAK,QAAQ;GAChD,YAAY,KAAK,WAAW,iBAAiBU,EAAW,iBAAiBO,GAA2BC,CAAyB;GAC7H,MAAM;GACN,WAAWJ;EACZ,CAAC,GACDa,EAAgB,KAAK,WAAW,MAAMrB,GAAqB,KAAK,aAAa,OAAO;EAEpF,IAAIsB,IAAWC,EAAiBjB,GAAQ,QAAQ,WAAW;EAG3D,AAFA,KAAK,OAAOgB,GACZ,KAAK,aAAaH,GAClB,KAAK,eAAed;EAEpB,IAAImB,IAAgBN,EAAiBI,CAAQ,GACzCG,IAAa,KAAK,OAAO,UAAUpB,IAAec,IAAaK,CAAa;EAChF,KAAK,aAAa,KAAKC,EAAW,OAAO;CAC1C;CAEA,GAAG,GAAkB;EACpB,IAAIC,IAAY,KAAK,iBAAiBC,CAAK;EAC3C,OAAO,KAAK,aAAaD,GAAWC,IAAQ,KAAK,kBAAkB;CACpE;CACA,IAAI,GAAe,IAAY,GAAc;EAC5C,IAAMR,IAAa,KAAK;EACxB,IAAGS,KAAaT,GACf,MAAU,MAAM,GAAGS,EAAU,+BAA+BT,GAAY;EAIzE,OADgB,KAAK,iBAAiBQ,CAC/B,CAAA,CAAWA,IAAQ,KAAK,qBAAsBR,IAAaS;CACnE;CACA,IAAI,GAAe,GAAmB,GAAkB;EACvD,IAAMT,IAAa,KAAK;EACxB,IAAGS,KAAaT,GACf,MAAU,MAAM,GAAGS,EAAU,+BAA+BT,GAAY;EAGzE,IAAIO,IAAY,KAAK,iBAAiBC,CAAK;EAC3C,EAAWA,IAAQ,KAAK,qBAAsBR,IAAaS,KAAaf;CACzE;CAIA,SAAS,GAAkB;EAC1B,OAAO,KAAK,iBAAiBc,CAAK;CACnC;CAEA,YAAY,GAAuB;EAClC,OAAQA,IAAQ,KAAK,qBAAsB,KAAK;CACjD;CAEA,KAAK,GAA8C;EAClD,IAAIR,IAAa,KAAK,kBAChBU,IAAgB,OAAOC,KAAW;EACxC,IAAG,CAACD,KAAiBC,EAAO,SAASX,GACpC,MAAU,MAAM,gBAAgBW,EAAO,OAAO,6BAA6BX,EAAW,YAAY;EAKnG,IAAIY,IAAW,KAAK,aAAa,WAAW,IAAI,KAAA,IAAY,KAAK,aAAa,IAAI;EAClF,AAAGA,MAAa,KAAA,MACf,IAAW,QAAQ,IAAI,KAAK,WAAW,MAAMpC,GAAc,CAAC;EAG7D,IAAI+B,IAAY,KAAK,iBAAiBK,CAAQ,GAC1CC,IAAab,KAAcY,IAAW,KAAK;EAC/C,IAAGF,GACF,EAAUG,KAAcF;OAExB,KAAI,IAAIG,IAAI,GAAGA,IAAIH,EAAO,QAAQ,KACjC,EAAUE,IAAaC,KAAKH,EAAOG;EAIrC,OAAOF;CACR;CAEA,kBAAkB,GAAuB;EACxC,IAAG,CAAC,OAAO,UAAUG,CAAK,KAAKA,IAAQ,GACtC,MAAU,MAAM,iBAAiBA,EAAM,cAAc;EAEtD,OAAO,QAAQ,IAAI,KAAK,WAAW,MAAMvC,GAAcuC,CAAK;CAC7D;CAEA,YAAY,GAAe;EAC1B,KAAK,aAAa,KAAKP,CAAK;CAC7B;CAEA,QAAQ;EAEP,AADA,KAAK,WAAW,KAAKhC,KAAgB,GACrC,KAAK,aAAa,MAAM;CACzB;CAEA,EAAE,OAAO,YAAY;EACpB,IAAMwC,IAA0C,CAAC;EACjD,KAAI,IAAItB,KAAS,KAAK,cACrB,EAAeA,KAAS;EAGzB,IAAMR,IAAe,KAAK,oBAGpB+B,IAAS,QAAQ,KAAK,KAAK,WAAW,MAAMzC,CAAY,GAC1D+B,IAAY,KAAK,iBAAiB,CAAC,GACnCW,IAAiB;EACrB,KAAI,IAAIJ,IAAI,GAAGA,IAAIG,GAAQ,KAC1B,IAAG,CAACD,EAAeF,IAAI;GACtB,IAAIK,IAAoB,KAAK,MAAML,IAAI5B,CAAY;GAKnD,AAJGiC,MAAsBD,MACxB,IAAY,KAAK,iBAAiBJ,CAAC,GACnC,IAAiBK,IAElB,MAAM,KAAK,aAAaZ,GAAWO,IAAI5B,CAAY;EACpD;CAEF;CAEA,CAAC,UAAyC;EACzC,IAAM8B,IAA0C,CAAC;EACjD,KAAI,IAAItB,KAAS,KAAK,cACrB,EAAeA,KAAS;EAGzB,IAAMR,IAAe,KAAK,oBACpB+B,IAAS,QAAQ,KAAK,KAAK,WAAW,MAAMzC,CAAY,GAC1D+B,IAAY,KAAK,iBAAiB,CAAC,GACnCW,IAAiB;EACrB,KAAI,IAAIJ,IAAI,GAAGA,IAAIG,GAAQ,KAC1B,IAAG,CAACD,EAAeF,IAAI;GACtB,IAAIK,IAAoB,KAAK,MAAML,IAAI5B,CAAY;GAKnD,AAJGiC,MAAsBD,MACxB,IAAY,KAAK,iBAAiBJ,CAAC,GACnC,IAAiBK,IAElB,MAAM,CAACL,GAAG,KAAK,aAAaP,GAAWO,IAAI5B,CAAY,CAAC;EACzD;CAEF;CAEA,iBAAyB,GAAe;EACvC,IAAIkC,IAAe,KAAK,MAAMZ,IAAQ,KAAK,kBAAkB,GACzDa,IAAkB,KAAK,oBAAoBD;EAC/C,IAAGC,GACF,OAAOA;EAER,IAAGD,KAAgB,KAAK,aAAa,QAAQ;GAG5C,EAAK,KAAK,QAAQ;GAClB,IAAI;IAEH,OAAMA,KAAgB,KAAK,aAAa,SAAQ;KAC/C,IAAIE,IAAW,KAAK,OAAO,UAAU,KAAK,qBAAqB,KAAK,mBAAmB,KAAK,mBAAmB;KAC/G,KAAK,aAAa,KAAKA,EAAS,OAAO;IACxC;GACD,UAAU;IACT,EAAO,KAAK,QAAQ;GACrB;EACD;EAEA,IAAIC,IAAQ,IAAIjD,EAAgB,KAAK,QAAQuB,EAAW,KAAK,aAAa,GAAGuB,CAAY,GAAG,KAAK,OAAO,YAAY,CAAC,GAEjHI,IAAc,KAAK,mBAAmB,KAAK,oBAC3CC,IAAOC,EAAc,KAAK,YAAYH,EAAM,KAAK,QAAQA,EAAM,kBAAkBC,CAAW;EAGhG,OADA,KAAK,oBAAoBJ,KAAgBK,GAClCA;CACR;CAEA,aAAqB,GAAY,GAAkB;EAClD,IAAMzB,IAAa,KAAK,kBAClB2B,IAAQnB,IAAQR;EACtB,OAAO4B,EAAQ,SAASD,GAAOA,IAAQ3B,CAAU;CAClD;CAEA,OAAO;EACN,KAAK,aAAa,KAAK;EAEvB,KAAI,IAAIJ,KAAW,KAAK,cAEvB,IADiBtB,EAAgB,KAAK,QAAQuB,EAAWD,GAAS,KAAK,OAAO,YAAY,CAC1F,CAAA,CAAO,KAAK;EAGb,AADA,KAAK,aAAa,KAAK,GACpB,KAAK,kBACP,KAAK,WAAW,KAAK;CAEvB;CAEA,kBAAoC;EACnC,OAAO,EACN,YAAY,KAAK,WAAW,gBAAgB,EAC7C;CACD;AACD"}
1
+ {"version":3,"file":"shared-pool.js","names":["AllocatedMemory","SharedStack","LENGTH_INDEX","TYPE_INDEX","MAX_CHUNK_SIZE_INDEX","GROW_LOCK_INDEX","POINTER_STACK_INDEX","RECYCLE_STACK_INDEX","DEFAULT_MAX_CHUNK_SIZE","DEFAULT_MAX_LENGTH","DEFAULT_MAX_RECYCLED_LENGTH","SharedPool","maxChunkSize","config","maxLength","maxRecycledLength","maxSegmentLength","memory","pointerStackAllocateCount","recycleStackAllocateCount","value","total","pointer","getPointer","loadRawPointer","getByteMultipler","dataLength","pointerStackMaxLength","storeRawPointer","typeCode","getArrayTypeCode","byteMultipler","firstArray","dataBlock","index","dataIndex","isSingleValue","values","newIndex","startIndex","i","count","length","recycled","recycledValues","dataBlockIndex","newDataBlockIndex","pointerIndex","cachedDataBlock","newArray","array","blockLength","data","makeArrayView","start","rawData"],"sources":["../src/shared-pool.ts"],"sourcesContent":["import type { SharedAllocatedMemory } from './allocated-memory';\nimport AllocatedMemory from './allocated-memory';\nimport { lock, unlock } from './lock/simple-lock';\nimport type MemoryHeap from './memory-heap';\nimport SharedStack from './shared-stack';\nimport { getPointer, loadRawPointer, storeRawPointer } from './utils/pointer';\nimport { getArrayTypeCode, getByteMultipler, makeArrayView, type NumericArray, type NumericArrayIO, type TypedArrayConstructor } from './utils/array-type';\n\nconst LENGTH_INDEX = 0;\nconst TYPE_INDEX = 1;\nconst MAX_CHUNK_SIZE_INDEX = 2;\n// Guards appending a chunk pointer so only one thread grows the pointer stack at a time\nconst GROW_LOCK_INDEX = 3;\n// Pointers to the two backing SharedStacks (their own firstBlocks): the chunk pointers and the recycled indexes\nconst POINTER_STACK_INDEX = 4;\nconst RECYCLE_STACK_INDEX = 5;\n\nconst DEFAULT_MAX_CHUNK_SIZE = 100;\nconst DEFAULT_MAX_LENGTH = 1_000_000;\nconst DEFAULT_MAX_RECYCLED_LENGTH = 100_000;\n\n// Array with stable indexes and maximum contiguous memory sizes (necessary to fit large data sets into max 1MB buffers).\n// The chunk pointers and the recycled indexes both live in SharedStacks, whose segments are never moved or freed once\n// published, so concurrent readers never touch memory that is being reclaimed.\n// https://plflib.org/colony.htm for future enhancements - it seems to be an optimized version of what we were aiming for with this\nexport default class SharedPool<T extends NumericArray = Uint32Array> implements Iterable<T> {\n\tstatic readonly ALLOCATE_COUNT = 6;\n\n\t// u32s a pool with this config needs for its firstBlock, including both inlined stacks. Lets an owner (e.g.\n\t// SharedQuadtree) reserve one contiguous slice and hand it back through the config's firstBlock to inline the pool.\n\tstatic getAllocateCount(memory: MemoryHeap, config?: SharedPoolConfig<NumericArray>): number {\n\t\tlet maxChunkSize = config?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\t\tlet maxLength = config?.maxLength ?? DEFAULT_MAX_LENGTH;\n\t\tlet maxRecycledLength = config?.maxRecycledLength ?? DEFAULT_MAX_RECYCLED_LENGTH;\n\t\tlet maxSegmentLength = SharedStack.getMaxSegmentLength(memory.maxAllocationLength);\n\t\tlet pointerStackAllocateCount = SharedStack.getAllocateCount(maxLength / maxChunkSize, undefined, maxSegmentLength);\n\t\tlet recycleStackAllocateCount = SharedStack.getAllocateCount(maxRecycledLength, undefined, maxSegmentLength);\n\t\treturn SharedPool.ALLOCATE_COUNT + pointerStackAllocateCount + recycleStackAllocateCount;\n\t}\n\n\tprivate memory: MemoryHeap;\n\n\t// Current Length, Type/DataLength, MaxChunkLength, Grow lock, Pointer stack, Recycle stack\n\tprivate firstBlock: AllocatedMemory;\n\tprivate uint16Array: Uint16Array;\n\tprivate growLock: Int32Array;\n\tprivate pointerStack!: SharedStack;\n\tprivate recycleStack!: SharedStack;\n\treadonly maxLength: number;\n\n\t// False when firstBlock is a slice of another structure's memory (e.g. inlined in SharedQuadtree); that owner frees it\n\tprivate ownsFirstBlock: boolean;\n\n\t// Chunk views cached by pointer index. An array (dense, small integer keys) resolves faster than an object on the hot\n\t// get/set path and never needs rehashing.\n\tprivate cachedFullDataBlock: Array<T | undefined> = [];\n\n\t// Config is written once at construction and never mutated, so it is cached in plain fields\n\tprivate readonly cachedMaxChunkSize: number;\n\tprivate readonly cachedDataLength: number;\n\tprivate readonly cachedType: number;\n\tprivate readonly cachedByteMultipler: number;\n\n\tget length(): number {\n\t\treturn Atomics.load(this.firstBlock.data, LENGTH_INDEX) - this.recycleStack.length;\n\t}\n\tget maxChunkSize(): number {\n\t\treturn this.cachedMaxChunkSize;\n\t}\n\tprivate set maxChunkSize(value: number) {\n\t\tAtomics.store(this.firstBlock.data, MAX_CHUNK_SIZE_INDEX, value);\n\t}\n\n\tget type(): number {\n\t\treturn this.cachedType;\n\t}\n\tprivate set type(value: number) {\n\t\tAtomics.store(this.uint16Array, 0, value);\n\t}\n\tget dataLength(): number {\n\t\treturn this.cachedDataLength;\n\t}\n\tprivate set dataLength(value: number) {\n\t\tAtomics.store(this.uint16Array, 1, value);\n\t}\n\n\tget bufferLength(): number {\n\t\treturn this.cachedMaxChunkSize * this.pointerStack.length;\n\t}\n\tget byteMultipler(): number {\n\t\treturn this.cachedByteMultipler;\n\t}\n\n\t// Own internal memory (which already includes both stacks' inlined firstBlocks) plus every chunk buffer and the\n\t// segments each stack has grown. The stacks' usedMemory excludes their inlined firstBlocks, so they aren't double-counted.\n\tget usedMemory(): number {\n\t\tlet total = this.ownsFirstBlock ? this.firstBlock.usedMemory : 0;\n\t\tfor(let pointer of this.pointerStack) {\n\t\t\ttotal += new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits)).usedMemory;\n\t\t}\n\t\treturn total + this.pointerStack.usedMemory + this.recycleStack.usedMemory;\n\t}\n\n\tconstructor(memory: MemoryHeap, config?: SharedPoolConfig<T> | SharedPoolMemory | SharedPoolMemory & SharedPoolConfig<T>) {\n\t\tthis.memory = memory;\n\n\t\tif(config && 'firstBlock' in config) {\n\t\t\t// An AllocatedMemory instance is a caller-reserved slice (e.g. inlined in SharedQuadtree); a plain pointer is the\n\t\t\t// serialized clone path. Taking the instance directly keeps us off the pointer-resolving construction branch.\n\t\t\tthis.firstBlock = config.firstBlock instanceof AllocatedMemory\n\t\t\t\t? config.firstBlock\n\t\t\t\t: new AllocatedMemory(memory, { length: SharedPool.ALLOCATE_COUNT, ...config.firstBlock });\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\n\t\t\t// Memory passed together with config means the caller reserved the firstBlock slot for us to initialize in place\n\t\t\tif('type' in config || 'dataLength' in config || 'maxLength' in config || 'maxChunkSize' in config || 'maxRecycledLength' in config) {\n\t\t\t\tthis.initialize(config);\n\t\t\t\tthis.ownsFirstBlock = false;\n\t\t\t} else {\n\t\t\t\tthis.pointerStack = new SharedStack(memory, {\n\t\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, POINTER_STACK_INDEX), memory.positionBits),\n\t\t\t\t});\n\t\t\t\tthis.recycleStack = new SharedStack(memory, {\n\t\t\t\t\tfirstBlock: getPointer(loadRawPointer(this.firstBlock.data, RECYCLE_STACK_INDEX), memory.positionBits),\n\t\t\t\t});\n\t\t\t\tthis.ownsFirstBlock = true;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.firstBlock = memory.allocUI32(SharedPool.getAllocateCount(memory, config));\n\t\t\tthis.uint16Array = new Uint16Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + TYPE_INDEX * Uint32Array.BYTES_PER_ELEMENT, 2);\n\t\t\tthis.initialize(config);\n\t\t\tthis.ownsFirstBlock = true;\n\t\t}\n\n\t\tthis.cachedType = this.uint16Array[0];\n\t\tthis.cachedDataLength = Math.max(1, this.uint16Array[1]);\n\t\tthis.cachedMaxChunkSize = this.firstBlock.data[MAX_CHUNK_SIZE_INDEX];\n\t\tthis.cachedByteMultipler = getByteMultipler(this.cachedType);\n\t\tthis.maxLength = this.cachedMaxChunkSize * this.pointerStack.maxLength;\n\n\t\tthis.growLock = new Int32Array(this.firstBlock.data.buffer, this.firstBlock.bufferByteOffset + GROW_LOCK_INDEX * Uint32Array.BYTES_PER_ELEMENT, 1);\n\t}\n\n\t// Lay out the two inlined stacks (their firstBlocks sliced from ours), record their pointers, and seed the first chunk.\n\t// firstBlock and uint16Array must already be set. Used by both the fresh-alloc path and the inline-in-place path.\n\tprivate initialize(config?: SharedPoolConfig<T>) {\n\t\tlet dataLength = config?.dataLength ?? 1;\n\t\tlet maxChunkSize = config?.maxChunkSize ?? DEFAULT_MAX_CHUNK_SIZE;\n\t\tlet maxLength = config?.maxLength ?? DEFAULT_MAX_LENGTH;\n\t\tlet maxRecycledLength = config?.maxRecycledLength ?? DEFAULT_MAX_RECYCLED_LENGTH;\n\n\t\t// Each stack sizes its inlined firstBlock from its own maxLength, so compute both up front to lay them out. The\n\t\t// stacks cap their segments at what a buffer can hold, so size the inlined blocks against that same cap.\n\t\tlet maxSegmentLength = SharedStack.getMaxSegmentLength(this.memory.maxAllocationLength);\n\t\tlet pointerStackMaxLength = maxLength / maxChunkSize;\n\t\tlet pointerStackAllocateCount = SharedStack.getAllocateCount(pointerStackMaxLength, undefined, maxSegmentLength);\n\t\tlet recycleStackAllocateCount = SharedStack.getAllocateCount(maxRecycledLength, undefined, maxSegmentLength);\n\n\t\t// Inline both stacks' firstBlocks right after the pool header so the whole spine is one contiguous allocation\n\t\tthis.pointerStack = new SharedStack(this.memory, {\n\t\t\tfirstBlock: this.firstBlock.getSubAllocation(SharedPool.ALLOCATE_COUNT, pointerStackAllocateCount),\n\t\t\ttype: Uint32Array,\n\t\t\tmaxLength: pointerStackMaxLength,\n\t\t});\n\t\tstoreRawPointer(this.firstBlock.data, POINTER_STACK_INDEX, this.pointerStack.pointer);\n\t\tthis.recycleStack = new SharedStack(this.memory, {\n\t\t\tfirstBlock: this.firstBlock.getSubAllocation(SharedPool.ALLOCATE_COUNT + pointerStackAllocateCount, recycleStackAllocateCount),\n\t\t\ttype: Uint32Array,\n\t\t\tmaxLength: maxRecycledLength,\n\t\t});\n\t\tstoreRawPointer(this.firstBlock.data, RECYCLE_STACK_INDEX, this.recycleStack.pointer);\n\n\t\tlet typeCode = getArrayTypeCode(config?.type ?? Uint32Array);\n\t\tthis.type = typeCode;\n\t\tthis.dataLength = dataLength;\n\t\tthis.maxChunkSize = maxChunkSize;\n\n\t\tlet byteMultipler = getByteMultipler(typeCode);\n\t\tlet firstArray = this.memory.allocUI32(maxChunkSize * dataLength * byteMultipler);\n\t\tthis.pointerStack.push(firstArray.pointer);\n\t}\n\n\tat(index: number): T {\n\t\tlet dataBlock = this.getFullDataBlock(index);\n\t\treturn this.getDataBlock(dataBlock, index % this.cachedMaxChunkSize);\n\t}\n\tget(index: number, dataIndex = 0): T[number] {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tif(dataIndex >= dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${dataLength}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(index) as NumericArrayIO;\n\t\treturn dataBlock[(index % this.cachedMaxChunkSize) * dataLength + dataIndex];\n\t}\n\tset(index: number, dataIndex: number, value: T[number]) {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tif(dataIndex >= dataLength) {\n\t\t\tthrow new Error(`${dataIndex} is out of dataLength bounds ${dataLength}`);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(index) as NumericArrayIO;\n\t\tdataBlock[(index % this.cachedMaxChunkSize) * dataLength + dataIndex] = value;\n\t}\n\n\t// Resolve the chunk view holding an index once. Callers touching several fields of the same record read/write straight\n\t// into this view at blockOffset(index) + fieldIndex, avoiding a repeated chunk lookup per field.\n\tblockFor(index: number): T {\n\t\treturn this.getFullDataBlock(index);\n\t}\n\t// Base slot of a record within the view blockFor(index) returns.\n\tblockOffset(index: number): number {\n\t\treturn (index % this.cachedMaxChunkSize) * this.cachedDataLength;\n\t}\n\n\tpush(values: T[number] | Array<T[number]>): number {\n\t\tlet dataLength = this.cachedDataLength;\n\t\tconst isSingleValue = typeof values !== 'object';\n\t\tif(!isSingleValue && values.length > dataLength) {\n\t\t\tthrow new Error(`Can't insert ${values.length} array into shared list of ${dataLength} dataLength`);\n\t\t}\n\n\t\t// Reuse a recycled index if one is available. pop() can come back undefined when another thread drained the last\n\t\t// slot between our two calls, so fall through to a fresh index rather than trusting a length() read\n\t\tlet newIndex = this.recycleStack.length === 0 ? undefined : this.recycleStack.pop();\n\t\tif(newIndex === undefined) {\n\t\t\tnewIndex = Atomics.add(this.firstBlock.data, LENGTH_INDEX, 1);\n\t\t}\n\n\t\tlet dataBlock = this.getFullDataBlock(newIndex) as NumericArrayIO;\n\t\tlet startIndex = dataLength * (newIndex % this.cachedMaxChunkSize);\n\t\tif(isSingleValue) {\n\t\t\tdataBlock[startIndex] = values;\n\t\t} else {\n\t\t\tfor(let i = 0; i < values.length; i++) {\n\t\t\t\tdataBlock[startIndex + i] = values[i];\n\t\t\t}\n\t\t}\n\n\t\treturn newIndex;\n\t}\n\n\treserveContiguous(count: number): number {\n\t\tif(!Number.isInteger(count) || count < 0) {\n\t\t\tthrow new Error(`Can't reserve ${count} pool entries`);\n\t\t}\n\t\treturn Atomics.add(this.firstBlock.data, LENGTH_INDEX, count);\n\t}\n\n\tdeleteIndex(index: number) {\n\t\tthis.recycleStack.push(index);\n\t}\n\n\tclear() {\n\t\tthis.firstBlock.data[LENGTH_INDEX] = 0;\n\t\tthis.recycleStack.clear();\n\t}\n\n\t// Flags recycled indexes up to the allocated length (the mask's length). Lets a caller walk chunks directly via\n\t// blockFor instead of paying entries()'s per-record generator, tuple and subarray.\n\tgetRecycledMask(): Uint8Array {\n\t\tconst length = Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t\tconst recycled = new Uint8Array(length);\n\t\tfor(let index of this.recycleStack) {\n\t\t\tif(index < length) {\n\t\t\t\trecycled[index] = 1;\n\t\t\t}\n\t\t}\n\t\treturn recycled;\n\t}\n\n\t*[Symbol.iterator]() {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycleStack) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tconst maxChunkSize = this.cachedMaxChunkSize;\n\t\t// Snapshot the length once - iteration over a concurrently mutated pool is a snapshot anyway, and re-loading the\n\t\t// atomic every step is pure overhead\n\t\tconst length = Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < length; i++) {\n\t\t\tif(!recycledValues[i]) {\n\t\t\t\tlet newDataBlockIndex = Math.floor(i / maxChunkSize);\n\t\t\t\tif(newDataBlockIndex !== dataBlockIndex) {\n\t\t\t\t\tdataBlock = this.getFullDataBlock(i);\n\t\t\t\t\tdataBlockIndex = newDataBlockIndex;\n\t\t\t\t}\n\t\t\t\tyield this.getDataBlock(dataBlock, i % maxChunkSize);\n\t\t\t}\n\t\t}\n\t}\n\n\t*entries(): IterableIterator<[number, T]> {\n\t\tconst recycledValues: { [key: number]: true } = {};\n\t\tfor(let value of this.recycleStack) {\n\t\t\trecycledValues[value] = true;\n\t\t}\n\n\t\tconst maxChunkSize = this.cachedMaxChunkSize;\n\t\tconst length = Atomics.load(this.firstBlock.data, LENGTH_INDEX);\n\t\tlet dataBlock = this.getFullDataBlock(0);\n\t\tlet dataBlockIndex = 0;\n\t\tfor(let i = 0; i < length; i++) {\n\t\t\tif(!recycledValues[i]) {\n\t\t\t\tlet newDataBlockIndex = Math.floor(i / maxChunkSize);\n\t\t\t\tif(newDataBlockIndex !== dataBlockIndex) {\n\t\t\t\t\tdataBlock = this.getFullDataBlock(i);\n\t\t\t\t\tdataBlockIndex = newDataBlockIndex;\n\t\t\t\t}\n\t\t\t\tyield [i, this.getDataBlock(dataBlock, i % maxChunkSize)];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getFullDataBlock(index: number) {\n\t\tlet pointerIndex = Math.floor(index / this.cachedMaxChunkSize);\n\t\tlet cachedDataBlock = this.cachedFullDataBlock[pointerIndex];\n\t\tif(cachedDataBlock) {\n\t\t\treturn cachedDataBlock;\n\t\t}\n\t\tif(pointerIndex >= this.pointerStack.length) {\n\t\t\t// Only let a single thread append a new chunk at a time - otherwise two concurrent inserts landing in a new\n\t\t\t// chunk would each allocate + push a buffer, orphaning one and leaking memory\n\t\t\tlock(this.growLock);\n\t\t\ttry {\n\t\t\t\t// Re-check under the lock: another thread may have already appended the chunk while we were waiting\n\t\t\t\twhile(pointerIndex >= this.pointerStack.length) {\n\t\t\t\t\tlet newArray = this.memory.allocUI32(this.cachedMaxChunkSize * this.cachedDataLength * this.cachedByteMultipler);\n\t\t\t\t\tthis.pointerStack.push(newArray.pointer);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tunlock(this.growLock);\n\t\t\t}\n\t\t}\n\n\t\tlet array = new AllocatedMemory(this.memory, getPointer(this.pointerStack.at(pointerIndex), this.memory.positionBits));\n\n\t\tlet blockLength = this.cachedDataLength * this.cachedMaxChunkSize;\n\t\tlet data = makeArrayView(this.cachedType, array.data.buffer, array.bufferByteOffset, blockLength) as T;\n\n\t\tthis.cachedFullDataBlock[pointerIndex] = data;\n\t\treturn data;\n\t}\n\n\tprivate getDataBlock(rawData: T, index: number): T {\n\t\tconst dataLength = this.cachedDataLength;\n\t\tconst start = index * dataLength;\n\t\treturn rawData.subarray(start, start + dataLength) as T;\n\t}\n\n\tfree() {\n\t\tthis.recycleStack.free();\n\n\t\tfor(let pointer of this.pointerStack) {\n\t\t\tlet memory = new AllocatedMemory(this.memory, getPointer(pointer, this.memory.positionBits));\n\t\t\tmemory.free();\n\t\t}\n\t\tthis.pointerStack.free();\n\t\tif(this.ownsFirstBlock) {\n\t\t\tthis.firstBlock.free();\n\t\t}\n\t}\n\n\tgetSharedMemory(): SharedPoolMemory {\n\t\treturn {\n\t\t\tfirstBlock: this.firstBlock.getSharedMemory(),\n\t\t};\n\t}\n}\n\ninterface SharedPoolConfig<T extends NumericArray> {\n\tmaxChunkSize?: number\n\tmaxLength?: number\n\tmaxRecycledLength?: number\n\ttype?: TypedArrayConstructor<T>\n\tdataLength?: number\n}\ninterface SharedPoolMemory {\n\tfirstBlock: SharedAllocatedMemory | AllocatedMemory\n}\n\nexport type { SharedPoolConfig, SharedPoolMemory };\n"],"mappings":"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"}