@woosh/meep-engine 2.104.0 → 2.105.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.
@@ -60003,28 +60003,6 @@ const RESERVED_HASH_SUBSTITUTE = 0;
60003
60003
  const UNDEFINED_BIN_INDEX = ~0;
60004
60004
 
60005
60005
 
60006
- /**
60007
- * @template K,V
60008
- * @param {HashMapEntry<K,V>} record
60009
- * @param {number} hash
60010
- * @param {K} key
60011
- * @param {function(a:K,b:K):boolean} equality_op
60012
- */
60013
- function entry_equality_check(record, hash, key, equality_op) {
60014
- if (record.hash !== hash) {
60015
- return false;
60016
- }
60017
-
60018
- if (record.key === key) {
60019
- return true;
60020
- }
60021
-
60022
- const result = equality_op(record.key, key);
60023
-
60024
- return result;
60025
- }
60026
-
60027
-
60028
60006
  const EMPTY_BINS = new Uint32Array(0);
60029
60007
 
60030
60008
  /**
@@ -60092,6 +60070,10 @@ class HashMap {
60092
60070
  */
60093
60071
  #load_factor = DEFAULT_LOAD_FACTOR;
60094
60072
 
60073
+ /**
60074
+ * Used to track modifications to prevent concurrent changes during iteration
60075
+ * @type {number}
60076
+ */
60095
60077
  #version = 0;
60096
60078
 
60097
60079
  /**
@@ -60204,6 +60186,25 @@ class HashMap {
60204
60186
  return original === RESERVED_HASH ? RESERVED_HASH_SUBSTITUTE : original;
60205
60187
  }
60206
60188
 
60189
+ /**
60190
+ * @param {HashMapEntry<K,V>} record
60191
+ * @param {number} hash
60192
+ * @param {K} key
60193
+ */
60194
+ #entry_equality_check(record, hash, key) {
60195
+ if (record.hash !== hash) {
60196
+ return false;
60197
+ }
60198
+
60199
+ if (record.key === key) {
60200
+ return true;
60201
+ }
60202
+
60203
+ const result = this.keyEqualityFunction(record.key, key);
60204
+
60205
+ return result;
60206
+ }
60207
+
60207
60208
  /**
60208
60209
  *
60209
60210
  * @param {K} k
@@ -60279,11 +60280,12 @@ class HashMap {
60279
60280
  // check if it's the entry that we're looking for
60280
60281
  const entry = this.#entries[bin - ENTRY_BASE];
60281
60282
 
60282
- if (entry_equality_check(entry, raw_hash, key, this.keyEqualityFunction)) {
60283
+ if (this.#entry_equality_check(entry, raw_hash, key)) {
60283
60284
  // found the right entry
60284
60285
  entry.value = value;
60285
60286
  return;
60286
60287
  }
60288
+
60287
60289
  } else if (bin === BIN_RESERVED_VALUE_EMPTY) {
60288
60290
  // bin is empty
60289
60291
 
@@ -60342,7 +60344,7 @@ class HashMap {
60342
60344
  // check if the entry is what we're looking for
60343
60345
  const entry = this.#entries[bin - ENTRY_BASE];
60344
60346
 
60345
- if (entry_equality_check(entry, raw_hash, key, this.keyEqualityFunction)) {
60347
+ if (this.#entry_equality_check(entry, raw_hash, key)) {
60346
60348
  // found the right entry
60347
60349
  return entry.value;
60348
60350
  }
@@ -60442,7 +60444,7 @@ class HashMap {
60442
60444
  const entry_index = bin - ENTRY_BASE;
60443
60445
  const entry = entries[entry_index];
60444
60446
 
60445
- if (entry_equality_check(entry, raw_hash, key, this.keyEqualityFunction)) {
60447
+ if (this.#entry_equality_check(entry, raw_hash, key)) {
60446
60448
  // found the right entry
60447
60449
 
60448
60450
  // record entry as dead
@@ -60776,16 +60778,27 @@ class CacheElement {
60776
60778
  next.previous = previous;
60777
60779
  }
60778
60780
  }
60781
+
60782
+ toString() {
60783
+ return `CacheElement{ hasNext:${this.next !== null}, hasPrevious:${this.previous !== null}, weight:${this.weight}, key:${this.key}, value:${this.value} }`;
60784
+ }
60779
60785
  }
60780
60786
 
60781
- // 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
60782
-
60783
60787
  /**
60784
60788
  * Hash-based cache, uses LRU (least-recently-used) eviction policy
60789
+ * Make sure that keys being used are truly immutable when it comes to hash and equality calculation, otherwise cache corruption is inevitable
60785
60790
  * @template Key, Value
60786
60791
  * @extends Map<Key,Value>
60787
60792
  */
60788
60793
  class Cache {
60794
+ #maxWeight = Number.POSITIVE_INFINITY;
60795
+ /**
60796
+ *
60797
+ * @type {number}
60798
+ * @private
60799
+ */
60800
+ #weight = 0;
60801
+
60789
60802
  /**
60790
60803
  * @param {number} [maxWeight=Number.POSITIVE_INFINITY]
60791
60804
  * @param {function(key:Key):number} [keyWeigher= key=>0]
@@ -60809,14 +60822,8 @@ class Cache {
60809
60822
  * @type {number}
60810
60823
  * @private
60811
60824
  */
60812
- this.maxWeight = maxWeight;
60825
+ this.#maxWeight = maxWeight;
60813
60826
 
60814
- /**
60815
- *
60816
- * @type {number}
60817
- * @private
60818
- */
60819
- this.weight = 0;
60820
60827
 
60821
60828
  /**
60822
60829
  *
@@ -60917,18 +60924,37 @@ class Cache {
60917
60924
  return this.data.size;
60918
60925
  }
60919
60926
 
60927
+ /**
60928
+ * @deprecated use {@link maxWeight} directly instead
60929
+ */
60930
+ setMaxWeight(value) {
60931
+ this.maxWeight = value;
60932
+ }
60933
+
60934
+ /**
60935
+ * Total weight of all elements currently in the cache
60936
+ * @returns {number}
60937
+ */
60938
+ get weight() {
60939
+ return this.#weight;
60940
+ }
60941
+
60920
60942
  /**
60921
60943
  * Will cause evictions if current weight is smaller than what we're setting
60922
60944
  * @param {number} value
60923
60945
  */
60924
- setMaxWeight(value) {
60946
+ set maxWeight(value) {
60925
60947
  if (typeof value !== "number" || value < 0) {
60926
60948
  throw new Error(`Weight must be a non-negative number, instead was '${value}'`);
60927
60949
  }
60928
60950
 
60929
- this.maxWeight = value;
60951
+ this.#maxWeight = value;
60952
+
60953
+ this.evictUntilWeight(this.#maxWeight);
60954
+ }
60930
60955
 
60931
- this.evictUntilWeight(this.maxWeight);
60956
+ get maxWeight() {
60957
+ return this.#maxWeight;
60932
60958
  }
60933
60959
 
60934
60960
  /**
@@ -60947,7 +60973,8 @@ class Cache {
60947
60973
  result += weight;
60948
60974
  }
60949
60975
 
60950
- this.weight = result;
60976
+ this.#weight = result;
60977
+ this.evictUntilWeight(this.#maxWeight);
60951
60978
  }
60952
60979
 
60953
60980
  /**
@@ -60977,13 +61004,13 @@ class Cache {
60977
61004
 
60978
61005
  const delta_weight = new_weight - old_weight;
60979
61006
 
60980
- this.weight += delta_weight;
61007
+ this.#weight += delta_weight;
60981
61008
 
60982
61009
  if (
60983
- this.weight > this.maxWeight
60984
- && new_weight <= this.maxWeight //make it less likely to drop entire cache
61010
+ this.#weight > this.#maxWeight
61011
+ && new_weight <= this.#maxWeight //make it less likely to drop entire cache
60985
61012
  ) {
60986
- this.evictUntilWeight(this.maxWeight);
61013
+ this.evictUntilWeight(this.#maxWeight);
60987
61014
  }
60988
61015
 
60989
61016
  return true;
@@ -61039,7 +61066,7 @@ class Cache {
61039
61066
 
61040
61067
  const target = Math.max(targetWeight, 0);
61041
61068
 
61042
- while (this.weight > target) {
61069
+ while (this.#weight > target) {
61043
61070
  this.evictOne();
61044
61071
  }
61045
61072
  }
@@ -61081,7 +61108,7 @@ class Cache {
61081
61108
  * in which case entire cache will be evicted, but there still won't be enough space
61082
61109
  * @type {number}
61083
61110
  */
61084
- const weightTarget = this.maxWeight - elementWeight;
61111
+ const weightTarget = this.#maxWeight - elementWeight;
61085
61112
 
61086
61113
  if (weightTarget < 0) {
61087
61114
  // Special case
@@ -61096,13 +61123,13 @@ class Cache {
61096
61123
  this.data.set(key, element);
61097
61124
 
61098
61125
  //update weight
61099
- this.weight += elementWeight;
61126
+ this.#weight += elementWeight;
61100
61127
  } else {
61101
61128
  // check if value is the same
61102
61129
  if (value === element.value) ; else {
61103
61130
  // replace value, adjust weight
61104
- this.weight -= this.valueWeigher(element.value);
61105
- this.weight += this.valueWeigher(value);
61131
+ this.#weight -= this.valueWeigher(element.value);
61132
+ this.#weight += this.valueWeigher(value);
61106
61133
 
61107
61134
  element.value = value;
61108
61135
  }
@@ -61188,7 +61215,7 @@ class Cache {
61188
61215
  this.data.delete(key);
61189
61216
 
61190
61217
  //update weight
61191
- this.weight -= element.weight;
61218
+ this.#weight -= element.weight;
61192
61219
  }
61193
61220
 
61194
61221
  /**
@@ -61260,7 +61287,7 @@ class Cache {
61260
61287
  this.__first = null;
61261
61288
  this.__last = null;
61262
61289
 
61263
- this.weight = 0;
61290
+ this.#weight = 0;
61264
61291
  }
61265
61292
 
61266
61293
  /**
@@ -63121,12 +63148,14 @@ class LineBuilder {
63121
63148
  *
63122
63149
  * @type {Line[]}
63123
63150
  */
63124
- lines = [];
63151
+ #lines = [];
63152
+
63125
63153
  /**
63126
63154
  *
63127
63155
  * @type {number}
63128
63156
  */
63129
- indentation = 0;
63157
+ #indentation = 0;
63158
+
63130
63159
  /**
63131
63160
  *
63132
63161
  * @type {number}
@@ -63138,7 +63167,7 @@ class LineBuilder {
63138
63167
  * @return {number}
63139
63168
  */
63140
63169
  get count() {
63141
- return this.lines.length;
63170
+ return this.#lines.length;
63142
63171
  }
63143
63172
 
63144
63173
  /**
@@ -63147,7 +63176,7 @@ class LineBuilder {
63147
63176
  * @param {string} term
63148
63177
  */
63149
63178
  containsSubstring(term) {
63150
- const lines = this.lines;
63179
+ const lines = this.#lines;
63151
63180
  const n = lines.length;
63152
63181
  for (let i = 0; i < n; i++) {
63153
63182
  const line = lines[i];
@@ -63167,7 +63196,7 @@ class LineBuilder {
63167
63196
  * @returns {LineBuilder}
63168
63197
  */
63169
63198
  indent() {
63170
- this.indentation++;
63199
+ this.#indentation++;
63171
63200
  return this;
63172
63201
  }
63173
63202
 
@@ -63176,7 +63205,7 @@ class LineBuilder {
63176
63205
  * @returns {LineBuilder}
63177
63206
  */
63178
63207
  dedent() {
63179
- this.indentation--;
63208
+ this.#indentation--;
63180
63209
  return this;
63181
63210
  }
63182
63211
 
@@ -63187,9 +63216,9 @@ class LineBuilder {
63187
63216
  */
63188
63217
  add(line_text) {
63189
63218
 
63190
- const line = new Line(line_text, this.indentation);
63219
+ const line = new Line(line_text, this.#indentation);
63191
63220
 
63192
- this.lines.push(line);
63221
+ this.#lines.push(line);
63193
63222
 
63194
63223
  return this;
63195
63224
  }
@@ -63200,23 +63229,23 @@ class LineBuilder {
63200
63229
  */
63201
63230
  addLines(lines) {
63202
63231
 
63203
- const other_lines = lines.lines;
63232
+ const other_lines = lines.#lines;
63204
63233
 
63205
63234
  const other_line_count = other_lines.length;
63206
63235
 
63207
63236
  for (let i = 0; i < other_line_count; i++) {
63208
63237
  const otherLine = other_lines[i];
63209
63238
 
63210
- const line = new Line(otherLine.text, otherLine.indentation + this.indentation);
63239
+ const line = new Line(otherLine.text, otherLine.indentation + this.#indentation);
63211
63240
 
63212
- this.lines.push(line);
63241
+ this.#lines.push(line);
63213
63242
  }
63214
63243
 
63215
63244
  }
63216
63245
 
63217
63246
  clear() {
63218
- this.lines = [];
63219
- this.indentation = 0;
63247
+ this.#lines = [];
63248
+ this.#indentation = 0;
63220
63249
  }
63221
63250
 
63222
63251
  /**
@@ -63228,7 +63257,7 @@ class LineBuilder {
63228
63257
 
63229
63258
  let i, j, l;
63230
63259
 
63231
- const lines = this.lines;
63260
+ const lines = this.#lines;
63232
63261
 
63233
63262
  for (i = 0, l = lines.length; i < l; i++) {
63234
63263
  const line = lines[i];
@@ -63261,7 +63290,9 @@ class LineBuilder {
63261
63290
 
63262
63291
  for (let i = 0; i < n; i++) {
63263
63292
 
63264
- r.add(lines[i]);
63293
+ const line_text = lines[i];
63294
+
63295
+ r.add(line_text);
63265
63296
 
63266
63297
  }
63267
63298
 
@@ -66275,7 +66306,7 @@ class GeometrySpatialQueryAccelerator {
66275
66306
  * @param {number} value in bytes
66276
66307
  */
66277
66308
  set cache_size(value) {
66278
- this.cache.setMaxWeight(value);
66309
+ this.cache.maxWeight = value;
66279
66310
  }
66280
66311
 
66281
66312
  /**
@@ -208,7 +208,7 @@ export class BlenderCameraOrientationGizmo extends CanvasView {
208
208
  direction: new Vector3(0, 0, -1),
209
209
  size: this.options.bubbleSizeSecondary,
210
210
  style: this.options.axisStyles.nz,
211
- label: "-Y",
211
+ label: "-Z",
212
212
  labelHideUnselected: true,
213
213
  primary: false
214
214
  },
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.104.0",
8
+ "version": "2.105.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Compute morton codes for each triangle
3
- * @param {number[]|Uint32Array} morton_codes
3
+ * @param {number[]|Uint32Array} morton_codes output where the morton codes are to be written to, matching order in {@link index_array}
4
4
  * @param {number} tri_count
5
5
  * @param {number[]|Uint8Array|Uint16Array|Uint32Array} index_array
6
6
  * @param {number[]|Float32Array} position_array
@@ -1 +1 @@
1
- {"version":3,"file":"build_triangle_morton_codes.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/build_triangle_morton_codes.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,0DAXW,MAAM,EAAE,GAAC,WAAW,aACpB,MAAM,eACN,MAAM,EAAE,GAAC,UAAU,GAAC,WAAW,GAAC,WAAW,kBAC3C,MAAM,EAAE,GAAC,YAAY,WACrB,MAAM,WACN,MAAM,WACN,MAAM,WACN,MAAM,WACN,MAAM,WACN,MAAM,QA4DhB"}
1
+ {"version":3,"file":"build_triangle_morton_codes.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/build_triangle_morton_codes.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,0DAXW,MAAM,EAAE,GAAC,WAAW,aACpB,MAAM,eACN,MAAM,EAAE,GAAC,UAAU,GAAC,WAAW,GAAC,WAAW,kBAC3C,MAAM,EAAE,GAAC,YAAY,WACrB,MAAM,WACN,MAAM,WACN,MAAM,WACN,MAAM,WACN,MAAM,WACN,MAAM,QA8DhB"}
@@ -2,7 +2,7 @@ import morton from "../../geom/3d/morton/Morton.js";
2
2
 
3
3
  /**
4
4
  * Compute morton codes for each triangle
5
- * @param {number[]|Uint32Array} morton_codes
5
+ * @param {number[]|Uint32Array} morton_codes output where the morton codes are to be written to, matching order in {@link index_array}
6
6
  * @param {number} tri_count
7
7
  * @param {number[]|Uint8Array|Uint16Array|Uint32Array} index_array
8
8
  * @param {number[]|Float32Array} position_array
@@ -37,10 +37,12 @@ export function build_triangle_morton_codes(
37
37
 
38
38
  const i3 = i * 3;
39
39
 
40
+ // read indices
40
41
  const a = index_array[i3];
41
42
  const b = index_array[i3 + 1];
42
43
  const c = index_array[i3 + 2];
43
44
 
45
+ // read vertex positions
44
46
  const a_address = a * 3;
45
47
  const ax = position_array[a_address];
46
48
  const ay = position_array[a_address + 1];
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * Given a set of leaves, build intermediate node hierarchy on top, all the way up to the root
2
3
  * Assumes nodes are spatially sorted
3
4
  * NOTE: {@link unprocessed_nodes} will be modified during execution to save memory
4
5
  * @param {BVH} bvh
@@ -1 +1 @@
1
- {"version":3,"file":"ebvh_build_hierarchy.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_build_hierarchy.js"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,kEANW,MAAM,EAAE,GAAC,WAAW,oBACpB,MAAM,aACN,MAAM,EAAE,GAAC,WAAW,oBACpB,MAAM,GACJ,MAAM,CAyDlB"}
1
+ {"version":3,"file":"ebvh_build_hierarchy.d.ts","sourceRoot":"","sources":["../../../../../src/core/bvh2/bvh3/ebvh_build_hierarchy.js"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,kEANW,MAAM,EAAE,GAAC,WAAW,oBACpB,MAAM,aACN,MAAM,EAAE,GAAC,WAAW,oBACpB,MAAM,GACJ,MAAM,CAyDlB"}
@@ -2,6 +2,7 @@ import { assert } from "../../assert.js";
2
2
  import { max2 } from "../../math/max2.js";
3
3
 
4
4
  /**
5
+ * Given a set of leaves, build intermediate node hierarchy on top, all the way up to the root
5
6
  * Assumes nodes are spatially sorted
6
7
  * NOTE: {@link unprocessed_nodes} will be modified during execution to save memory
7
8
  * @param {BVH} bvh
@@ -19,8 +20,8 @@ export function ebvh_build_hierarchy(
19
20
  node_pool_offset
20
21
  ) {
21
22
 
22
- assert.isNonNegativeInteger(input_node_count,'input_node_count');
23
- assert.isNonNegativeInteger(node_pool_offset,'node_pool_offset');
23
+ assert.isNonNegativeInteger(input_node_count, 'input_node_count');
24
+ assert.isNonNegativeInteger(node_pool_offset, 'node_pool_offset');
24
25
 
25
26
  let used_index = node_pool_offset;
26
27
 
@@ -21,7 +21,8 @@ export class Cache<K, V> {
21
21
  readonly onRemoved: Signal<K, V>
22
22
 
23
23
  readonly weight: number
24
- readonly maxWeight: number
24
+
25
+ maxWeight: number
25
26
 
26
27
  size(): number
27
28
 
@@ -1 +1 @@
1
- {"version":3,"file":"Cache.d.ts","sourceRoot":"","sources":["../../../../src/core/cache/Cache.js"],"names":[],"mappings":"AAWA;;;;GAIG;AACH;IACI;;;;;;;;OAQG;IACH,sGARW,MAAM,EA6FhB;IAtEG;;;;OAIG;IACH,kBAA0B;IAE1B;;;;OAIG;IACH,eAAe;IAEf;;;;OAIG;IACH,mBAA4B;IAE5B;;;;OAIG;IACH,qBAAgC;IAEhC;;;;OAIG;IACH,gBAAmB;IACnB;;;;OAIG;IACH,eAAkB;IAGlB;;;;OAIG;IACH,aAIE;IAEF;;;OAGG;IACH,WAFU,OAAO,GAAG,EAAC,KAAK,CAAC,CAEE;IAE7B;;;OAGG;IACH,WAFU,OAAO,GAAG,EAAC,KAAK,CAAC,CAEE;IAE7B;;;OAGG;IACH,OAFU,OAAO,GAAG,EAAC,KAAK,CAAC,CAEF;IAG7B;;;;;OAKG;IACH,kBAyBC;IAED;;;OAGG;IACH,QAFa,MAAM,CAIlB;IAED;;;OAGG;IACH,oBAFW,MAAM,QAUhB;IAED;;;;OAIG;IACH,wBAYC;IAED;;;;;;OAMG;IACH,yBAHW,GAAG,GACD,OAAO,CAgCnB;IAED;;;;;OAKG;IACH,6BAUC;IAED;;;OAGG;IACH,sBAFa,aAAa,GAAG,EAAC,KAAK,CAAC,GAAC,IAAI,CAIxC;IAED;;;OAGG;IACH,YAFa,OAAO,CAgBnB;IAED;;;OAGG;IACH,+BAFW,MAAM,QAWhB;IAED;;;;OAIG;IACH,SAHW,GAAG,SACH,KAAK,QAoEf;IAED;;;;OAIG;IACH,cAHW,GAAG,GACD,OAAO,CAInB;IAED;;;;OAIG;IACH,SAHW,GAAG,GACD,KAAK,GAAC,IAAI,CAYtB;IAGD;;;;;;OAMG;IACH,kBALW,GAAG,kBACM,GAAG,KAAE,KAAK,0BAElB,KAAK,CAchB;IAED;;;;OAIG;IACH,wBAqBC;IAED;;;;OAIG;IACH,YAHW,GAAG,GACD,OAAO,CAgBnB;IAED;;;;;OAKG;IACH,kBAHW,GAAG,GACD,OAAO,CAanB;IAED;;OAEG;IACH,cAcC;IAED;;;OAGG;IACH,aAOC;IAED;;;;;OAKG;IACH,wCAFa,OAAO,CAMnB;IAGL;;;OAGG;IACH,6CAAmB;IAEnB;;;OAGG;IACH,+BA5FiB,OAAO,CA4FF;IAEtB;;;OAGG;IACH,4BA9KiB,OAAO,CA8KL;CAlBlB;mBApgBkB,4BAA4B;6BAIlB,mBAAmB"}
1
+ {"version":3,"file":"Cache.d.ts","sourceRoot":"","sources":["../../../../src/core/cache/Cache.js"],"names":[],"mappings":"AASA;;;;;GAKG;AACH;IASI;;;;;;;;OAQG;IACH,sGARW,MAAM,EAuFhB;IAxDG;;;;OAIG;IACH,mBAA4B;IAE5B;;;;OAIG;IACH,qBAAgC;IAEhC;;;;OAIG;IACH,gBAAmB;IACnB;;;;OAIG;IACH,eAAkB;IAGlB;;;;OAIG;IACH,aAIE;IAEF;;;OAGG;IACH,WAFU,OAAO,GAAG,EAAC,KAAK,CAAC,CAEE;IAE7B;;;OAGG;IACH,WAFU,OAAO,GAAG,EAAC,KAAK,CAAC,CAEE;IAE7B;;;OAGG;IACH,OAFU,OAAO,GAAG,EAAC,KAAK,CAAC,CAEF;IAG7B;;;;;OAKG;IACH,kBAyBC;IAED;;;OAGG;IACH,QAFa,MAAM,CAIlB;IAED;;OAEG;IACH,+BAEC;IAUD;;;OAGG;IACH,2BAQC;IAED,wBAEC;IAxBD;;;OAGG;IACH,qBAEC;IAoBD;;;;OAIG;IACH,wBAaC;IAED;;;;;;OAMG;IACH,yBAHW,GAAG,GACD,OAAO,CAgCnB;IAED;;;;;OAKG;IACH,6BAUC;IAED;;;OAGG;IACH,sBAFa,aAAa,GAAG,EAAC,KAAK,CAAC,GAAC,IAAI,CAIxC;IAED;;;OAGG;IACH,YAFa,OAAO,CAkBnB;IAED;;;OAGG;IACH,+BAFW,MAAM,QAWhB;IAED;;;;OAIG;IACH,SAHW,GAAG,SACH,KAAK,QAoEf;IAED;;;;OAIG;IACH,cAHW,GAAG,GACD,OAAO,CAInB;IAED;;;;OAIG;IACH,SAHW,GAAG,GACD,KAAK,GAAC,IAAI,CAYtB;IAGD;;;;;;OAMG;IACH,kBALW,GAAG,kBACM,GAAG,KAAE,KAAK,0BAElB,KAAK,CAchB;IAED;;;;OAIG;IACH,wBAqBC;IAED;;;;OAIG;IACH,YAHW,GAAG,GACD,OAAO,CAgBnB;IAED;;;;;OAKG;IACH,kBAHW,GAAG,GACD,OAAO,CAanB;IAED;;OAEG;IACH,cAcC;IAED;;;OAGG;IACH,aAOC;IAED;;;;;OAKG;IACH,wCAFa,OAAO,CAMnB;IAGL;;;OAGG;IACH,6CAAmB;IAEnB;;;OAGG;IACH,+BA5FiB,OAAO,CA4FF;IAEtB;;;OAGG;IACH,4BA9KiB,OAAO,CA8KL;;CAlBlB;mBA3hBkB,4BAA4B;6BAIlB,mBAAmB"}
@@ -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;
165
181
 
166
- this.evictUntilWeight(this.maxWeight);
182
+ this.evictUntilWeight(this.#maxWeight);
183
+ }
184
+
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
  }
@@ -322,7 +345,7 @@ export class Cache {
322
345
  * in which case entire cache will be evicted, but there still won't be enough space
323
346
  * @type {number}
324
347
  */
325
- const weightTarget = this.maxWeight - elementWeight;
348
+ const weightTarget = this.#maxWeight - elementWeight;
326
349
 
327
350
  if (weightTarget < 0) {
328
351
  // Special case
@@ -337,15 +360,15 @@ export class Cache {
337
360
  this.data.set(key, element);
338
361
 
339
362
  //update weight
340
- this.weight += elementWeight;
363
+ this.#weight += elementWeight;
341
364
  } else {
342
365
  // check if value is the same
343
366
  if (value === element.value) {
344
367
  // same value, no action required
345
368
  } else {
346
369
  // replace value, adjust weight
347
- this.weight -= this.valueWeigher(element.value);
348
- this.weight += this.valueWeigher(value);
370
+ this.#weight -= this.valueWeigher(element.value);
371
+ this.#weight += this.valueWeigher(value);
349
372
 
350
373
  element.value = value;
351
374
  }
@@ -431,7 +454,7 @@ export class Cache {
431
454
  this.data.delete(key);
432
455
 
433
456
  //update weight
434
- this.weight -= element.weight;
457
+ this.#weight -= element.weight;
435
458
  }
436
459
 
437
460
  /**
@@ -503,7 +526,7 @@ export class Cache {
503
526
  this.__first = null;
504
527
  this.__last = null;
505
528
 
506
- this.weight = 0;
529
+ this.#weight = 0;
507
530
  }
508
531
 
509
532
  /**