@woosh/meep-engine 2.104.0 → 2.106.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/build/meep.cjs +131 -85
  4. package/build/meep.min.js +1 -1
  5. package/build/meep.module.js +131 -85
  6. package/editor/tools/v2/BlenderCameraOrientationGizmo.js +1 -1
  7. package/package.json +1 -1
  8. package/src/core/assert.d.ts.map +1 -1
  9. package/src/core/assert.js +3 -1
  10. package/src/core/bvh2/bvh3/build_triangle_morton_codes.d.ts +1 -1
  11. package/src/core/bvh2/bvh3/build_triangle_morton_codes.d.ts.map +1 -1
  12. package/src/core/bvh2/bvh3/build_triangle_morton_codes.js +3 -1
  13. package/src/core/bvh2/bvh3/ebvh_build_hierarchy.d.ts +1 -0
  14. package/src/core/bvh2/bvh3/ebvh_build_hierarchy.d.ts.map +1 -1
  15. package/src/core/bvh2/bvh3/ebvh_build_hierarchy.js +3 -2
  16. package/src/core/cache/Cache.d.ts +2 -1
  17. package/src/core/cache/Cache.d.ts.map +1 -1
  18. package/src/core/cache/Cache.js +68 -41
  19. package/src/core/cache/Cache.spec.js +42 -0
  20. package/src/core/cache/CacheElement.d.ts +1 -0
  21. package/src/core/cache/CacheElement.d.ts.map +1 -1
  22. package/src/core/cache/CacheElement.js +4 -0
  23. package/src/core/codegen/LineBuilder.d.ts +1 -24
  24. package/src/core/codegen/LineBuilder.d.ts.map +1 -1
  25. package/src/core/codegen/LineBuilder.js +19 -15
  26. package/src/core/collection/map/HashMap.d.ts.map +1 -1
  27. package/src/core/collection/map/HashMap.js +48 -30
  28. package/src/core/model/node-graph/NodeGraph.js +2 -2
  29. package/src/engine/graphics/ecs/mesh/Mesh.js +1 -1
  30. package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +1 -1
@@ -7,14 +7,21 @@ import { returnZero } from "../function/returnZero.js";
7
7
  import { strictEquals } from "../function/strictEquals.js";
8
8
  import { CacheElement } from "./CacheElement.js";
9
9
 
10
- // TODO validate hashes of held elements to keep them up to date. Keys are assumed to be immutable, but this assumption may be broken by users
11
-
12
10
  /**
13
11
  * Hash-based cache, uses LRU (least-recently-used) eviction policy
12
+ * Make sure that keys being used are truly immutable when it comes to hash and equality calculation, otherwise cache corruption is inevitable
14
13
  * @template Key, Value
15
14
  * @extends Map<Key,Value>
16
15
  */
17
16
  export class Cache {
17
+ #maxWeight = Number.POSITIVE_INFINITY;
18
+ /**
19
+ *
20
+ * @type {number}
21
+ * @private
22
+ */
23
+ #weight = 0;
24
+
18
25
  /**
19
26
  * @param {number} [maxWeight=Number.POSITIVE_INFINITY]
20
27
  * @param {function(key:Key):number} [keyWeigher= key=>0]
@@ -44,14 +51,8 @@ export class Cache {
44
51
  * @type {number}
45
52
  * @private
46
53
  */
47
- this.maxWeight = maxWeight;
54
+ this.#maxWeight = maxWeight;
48
55
 
49
- /**
50
- *
51
- * @type {number}
52
- * @private
53
- */
54
- this.weight = 0;
55
56
 
56
57
  /**
57
58
  *
@@ -152,18 +153,37 @@ export class Cache {
152
153
  return this.data.size;
153
154
  }
154
155
 
156
+ /**
157
+ * @deprecated use {@link maxWeight} directly instead
158
+ */
159
+ setMaxWeight(value) {
160
+ this.maxWeight = value;
161
+ }
162
+
163
+ /**
164
+ * Total weight of all elements currently in the cache
165
+ * @returns {number}
166
+ */
167
+ get weight() {
168
+ return this.#weight;
169
+ }
170
+
155
171
  /**
156
172
  * Will cause evictions if current weight is smaller than what we're setting
157
173
  * @param {number} value
158
174
  */
159
- setMaxWeight(value) {
175
+ set maxWeight(value) {
160
176
  if (typeof value !== "number" || value < 0) {
161
177
  throw new Error(`Weight must be a non-negative number, instead was '${value}'`);
162
178
  }
163
179
 
164
- this.maxWeight = value;
180
+ this.#maxWeight = value;
181
+
182
+ this.evictUntilWeight(this.#maxWeight);
183
+ }
165
184
 
166
- this.evictUntilWeight(this.maxWeight);
185
+ get maxWeight() {
186
+ return this.#maxWeight;
167
187
  }
168
188
 
169
189
  /**
@@ -182,7 +202,8 @@ export class Cache {
182
202
  result += weight;
183
203
  }
184
204
 
185
- this.weight = result;
205
+ this.#weight = result;
206
+ this.evictUntilWeight(this.#maxWeight);
186
207
  }
187
208
 
188
209
  /**
@@ -212,13 +233,13 @@ export class Cache {
212
233
 
213
234
  const delta_weight = new_weight - old_weight;
214
235
 
215
- this.weight += delta_weight;
236
+ this.#weight += delta_weight;
216
237
 
217
238
  if (
218
- this.weight > this.maxWeight
219
- && new_weight <= this.maxWeight //make it less likely to drop entire cache
239
+ this.#weight > this.#maxWeight
240
+ && new_weight <= this.#maxWeight //make it less likely to drop entire cache
220
241
  ) {
221
- this.evictUntilWeight(this.maxWeight);
242
+ this.evictUntilWeight(this.#maxWeight);
222
243
  }
223
244
 
224
245
  return true;
@@ -259,7 +280,9 @@ export class Cache {
259
280
  const victim = this.findEvictionVictim();
260
281
 
261
282
  if (victim !== null) {
262
- this.remove(victim.key);
283
+ const removed_from_hash_table = this.remove(victim.key);
284
+
285
+ assert.ok(removed_from_hash_table, `Failed to remove key '${victim.key}', likely reasons:\n\t1. key was mutated (keys must never be mutated)\n\t2. provided hashing function is unstable\n\t3. provided equality function is inconsistent`);
263
286
 
264
287
  this.onEvicted.send2(victim.key, victim.value);
265
288
 
@@ -280,7 +303,7 @@ export class Cache {
280
303
 
281
304
  const target = Math.max(targetWeight, 0);
282
305
 
283
- while (this.weight > target) {
306
+ while (this.#weight > target) {
284
307
  this.evictOne();
285
308
  }
286
309
  }
@@ -294,6 +317,22 @@ export class Cache {
294
317
  let element = this.data.get(key);
295
318
 
296
319
  if (element === undefined) {
320
+ //compute weight
321
+ const elementWeight = this.computeElementWeight(key, value);
322
+
323
+ /**
324
+ * It's possible that element being added is larger than cache's capacity,
325
+ * in which case entire cache will be evicted, but there still won't be enough space
326
+ * @type {number}
327
+ */
328
+ const weightTarget = this.#maxWeight - elementWeight;
329
+
330
+ if (weightTarget < 0) {
331
+ // Special case
332
+ // element does not fit into cache, attempting to insert it forcibly would result in a full flush and overflow
333
+ return;
334
+ }
335
+
297
336
  element = new CacheElement();
298
337
 
299
338
  element.key = key;
@@ -311,25 +350,8 @@ export class Cache {
311
350
  this.__last = element;
312
351
  }
313
352
 
314
- //compute weight
315
- const elementWeight = this.computeElementWeight(key, value);
316
-
317
353
  element.weight = elementWeight;
318
354
 
319
-
320
- /**
321
- * It's possible that element being added is larger than cache's capacity,
322
- * in which case entire cache will be evicted, but there still won't be enough space
323
- * @type {number}
324
- */
325
- const weightTarget = this.maxWeight - elementWeight;
326
-
327
- if (weightTarget < 0) {
328
- // Special case
329
- // element does not fit into cache, attempting to insert it forcibly would result in a full flush and overflow
330
- return;
331
- }
332
-
333
355
  //evict elements until there is enough space for the element
334
356
  this.evictUntilWeight(weightTarget);
335
357
 
@@ -337,16 +359,21 @@ export class Cache {
337
359
  this.data.set(key, element);
338
360
 
339
361
  //update weight
340
- this.weight += elementWeight;
362
+ this.#weight += elementWeight;
341
363
  } else {
342
364
  // check if value is the same
343
365
  if (value === element.value) {
344
366
  // same value, no action required
345
367
  } else {
346
368
  // replace value, adjust weight
347
- this.weight -= this.valueWeigher(element.value);
348
- this.weight += this.valueWeigher(value);
369
+ this.#weight -= element.weight;
370
+
371
+ const elementWeight = this.computeElementWeight(key, value);
372
+
373
+ this.#weight += elementWeight;
349
374
 
375
+ // assign new values
376
+ element.weight = elementWeight;
350
377
  element.value = value;
351
378
  }
352
379
 
@@ -431,7 +458,7 @@ export class Cache {
431
458
  this.data.delete(key);
432
459
 
433
460
  //update weight
434
- this.weight -= element.weight;
461
+ this.#weight -= element.weight;
435
462
  }
436
463
 
437
464
  /**
@@ -503,7 +530,7 @@ export class Cache {
503
530
  this.__first = null;
504
531
  this.__last = null;
505
532
 
506
- this.weight = 0;
533
+ this.#weight = 0;
507
534
  }
508
535
 
509
536
  /**
@@ -32,6 +32,19 @@ test("trying to insert an element into the cache that's larger than the cache ca
32
32
  expect(cache.contains(2)).toBe(false);
33
33
  });
34
34
 
35
+ test("Recently accessed element should not be targeted for eviction where possible", () => {
36
+ const cache = new Cache();
37
+
38
+ cache.put(2, "hello");
39
+ cache.put(7, "world");
40
+
41
+ cache.get(2);
42
+
43
+ cache.evictOne();
44
+
45
+ expect(cache.has(2)).toBe(true);
46
+ });
47
+
35
48
  test("removeListener is called when element is evicted", () => {
36
49
 
37
50
  const removeListener = jest.fn();
@@ -233,3 +246,32 @@ test("silentRemove should not notify", () => {
233
246
 
234
247
  expect(mock).not.toHaveBeenCalled();
235
248
  });
249
+
250
+ test("setting maxWeight will drop data and update weight", () => {
251
+
252
+ const cache = new Cache();
253
+
254
+ cache.set("a", 1);
255
+ cache.set("b", 2);
256
+ cache.set("c", 3);
257
+
258
+ expect(cache.weight).toEqual(3);
259
+
260
+ cache.maxWeight = 1;
261
+
262
+ expect(cache.maxWeight).toEqual(1);
263
+ expect(cache.weight).toEqual(1);
264
+ });
265
+
266
+ test("setting maxWeight to 0 will empty out cache", () => {
267
+
268
+ const cache = new Cache();
269
+
270
+ cache.set("a", 1);
271
+ cache.set("b", 2);
272
+
273
+ cache.maxWeight = 0;
274
+
275
+ expect(cache.size()).toBe(0);
276
+
277
+ });
@@ -30,5 +30,6 @@ export class CacheElement<Key, Value> {
30
30
  */
31
31
  previous: CacheElement<Key_1, Value_1>;
32
32
  unlink(): void;
33
+ toString(): string;
33
34
  }
34
35
  //# sourceMappingURL=CacheElement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CacheElement.d.ts","sourceRoot":"","sources":["../../../../src/core/cache/CacheElement.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;IAMQ;;;OAGG;IACH,WAAe;IAEf;;;OAGG;IACH,eAAiB;IAEjB;;;OAGG;IACH,QAFU,MAAM,CAED;IAEf;;;OAGG;IACH,mCAAgB;IAEhB;;;OAGG;IACH,uCAAoB;IAGxB,eAWC;CACJ"}
1
+ {"version":3,"file":"CacheElement.d.ts","sourceRoot":"","sources":["../../../../src/core/cache/CacheElement.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;IAMQ;;;OAGG;IACH,WAAe;IAEf;;;OAGG;IACH,eAAiB;IAEjB;;;OAGG;IACH,QAFU,MAAM,CAED;IAEf;;;OAGG;IACH,mCAAgB;IAEhB;;;OAGG;IACH,uCAAoB;IAGxB,eAWC;IAED,mBAEC;CACJ"}
@@ -52,4 +52,8 @@ export class CacheElement {
52
52
  next.previous = previous;
53
53
  }
54
54
  }
55
+
56
+ toString() {
57
+ return `CacheElement{ hasNext:${this.next !== null}, hasPrevious:${this.previous !== null}, weight:${this.weight}, key:${this.key}, value:${this.value} }`;
58
+ }
55
59
  }
@@ -9,16 +9,6 @@ declare class LineBuilder {
9
9
  * @returns {LineBuilder}
10
10
  */
11
11
  static fromText(text: string): LineBuilder;
12
- /**
13
- *
14
- * @type {Line[]}
15
- */
16
- lines: Line[];
17
- /**
18
- *
19
- * @type {number}
20
- */
21
- indentation: number;
22
12
  /**
23
13
  *
24
14
  * @type {number}
@@ -62,19 +52,6 @@ declare class LineBuilder {
62
52
  * @returns {string}
63
53
  */
64
54
  build(): string;
65
- }
66
- /**
67
- * Created by Alex on 08/06/2015.
68
- */
69
- declare class Line {
70
- /**
71
- *
72
- * @param {string} text
73
- * @param {number} indent
74
- * @constructor
75
- */
76
- constructor(text: string, indent: number);
77
- text: string;
78
- indentation: number;
55
+ #private;
79
56
  }
80
57
  //# sourceMappingURL=LineBuilder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LineBuilder.d.ts","sourceRoot":"","sources":["../../../../src/core/codegen/LineBuilder.js"],"names":[],"mappings":";AAoBA;;GAEG;AACH;IAkII;;;;OAIG;IACH,sBAHW,MAAM,GACJ,WAAW,CAkBvB;IArJD;;;OAGG;IACH,OAFU,IAAI,EAAE,CAEL;IACX;;;OAGG;IACH,aAFU,MAAM,CAEA;IAChB;;;OAGG;IACH,cAFU,MAAM,CAEqB;IAErC;;;OAGG;IACH,oBAEC;IAED;;;;OAIG;IACH,wBAFW,MAAM,GADL,OAAO,CAiBlB;IAED;;;OAGG;IACH,UAFa,WAAW,CAKvB;IAED;;;OAGG;IACH,UAFa,WAAW,CAKvB;IAED;;;;OAIG;IACH,eAHW,MAAM,GACJ,WAAW,CASvB;IAED;;;OAGG;IACH,gBAFW,WAAW,QAgBrB;IAED,cAGC;IAED;;;OAGG;IACH,SAFa,MAAM,CAsBlB;CAwBJ;AA/KD;;GAEG;AAGH;IACI;;;;;OAKG;IACH,kBAJW,MAAM,UACN,MAAM,EAMhB;IAFG,aAAgB;IAChB,oBAAyB;CAEhC"}
1
+ {"version":3,"file":"LineBuilder.d.ts","sourceRoot":"","sources":["../../../../src/core/codegen/LineBuilder.js"],"names":[],"mappings":";AAoBA;;GAEG;AACH;IAoII;;;;OAIG;IACH,sBAHW,MAAM,GACJ,WAAW,CAoBvB;IA7ID;;;OAGG;IACH,cAFU,MAAM,CAEqB;IAErC;;;OAGG;IACH,oBAEC;IAED;;;;OAIG;IACH,wBAFW,MAAM,GADL,OAAO,CAiBlB;IAED;;;OAGG;IACH,UAFa,WAAW,CAKvB;IAED;;;OAGG;IACH,UAFa,WAAW,CAKvB;IAED;;;;OAIG;IACH,eAHW,MAAM,GACJ,WAAW,CASvB;IAED;;;OAGG;IACH,gBAFW,WAAW,QAgBrB;IAED,cAGC;IAED;;;OAGG;IACH,SAFa,MAAM,CAsBlB;;CA0BJ"}
@@ -27,12 +27,14 @@ class LineBuilder {
27
27
  *
28
28
  * @type {Line[]}
29
29
  */
30
- lines = [];
30
+ #lines = [];
31
+
31
32
  /**
32
33
  *
33
34
  * @type {number}
34
35
  */
35
- indentation = 0;
36
+ #indentation = 0;
37
+
36
38
  /**
37
39
  *
38
40
  * @type {number}
@@ -44,7 +46,7 @@ class LineBuilder {
44
46
  * @return {number}
45
47
  */
46
48
  get count() {
47
- return this.lines.length;
49
+ return this.#lines.length;
48
50
  }
49
51
 
50
52
  /**
@@ -53,7 +55,7 @@ class LineBuilder {
53
55
  * @param {string} term
54
56
  */
55
57
  containsSubstring(term) {
56
- const lines = this.lines;
58
+ const lines = this.#lines;
57
59
  const n = lines.length;
58
60
  for (let i = 0; i < n; i++) {
59
61
  const line = lines[i];
@@ -73,7 +75,7 @@ class LineBuilder {
73
75
  * @returns {LineBuilder}
74
76
  */
75
77
  indent() {
76
- this.indentation++;
78
+ this.#indentation++;
77
79
  return this;
78
80
  }
79
81
 
@@ -82,7 +84,7 @@ class LineBuilder {
82
84
  * @returns {LineBuilder}
83
85
  */
84
86
  dedent() {
85
- this.indentation--;
87
+ this.#indentation--;
86
88
  return this;
87
89
  }
88
90
 
@@ -93,9 +95,9 @@ class LineBuilder {
93
95
  */
94
96
  add(line_text) {
95
97
 
96
- const line = new Line(line_text, this.indentation);
98
+ const line = new Line(line_text, this.#indentation);
97
99
 
98
- this.lines.push(line);
100
+ this.#lines.push(line);
99
101
 
100
102
  return this;
101
103
  }
@@ -106,23 +108,23 @@ class LineBuilder {
106
108
  */
107
109
  addLines(lines) {
108
110
 
109
- const other_lines = lines.lines;
111
+ const other_lines = lines.#lines;
110
112
 
111
113
  const other_line_count = other_lines.length;
112
114
 
113
115
  for (let i = 0; i < other_line_count; i++) {
114
116
  const otherLine = other_lines[i];
115
117
 
116
- const line = new Line(otherLine.text, otherLine.indentation + this.indentation);
118
+ const line = new Line(otherLine.text, otherLine.indentation + this.#indentation);
117
119
 
118
- this.lines.push(line);
120
+ this.#lines.push(line);
119
121
  }
120
122
 
121
123
  }
122
124
 
123
125
  clear() {
124
- this.lines = [];
125
- this.indentation = 0;
126
+ this.#lines = [];
127
+ this.#indentation = 0;
126
128
  }
127
129
 
128
130
  /**
@@ -134,7 +136,7 @@ class LineBuilder {
134
136
 
135
137
  let i, j, l;
136
138
 
137
- const lines = this.lines;
139
+ const lines = this.#lines;
138
140
 
139
141
  for (i = 0, l = lines.length; i < l; i++) {
140
142
  const line = lines[i];
@@ -167,7 +169,9 @@ class LineBuilder {
167
169
 
168
170
  for (let i = 0; i < n; i++) {
169
171
 
170
- r.add(lines[i]);
172
+ const line_text = lines[i];
173
+
174
+ r.add(line_text);
171
175
 
172
176
  }
173
177
 
@@ -1 +1 @@
1
- {"version":3,"file":"HashMap.d.ts","sourceRoot":"","sources":["../../../../../src/core/collection/map/HashMap.js"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;GAYG;AACH,uFAIC;AAsHD;;;;;;;GAOG;AACH;IA2DI;;;;;;OAMG;IACH,4FALuB,MAAM,EAsC5B;IAlBG;;;;;OAKG;IACH,iCAAsC;IACtC;;;;;OAKG;IACH,qCAA8C;IAOlD,mBAEC;IAED;;;OAGG;IACH,kBAFa,MAAM,CAIlB;IA2HD;;;;OAIG;IACH,SAHW,CAAC,SACD,CAAC,QAoEX;IAED;;;;OAIG;IACH,SAHW,CAAC,GACC,CAAC,GAAC,SAAS,CA+BvB;IAED;;;;;;;;OAQG;IACH,kBALW,CAAC,kBACQ,CAAC,KAAE,CAAC,0BAEZ,CAAC,CAcZ;IAED;;;;;OAKG;IACH,cAJW,CAAC,SACD,CAAC,GACA,CAAC,CAYZ;IAuBD;;;;OAIG;IACH,YAHW,CAAC,GACC,OAAO,CA+CnB;IAED;;;;;OAKG;IACH,4CAFa,OAAO,CA+BnB;IAOD;;OAEG;IACH,gBAkDC;IAmBD,2CAwBC;IAED;;;;OAIG;IACH,SAHW,CAAC,GACC,OAAO,CAInB;IAED;;OAEG;IACH,cA6BC;IA+BD;;;OAGG;IACH,UAFa,SAAS,CAAC,CAAC,CAOvB;IAED;;;OAGG;IACH,QAFa,SAAS,CAAC,CAAC,CAMvB;IAhDD,yDA2BC;;CAsBJ"}
1
+ {"version":3,"file":"HashMap.d.ts","sourceRoot":"","sources":["../../../../../src/core/collection/map/HashMap.js"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;GAYG;AACH,uFAIC;AA8FD;;;;;;;GAOG;AACH;IA+DI;;;;;;OAMG;IACH,4FALuB,MAAM,EAsC5B;IAlBG;;;;;OAKG;IACH,iCAAsC;IACtC;;;;;OAKG;IACH,qCAA8C;IAOlD,mBAEC;IAED;;;OAGG;IACH,kBAFa,MAAM,CAIlB;IAuJD;;;;OAIG;IACH,SAHW,CAAC,SACD,CAAC,QA0EX;IAED;;;;OAIG;IACH,SAHW,CAAC,GACC,CAAC,GAAC,SAAS,CA+BvB;IAED;;;;;;;;OAQG;IACH,kBALW,CAAC,kBACQ,CAAC,KAAE,CAAC,0BAEZ,CAAC,CAcZ;IAED;;;;;OAKG;IACH,cAJW,CAAC,SACD,CAAC,GACA,CAAC,CAYZ;IAuBD;;;;OAIG;IACH,YAHW,CAAC,GACC,OAAO,CA+CnB;IAED;;;;;OAKG;IACH,4CAFa,OAAO,CA+BnB;IAOD;;OAEG;IACH,gBAsDC;IAmBD,2CAwBC;IAED;;;;OAIG;IACH,SAHW,CAAC,GACC,OAAO,CAInB;IAED;;OAEG;IACH,cA6BC;IA+BD;;;OAGG;IACH,UAFa,SAAS,CAAC,CAAC,CAOvB;IAED;;;OAGG;IACH,QAFa,SAAS,CAAC,CAAC,CAMvB;IAhDD,yDA2BC;;CAsBJ"}
@@ -124,30 +124,6 @@ const RESERVED_HASH_SUBSTITUTE = 0;
124
124
  const UNDEFINED_BIN_INDEX = ~0;
125
125
 
126
126
 
127
- /**
128
- * @template K,V
129
- * @param {HashMapEntry<K,V>} record
130
- * @param {number} hash
131
- * @param {K} key
132
- * @param {function(a:K,b:K):boolean} equality_op
133
- */
134
- function entry_equality_check(record, hash, key, equality_op) {
135
- if (record.hash !== hash) {
136
- return false;
137
- }
138
-
139
- if (record.key === key) {
140
- return true;
141
- }
142
-
143
- const result = equality_op(record.key, key);
144
-
145
- assert.isBoolean(result, `result(a=${record.key},b=${key})`);
146
-
147
- return result;
148
- }
149
-
150
-
151
127
  const EMPTY_BINS = new Uint32Array(0);
152
128
 
153
129
  /**
@@ -215,6 +191,10 @@ export class HashMap {
215
191
  */
216
192
  #load_factor = DEFAULT_LOAD_FACTOR;
217
193
 
194
+ /**
195
+ * Used to track modifications to prevent concurrent changes during iteration
196
+ * @type {number}
197
+ */
218
198
  #version = 0;
219
199
 
220
200
  /**
@@ -291,6 +271,8 @@ export class HashMap {
291
271
  this.#bin_count = 2 ** this.#bin_count_power_of_two;
292
272
  this.#bin_count_mask = this.#bin_count - 1;
293
273
 
274
+ const old_entry_allocation_count = this.#entries_allocated_count;
275
+
294
276
  this.#entries_allocated_count = 2 ** this.#entries_count_power_of_two;
295
277
 
296
278
  const BinsArray = UintArrayForCount(this.#entries_allocated_count + ENTRY_BASE);
@@ -302,7 +284,7 @@ export class HashMap {
302
284
 
303
285
  this.#entries = new_entries;
304
286
 
305
- array_copy(old_entries, 0, new_entries, 0, min2(old_entries.length, this.#entries_allocated_count));
287
+ array_copy(old_entries, 0, new_entries, 0, min2(old_entry_allocation_count, this.#entries_allocated_count));
306
288
 
307
289
  if (this.#size > 0) {
308
290
  // re-hash
@@ -339,6 +321,29 @@ export class HashMap {
339
321
  return original === RESERVED_HASH ? RESERVED_HASH_SUBSTITUTE : original;
340
322
  }
341
323
 
324
+ /**
325
+ * @param {HashMapEntry<K,V>} record
326
+ * @param {number} hash
327
+ * @param {K} key
328
+ */
329
+ #entry_equality_check(record, hash, key) {
330
+ if (record.hash !== hash) {
331
+ return false;
332
+ }
333
+
334
+ if (record.key === key) {
335
+ return true;
336
+ }
337
+
338
+ assert.equal(record.hash, this.#build_key_hash(record.key), `Key hash has diverged for key ${record.key}, likely key was mutated or hash function is unstable`);
339
+
340
+ const result = this.keyEqualityFunction(record.key, key);
341
+
342
+ assert.isBoolean(result, `result(a=${record.key},b=${key})`);
343
+
344
+ return result;
345
+ }
346
+
342
347
  /**
343
348
  *
344
349
  * @param {K} k
@@ -354,6 +359,9 @@ export class HashMap {
354
359
 
355
360
  if (this.#entries[i] !== undefined) {
356
361
  const entry = this.#entries[i];
362
+
363
+ assert.equal(entry.hash, RESERVED_HASH, 'Entry is occupied');
364
+
357
365
  entry.hash = hash;
358
366
  entry.key = k;
359
367
  entry.value = v;
@@ -402,6 +410,7 @@ export class HashMap {
402
410
 
403
411
  const raw_hash = this.#build_key_hash(key);
404
412
  let bin_index = this.#compute_bin_index(raw_hash);
413
+
405
414
  assert.isFiniteNumber(bin_index, 'hash');
406
415
 
407
416
  let first_deleted_bin_index = UNDEFINED_BIN_INDEX;
@@ -415,11 +424,12 @@ export class HashMap {
415
424
  // check if it's the entry that we're looking for
416
425
  const entry = this.#entries[bin - ENTRY_BASE];
417
426
 
418
- if (entry_equality_check(entry, raw_hash, key, this.keyEqualityFunction)) {
427
+ if (this.#entry_equality_check(entry, raw_hash, key)) {
419
428
  // found the right entry
420
429
  entry.value = value;
421
430
  return;
422
431
  }
432
+
423
433
  } else if (bin === BIN_RESERVED_VALUE_EMPTY) {
424
434
  // bin is empty
425
435
 
@@ -436,7 +446,11 @@ export class HashMap {
436
446
  assert.equal(this.#entries[entry_index].value, value, 'entry.value');
437
447
  assert.equal(this.#entries[entry_index].key, key, 'entry.key');
438
448
 
439
- this.#bins[bin_index] = entry_index + ENTRY_BASE;
449
+ const bin_value = entry_index + ENTRY_BASE;
450
+
451
+ this.#bins[bin_index] = bin_value;
452
+
453
+ assert.equal(bin_value, this.#bins[bin_index], 'Bin value write error');
440
454
 
441
455
  break;
442
456
 
@@ -484,7 +498,7 @@ export class HashMap {
484
498
  // check if the entry is what we're looking for
485
499
  const entry = this.#entries[bin - ENTRY_BASE];
486
500
 
487
- if (entry_equality_check(entry, raw_hash, key, this.keyEqualityFunction)) {
501
+ if (this.#entry_equality_check(entry, raw_hash, key)) {
488
502
  // found the right entry
489
503
  return entry.value;
490
504
  }
@@ -588,7 +602,7 @@ export class HashMap {
588
602
  const entry_index = bin - ENTRY_BASE;
589
603
  const entry = entries[entry_index];
590
604
 
591
- if (entry_equality_check(entry, raw_hash, key, this.keyEqualityFunction)) {
605
+ if (this.#entry_equality_check(entry, raw_hash, key)) {
592
606
  // found the right entry
593
607
 
594
608
  // record entry as dead
@@ -670,7 +684,11 @@ export class HashMap {
670
684
 
671
685
  let written_entries = 0;
672
686
 
673
- for (let existing_entry_index = this.#entries_start; existing_entry_index < entries_bound; existing_entry_index++) {
687
+ for (
688
+ let existing_entry_index = this.#entries_start;
689
+ existing_entry_index < entries_bound;
690
+ existing_entry_index++
691
+ ) {
674
692
  const entry = entries[existing_entry_index];
675
693
 
676
694
  const hash = entry.hash;
@@ -244,7 +244,7 @@ export class NodeGraph {
244
244
  * @return {NodeInstance[]}
245
245
  */
246
246
  getNodes() {
247
- return this.nodes.data.slice();
247
+ return this.nodes.asArray().slice();
248
248
  }
249
249
 
250
250
  /**
@@ -252,7 +252,7 @@ export class NodeGraph {
252
252
  * @return {Connection[]}
253
253
  */
254
254
  getConnections() {
255
- return this.connections.data.slice();
255
+ return this.connections.asArray().slice();
256
256
  }
257
257
 
258
258
  /**
@@ -397,7 +397,7 @@ class Mesh {
397
397
  const matrixWorld = skeletonBone.matrixWorld;
398
398
 
399
399
 
400
- result.threejs_setFromMatrixPosition(matrixWorld);
400
+ result.setFromMatrixPosition(matrixWorld.elements);
401
401
  }
402
402
 
403
403
  }
@@ -41,7 +41,7 @@ export class GeometrySpatialQueryAccelerator {
41
41
  * @param {number} value in bytes
42
42
  */
43
43
  set cache_size(value) {
44
- this.cache.setMaxWeight(value);
44
+ this.cache.maxWeight = value;
45
45
  }
46
46
 
47
47
  /**