data-structure-typed 2.4.4 → 2.4.5

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 (41) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/README.md +24 -1
  3. package/dist/cjs/index.cjs +459 -132
  4. package/dist/cjs-legacy/index.cjs +459 -130
  5. package/dist/esm/index.mjs +459 -133
  6. package/dist/esm-legacy/index.mjs +459 -131
  7. package/dist/types/common/error.d.ts +23 -0
  8. package/dist/types/common/index.d.ts +1 -0
  9. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +10 -0
  10. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +7 -1
  11. package/dist/types/data-structures/graph/abstract-graph.d.ts +44 -0
  12. package/dist/types/data-structures/graph/directed-graph.d.ts +1 -0
  13. package/dist/types/data-structures/graph/undirected-graph.d.ts +14 -0
  14. package/dist/types/data-structures/queue/deque.d.ts +41 -1
  15. package/dist/types/types/data-structures/queue/deque.d.ts +6 -0
  16. package/dist/umd/data-structure-typed.js +458 -129
  17. package/dist/umd/data-structure-typed.min.js +4 -2
  18. package/package.json +2 -2
  19. package/src/common/error.ts +60 -0
  20. package/src/common/index.ts +2 -0
  21. package/src/data-structures/base/iterable-element-base.ts +3 -2
  22. package/src/data-structures/binary-tree/binary-indexed-tree.ts +6 -5
  23. package/src/data-structures/binary-tree/binary-tree.ts +113 -42
  24. package/src/data-structures/binary-tree/bst.ts +11 -3
  25. package/src/data-structures/binary-tree/red-black-tree.ts +20 -0
  26. package/src/data-structures/binary-tree/tree-map.ts +8 -7
  27. package/src/data-structures/binary-tree/tree-multi-map.ts +4 -4
  28. package/src/data-structures/binary-tree/tree-multi-set.ts +5 -4
  29. package/src/data-structures/binary-tree/tree-set.ts +7 -6
  30. package/src/data-structures/graph/abstract-graph.ts +106 -1
  31. package/src/data-structures/graph/directed-graph.ts +4 -0
  32. package/src/data-structures/graph/undirected-graph.ts +95 -0
  33. package/src/data-structures/hash/hash-map.ts +13 -2
  34. package/src/data-structures/heap/heap.ts +4 -3
  35. package/src/data-structures/heap/max-heap.ts +2 -3
  36. package/src/data-structures/matrix/matrix.ts +9 -10
  37. package/src/data-structures/priority-queue/max-priority-queue.ts +2 -3
  38. package/src/data-structures/queue/deque.ts +71 -3
  39. package/src/data-structures/trie/trie.ts +2 -1
  40. package/src/types/data-structures/queue/deque.ts +7 -0
  41. package/src/utils/utils.ts +4 -2
@@ -185,6 +185,55 @@ var IterableEntryBase = class {
185
185
  }
186
186
  };
187
187
 
188
+ // src/common/error.ts
189
+ var ERR = {
190
+ // Range / index
191
+ indexOutOfRange: /* @__PURE__ */ __name((index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`, "indexOutOfRange"),
192
+ invalidIndex: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`, "invalidIndex"),
193
+ // Type / argument
194
+ invalidArgument: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidArgument"),
195
+ comparatorRequired: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`, "comparatorRequired"),
196
+ invalidKey: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidKey"),
197
+ notAFunction: /* @__PURE__ */ __name((name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`, "notAFunction"),
198
+ invalidEntry: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`, "invalidEntry"),
199
+ invalidNaN: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`, "invalidNaN"),
200
+ invalidDate: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`, "invalidDate"),
201
+ reduceEmpty: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`, "reduceEmpty"),
202
+ callbackReturnType: /* @__PURE__ */ __name((expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`, "callbackReturnType"),
203
+ // State / operation
204
+ invalidOperation: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidOperation"),
205
+ // Matrix
206
+ matrixDimensionMismatch: /* @__PURE__ */ __name((op) => `Matrix: Dimensions must be compatible for ${op}.`, "matrixDimensionMismatch"),
207
+ matrixSingular: /* @__PURE__ */ __name(() => "Matrix: Singular matrix, inverse does not exist.", "matrixSingular"),
208
+ matrixNotSquare: /* @__PURE__ */ __name(() => "Matrix: Must be square for inversion.", "matrixNotSquare"),
209
+ matrixNotRectangular: /* @__PURE__ */ __name(() => "Matrix: Must be rectangular for transposition.", "matrixNotRectangular"),
210
+ matrixRowMismatch: /* @__PURE__ */ __name((expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`, "matrixRowMismatch")
211
+ };
212
+
213
+ // src/common/index.ts
214
+ var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
215
+ DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
216
+ DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
217
+ return DFSOperation2;
218
+ })(DFSOperation || {});
219
+ var Range = class {
220
+ constructor(low, high, includeLow = true, includeHigh = true) {
221
+ this.low = low;
222
+ this.high = high;
223
+ this.includeLow = includeLow;
224
+ this.includeHigh = includeHigh;
225
+ }
226
+ static {
227
+ __name(this, "Range");
228
+ }
229
+ // Determine whether a key is within the range
230
+ isInRange(key, comparator) {
231
+ const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
232
+ const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
233
+ return lowCheck && highCheck;
234
+ }
235
+ };
236
+
188
237
  // src/data-structures/base/iterable-element-base.ts
189
238
  var IterableElementBase = class {
190
239
  static {
@@ -203,7 +252,7 @@ var IterableElementBase = class {
203
252
  if (options) {
204
253
  const { toElementFn } = options;
205
254
  if (typeof toElementFn === "function") this._toElementFn = toElementFn;
206
- else if (toElementFn) throw new TypeError("toElementFn must be a function type");
255
+ else if (toElementFn) throw new TypeError(ERR.notAFunction("toElementFn"));
207
256
  }
208
257
  }
209
258
  /**
@@ -366,7 +415,7 @@ var IterableElementBase = class {
366
415
  acc = initialValue;
367
416
  } else {
368
417
  const first = iter.next();
369
- if (first.done) throw new TypeError("Reduce of empty structure with no initial value");
418
+ if (first.done) throw new TypeError(ERR.reduceEmpty());
370
419
  acc = first.value;
371
420
  index = 1;
372
421
  }
@@ -434,8 +483,10 @@ var getMSB = /* @__PURE__ */ __name((value) => {
434
483
  }
435
484
  return 1 << 31 - Math.clz32(value);
436
485
  }, "getMSB");
437
- var rangeCheck = /* @__PURE__ */ __name((index, min, max, message = "Index out of bounds.") => {
438
- if (index < min || index > max) throw new RangeError(message);
486
+ var rangeCheck = /* @__PURE__ */ __name((index, min, max, message) => {
487
+ if (index < min || index > max) {
488
+ throw new RangeError(message ?? `Index ${index} is out of range [${min}, ${max}].`);
489
+ }
439
490
  }, "rangeCheck");
440
491
  var throwRangeError = /* @__PURE__ */ __name((message = "The value is off-limits.") => {
441
492
  throw new RangeError(message);
@@ -858,8 +909,8 @@ var LinkedHashMap = class extends IterableEntryBase {
858
909
  if (this.isEntry(rawElement)) {
859
910
  return rawElement;
860
911
  }
861
- throw new Error(
862
- "If `entryOrRawElements` does not adhere to [key,value], provide `options.toEntryFn` to transform raw records."
912
+ throw new TypeError(
913
+ ERR.invalidArgument("If elements do not adhere to [key, value], provide options.toEntryFn to transform raw records.", "HashMap")
863
914
  );
864
915
  }, "_toEntryFn");
865
916
  get toEntryFn() {
@@ -1096,6 +1147,13 @@ var LinkedHashMap = class extends IterableEntryBase {
1096
1147
  }
1097
1148
  }
1098
1149
  _deleteNode(node) {
1150
+ const key = node.key;
1151
+ if (isWeakKey(key)) {
1152
+ this._objMap.delete(key);
1153
+ } else {
1154
+ const hash = this._hashFn(key);
1155
+ delete this._noObjMap[hash];
1156
+ }
1099
1157
  const { prev, next } = node;
1100
1158
  prev.next = next;
1101
1159
  next.prev = prev;
@@ -3610,18 +3668,12 @@ var Deque = class extends LinearBase {
3610
3668
  __name(this, "Deque");
3611
3669
  }
3612
3670
  _equals = /* @__PURE__ */ __name((a, b) => Object.is(a, b), "_equals");
3613
- /**
3614
- * Create a Deque and optionally bulk-insert elements.
3615
- * @remarks Time O(N), Space O(N)
3616
- * @param [elements] - Iterable (or iterable-like) of elements/records to insert.
3617
- * @param [options] - Options such as bucketSize, toElementFn, and maxLen.
3618
- * @returns New Deque instance.
3619
- */
3620
3671
  constructor(elements = [], options) {
3621
3672
  super(options);
3622
3673
  if (options) {
3623
- const { bucketSize } = options;
3674
+ const { bucketSize, autoCompactRatio } = options;
3624
3675
  if (typeof bucketSize === "number") this._bucketSize = bucketSize;
3676
+ if (typeof autoCompactRatio === "number") this._autoCompactRatio = autoCompactRatio;
3625
3677
  }
3626
3678
  let _size;
3627
3679
  if ("length" in elements) {
@@ -3647,6 +3699,30 @@ var Deque = class extends LinearBase {
3647
3699
  get bucketSize() {
3648
3700
  return this._bucketSize;
3649
3701
  }
3702
+ _autoCompactRatio = 0.5;
3703
+ /**
3704
+ * Get the auto-compaction ratio.
3705
+ * When `elements / (bucketCount * bucketSize)` drops below this ratio after
3706
+ * enough shift/pop operations, the deque auto-compacts.
3707
+ * @remarks Time O(1), Space O(1)
3708
+ * @returns Current ratio threshold. 0 means auto-compact is disabled.
3709
+ */
3710
+ get autoCompactRatio() {
3711
+ return this._autoCompactRatio;
3712
+ }
3713
+ /**
3714
+ * Set the auto-compaction ratio.
3715
+ * @remarks Time O(1), Space O(1)
3716
+ * @param value - Ratio in [0,1]. 0 disables auto-compact.
3717
+ */
3718
+ set autoCompactRatio(value) {
3719
+ this._autoCompactRatio = value;
3720
+ }
3721
+ /**
3722
+ * Counter for shift/pop operations since last compaction check.
3723
+ * Only checks ratio every `_bucketSize` operations to minimize overhead.
3724
+ */
3725
+ _compactCounter = 0;
3650
3726
  _bucketFirst = 0;
3651
3727
  /**
3652
3728
  * Get the index of the first bucket in use.
@@ -3785,6 +3861,7 @@ var Deque = class extends LinearBase {
3785
3861
  }
3786
3862
  }
3787
3863
  this._length -= 1;
3864
+ this._autoCompact();
3788
3865
  return element;
3789
3866
  }
3790
3867
  /**
@@ -3807,6 +3884,7 @@ var Deque = class extends LinearBase {
3807
3884
  }
3808
3885
  }
3809
3886
  this._length -= 1;
3887
+ this._autoCompact();
3810
3888
  return element;
3811
3889
  }
3812
3890
  /**
@@ -4139,11 +4217,40 @@ var Deque = class extends LinearBase {
4139
4217
  * @remarks Time O(N), Space O(1)
4140
4218
  * @returns void
4141
4219
  */
4220
+ /**
4221
+ * (Protected) Trigger auto-compaction if space utilization drops below threshold.
4222
+ * Only checks every `_bucketSize` operations to minimize hot-path overhead.
4223
+ * Uses element-based ratio: `elements / (bucketCount * bucketSize)`.
4224
+ */
4225
+ _autoCompact() {
4226
+ if (this._autoCompactRatio <= 0 || this._bucketCount <= 1) return;
4227
+ this._compactCounter++;
4228
+ if (this._compactCounter < this._bucketSize) return;
4229
+ this._compactCounter = 0;
4230
+ const utilization = this._length / (this._bucketCount * this._bucketSize);
4231
+ if (utilization < this._autoCompactRatio) {
4232
+ this.shrinkToFit();
4233
+ }
4234
+ }
4235
+ /**
4236
+ * Compact the deque by removing unused buckets.
4237
+ * @remarks Time O(N), Space O(1)
4238
+ * @returns True if compaction was performed (bucket count reduced).
4239
+ */
4240
+ /**
4241
+ * Compact the deque by removing unused buckets.
4242
+ * @remarks Time O(N), Space O(1)
4243
+ * @returns True if compaction was performed (bucket count reduced).
4244
+ */
4245
+ compact() {
4246
+ const before = this._bucketCount;
4247
+ this.shrinkToFit();
4248
+ return this._bucketCount < before;
4249
+ }
4142
4250
  shrinkToFit() {
4143
4251
  if (this._length === 0) return;
4144
4252
  const newBuckets = [];
4145
- if (this._bucketFirst === this._bucketLast) return;
4146
- else if (this._bucketFirst < this._bucketLast) {
4253
+ if (this._bucketFirst <= this._bucketLast) {
4147
4254
  for (let i = this._bucketFirst; i <= this._bucketLast; ++i) {
4148
4255
  newBuckets.push(this._buckets[i]);
4149
4256
  }
@@ -4158,6 +4265,8 @@ var Deque = class extends LinearBase {
4158
4265
  this._bucketFirst = 0;
4159
4266
  this._bucketLast = newBuckets.length - 1;
4160
4267
  this._buckets = newBuckets;
4268
+ this._bucketCount = newBuckets.length;
4269
+ this._compactCounter = 0;
4161
4270
  }
4162
4271
  /**
4163
4272
  * Deep clone this deque, preserving options.
@@ -4656,7 +4765,7 @@ var Heap = class _Heap extends IterableElementBase {
4656
4765
  */
4657
4766
  map(callback, options, thisArg) {
4658
4767
  const { comparator, toElementFn, ...rest } = options ?? {};
4659
- if (!comparator) throw new TypeError("Heap.map requires options.comparator for EM");
4768
+ if (!comparator) throw new TypeError(ERR.comparatorRequired("Heap.map"));
4660
4769
  const out = this._createLike([], { ...rest, comparator, toElementFn });
4661
4770
  let i = 0;
4662
4771
  for (const x of this) {
@@ -4683,7 +4792,7 @@ var Heap = class _Heap extends IterableElementBase {
4683
4792
  }
4684
4793
  _DEFAULT_COMPARATOR = /* @__PURE__ */ __name((a, b) => {
4685
4794
  if (typeof a === "object" || typeof b === "object") {
4686
- throw TypeError("When comparing object types, define a custom comparator in options.");
4795
+ throw new TypeError(ERR.comparatorRequired("Heap"));
4687
4796
  }
4688
4797
  if (a > b) return 1;
4689
4798
  if (a < b) return -1;
@@ -4795,7 +4904,7 @@ var FibonacciHeap = class {
4795
4904
  constructor(comparator) {
4796
4905
  this.clear();
4797
4906
  this._comparator = comparator || this._defaultComparator;
4798
- if (typeof this.comparator !== "function") throw new Error("FibonacciHeap: comparator must be a function.");
4907
+ if (typeof this.comparator !== "function") throw new TypeError(ERR.notAFunction("comparator", "FibonacciHeap"));
4799
4908
  }
4800
4909
  _root;
4801
4910
  /**
@@ -5011,9 +5120,7 @@ var MaxHeap = class extends Heap {
5011
5120
  super(elements, {
5012
5121
  comparator: /* @__PURE__ */ __name((a, b) => {
5013
5122
  if (typeof a === "object" || typeof b === "object") {
5014
- throw TypeError(
5015
- `When comparing object types, a custom comparator must be defined in the constructor's options parameter.`
5016
- );
5123
+ throw new TypeError(ERR.comparatorRequired("MaxHeap"));
5017
5124
  }
5018
5125
  if (a < b) return 1;
5019
5126
  if (a > b) return -1;
@@ -5182,7 +5289,7 @@ var AbstractGraph = class extends IterableEntryBase {
5182
5289
  const newEdge = this.createEdge(srcOrEdge, dest, weight, value);
5183
5290
  return this._addEdge(newEdge);
5184
5291
  } else {
5185
- throw new Error("dest must be a Vertex or vertex key while srcOrEdge is an Edge");
5292
+ throw new TypeError(ERR.invalidArgument("dest must be a Vertex or vertex key when srcOrEdge is an Edge.", "Graph"));
5186
5293
  }
5187
5294
  }
5188
5295
  }
@@ -5862,6 +5969,92 @@ var AbstractGraph = class extends IterableEntryBase {
5862
5969
  _getVertexKey(vertexOrKey) {
5863
5970
  return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey;
5864
5971
  }
5972
+ /**
5973
+ * The edge connector string used in visual output.
5974
+ * Override in subclasses (e.g., '--' for undirected, '->' for directed).
5975
+ */
5976
+ get _edgeConnector() {
5977
+ return "--";
5978
+ }
5979
+ /**
5980
+ * Generate a text-based visual representation of the graph.
5981
+ *
5982
+ * **Adjacency list format:**
5983
+ * ```
5984
+ * Graph (5 vertices, 6 edges):
5985
+ * A -> B (1), C (2)
5986
+ * B -> D (3)
5987
+ * C -> (no outgoing edges)
5988
+ * D -> A (1)
5989
+ * E (isolated)
5990
+ * ```
5991
+ *
5992
+ * @param options - Optional display settings.
5993
+ * @param options.showWeight - Whether to show edge weights (default: true).
5994
+ * @returns The visual string.
5995
+ */
5996
+ toVisual(options) {
5997
+ const showWeight = options?.showWeight ?? true;
5998
+ const vertices = [...this._vertexMap.values()];
5999
+ const vertexCount = vertices.length;
6000
+ const edgeCount = this.edgeSet().length;
6001
+ const lines = [`Graph (${vertexCount} vertices, ${edgeCount} edges):`];
6002
+ for (const vertex of vertices) {
6003
+ const neighbors = this.getNeighbors(vertex);
6004
+ if (neighbors.length === 0) {
6005
+ lines.push(` ${vertex.key} (isolated)`);
6006
+ } else {
6007
+ const edgeStrs = neighbors.map((neighbor) => {
6008
+ const edge = this.getEdge(vertex, neighbor);
6009
+ if (edge && showWeight && edge.weight !== void 0 && edge.weight !== 1) {
6010
+ return `${neighbor.key} (${edge.weight})`;
6011
+ }
6012
+ return `${neighbor.key}`;
6013
+ });
6014
+ lines.push(` ${vertex.key} ${this._edgeConnector} ${edgeStrs.join(", ")}`);
6015
+ }
6016
+ }
6017
+ return lines.join("\n");
6018
+ }
6019
+ /**
6020
+ * Generate DOT language representation for Graphviz.
6021
+ *
6022
+ * @param options - Optional display settings.
6023
+ * @param options.name - Graph name (default: 'G').
6024
+ * @param options.showWeight - Whether to label edges with weight (default: true).
6025
+ * @returns DOT format string.
6026
+ */
6027
+ toDot(options) {
6028
+ const name = options?.name ?? "G";
6029
+ const showWeight = options?.showWeight ?? true;
6030
+ const isDirected = this._edgeConnector === "->";
6031
+ const graphType = isDirected ? "digraph" : "graph";
6032
+ const edgeOp = isDirected ? "->" : "--";
6033
+ const lines = [`${graphType} ${name} {`];
6034
+ for (const vertex of this._vertexMap.values()) {
6035
+ lines.push(` "${vertex.key}";`);
6036
+ }
6037
+ const visited = /* @__PURE__ */ new Set();
6038
+ for (const vertex of this._vertexMap.values()) {
6039
+ for (const neighbor of this.getNeighbors(vertex)) {
6040
+ const edgeId = isDirected ? `${vertex.key}->${neighbor.key}` : [vertex.key, neighbor.key].sort().join("--");
6041
+ if (visited.has(edgeId)) continue;
6042
+ visited.add(edgeId);
6043
+ const edge = this.getEdge(vertex, neighbor);
6044
+ const label = edge && showWeight && edge.weight !== void 0 && edge.weight !== 1 ? ` [label="${edge.weight}"]` : "";
6045
+ lines.push(` "${vertex.key}" ${edgeOp} "${neighbor.key}"${label};`);
6046
+ }
6047
+ }
6048
+ lines.push("}");
6049
+ return lines.join("\n");
6050
+ }
6051
+ /**
6052
+ * Print the graph to console.
6053
+ * @param options - Display settings passed to `toVisual`.
6054
+ */
6055
+ print(options) {
6056
+ console.log(this.toVisual(options));
6057
+ }
5865
6058
  };
5866
6059
 
5867
6060
  // src/data-structures/graph/directed-graph.ts
@@ -5897,6 +6090,9 @@ var DirectedGraph = class _DirectedGraph extends AbstractGraph {
5897
6090
  constructor(options) {
5898
6091
  super(options);
5899
6092
  }
6093
+ get _edgeConnector() {
6094
+ return "->";
6095
+ }
5900
6096
  _outEdgeMap = /* @__PURE__ */ new Map();
5901
6097
  get outEdgeMap() {
5902
6098
  return this._outEdgeMap;
@@ -6678,6 +6874,84 @@ var UndirectedGraph = class _UndirectedGraph extends AbstractGraph {
6678
6874
  cutVertices
6679
6875
  };
6680
6876
  }
6877
+ /**
6878
+ * Find biconnected components using edge-stack Tarjan variant.
6879
+ * A biconnected component is a maximal biconnected subgraph.
6880
+ * @returns Array of edge arrays, each representing a biconnected component.
6881
+ * @remarks Time O(V + E), Space O(V + E)
6882
+ */
6883
+ getBiconnectedComponents() {
6884
+ const dfn = /* @__PURE__ */ new Map();
6885
+ const low = /* @__PURE__ */ new Map();
6886
+ const edgeStack = [];
6887
+ const components = [];
6888
+ let time = 0;
6889
+ const dfs = /* @__PURE__ */ __name((vertex, parent) => {
6890
+ dfn.set(vertex, time);
6891
+ low.set(vertex, time);
6892
+ time++;
6893
+ const neighbors = this.getNeighbors(vertex);
6894
+ let childCount = 0;
6895
+ for (const neighbor of neighbors) {
6896
+ const edge = this.getEdge(vertex, neighbor);
6897
+ if (!edge) continue;
6898
+ if (!dfn.has(neighbor)) {
6899
+ childCount++;
6900
+ edgeStack.push(edge);
6901
+ dfs(neighbor, vertex);
6902
+ low.set(vertex, Math.min(low.get(vertex), low.get(neighbor)));
6903
+ if (parent === void 0 && childCount > 1 || parent !== void 0 && low.get(neighbor) >= dfn.get(vertex)) {
6904
+ const component = [];
6905
+ let e;
6906
+ do {
6907
+ e = edgeStack.pop();
6908
+ if (e) component.push(e);
6909
+ } while (e && e !== edge);
6910
+ if (component.length > 0) components.push(component);
6911
+ }
6912
+ } else if (neighbor !== parent && dfn.get(neighbor) < dfn.get(vertex)) {
6913
+ edgeStack.push(edge);
6914
+ low.set(vertex, Math.min(low.get(vertex), dfn.get(neighbor)));
6915
+ }
6916
+ }
6917
+ }, "dfs");
6918
+ for (const vertex of this.vertexMap.values()) {
6919
+ if (!dfn.has(vertex)) {
6920
+ dfs(vertex, void 0);
6921
+ if (edgeStack.length > 0) {
6922
+ components.push([...edgeStack]);
6923
+ edgeStack.length = 0;
6924
+ }
6925
+ }
6926
+ }
6927
+ return components;
6928
+ }
6929
+ /**
6930
+ * Detect whether the graph contains a cycle.
6931
+ * Uses DFS with parent tracking.
6932
+ * @returns `true` if a cycle exists, `false` otherwise.
6933
+ * @remarks Time O(V + E), Space O(V)
6934
+ */
6935
+ hasCycle() {
6936
+ const visited = /* @__PURE__ */ new Set();
6937
+ const dfs = /* @__PURE__ */ __name((vertex, parent) => {
6938
+ visited.add(vertex);
6939
+ for (const neighbor of this.getNeighbors(vertex)) {
6940
+ if (!visited.has(neighbor)) {
6941
+ if (dfs(neighbor, vertex)) return true;
6942
+ } else if (neighbor !== parent) {
6943
+ return true;
6944
+ }
6945
+ }
6946
+ return false;
6947
+ }, "dfs");
6948
+ for (const vertex of this.vertexMap.values()) {
6949
+ if (!visited.has(vertex)) {
6950
+ if (dfs(vertex, void 0)) return true;
6951
+ }
6952
+ }
6953
+ return false;
6954
+ }
6681
6955
  /**
6682
6956
  * Get bridges discovered by `tarjan()`.
6683
6957
  * @returns Array of edges that are bridges.
@@ -6831,30 +7105,6 @@ var MapGraph = class _MapGraph extends DirectedGraph {
6831
7105
  }
6832
7106
  };
6833
7107
 
6834
- // src/common/index.ts
6835
- var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
6836
- DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
6837
- DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
6838
- return DFSOperation2;
6839
- })(DFSOperation || {});
6840
- var Range = class {
6841
- constructor(low, high, includeLow = true, includeHigh = true) {
6842
- this.low = low;
6843
- this.high = high;
6844
- this.includeLow = includeLow;
6845
- this.includeHigh = includeHigh;
6846
- }
6847
- static {
6848
- __name(this, "Range");
6849
- }
6850
- // Determine whether a key is within the range
6851
- isInRange(key, comparator) {
6852
- const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
6853
- const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
6854
- return lowCheck && highCheck;
6855
- }
6856
- };
6857
-
6858
7108
  // src/data-structures/binary-tree/binary-tree.ts
6859
7109
  var BinaryTreeNode = class {
6860
7110
  static {
@@ -6993,7 +7243,7 @@ var BinaryTreeNode = class {
6993
7243
  return "MAL_NODE";
6994
7244
  }
6995
7245
  };
6996
- var BinaryTree = class extends IterableEntryBase {
7246
+ var BinaryTree = class _BinaryTree extends IterableEntryBase {
6997
7247
  static {
6998
7248
  __name(this, "BinaryTree");
6999
7249
  }
@@ -7013,7 +7263,7 @@ var BinaryTree = class extends IterableEntryBase {
7013
7263
  if (isMapMode !== void 0) this._isMapMode = isMapMode;
7014
7264
  if (isDuplicate !== void 0) this._isDuplicate = isDuplicate;
7015
7265
  if (typeof toEntryFn === "function") this._toEntryFn = toEntryFn;
7016
- else if (toEntryFn) throw TypeError("toEntryFn must be a function type");
7266
+ else if (toEntryFn) throw new TypeError(ERR.notAFunction("toEntryFn", "BinaryTree"));
7017
7267
  }
7018
7268
  if (keysNodesEntriesOrRaws) this.setMany(keysNodesEntriesOrRaws);
7019
7269
  }
@@ -7251,7 +7501,7 @@ var BinaryTree = class extends IterableEntryBase {
7251
7501
  if (!this._root) {
7252
7502
  this._setRoot(newNode);
7253
7503
  if (this._isMapMode && newNode !== null && newNode !== void 0) this._store.set(newNode.key, newNode);
7254
- this._size = 1;
7504
+ if (newNode !== null) this._size = 1;
7255
7505
  return true;
7256
7506
  }
7257
7507
  const queue = new Queue([this._root]);
@@ -7283,7 +7533,7 @@ var BinaryTree = class extends IterableEntryBase {
7283
7533
  potentialParent.right = newNode;
7284
7534
  }
7285
7535
  if (this._isMapMode && newNode !== null && newNode !== void 0) this._store.set(newNode.key, newNode);
7286
- this._size++;
7536
+ if (newNode !== null) this._size++;
7287
7537
  return true;
7288
7538
  }
7289
7539
  return false;
@@ -7851,7 +8101,7 @@ var BinaryTree = class extends IterableEntryBase {
7851
8101
  }
7852
8102
  /**
7853
8103
  * Finds all leaf nodes in the tree.
7854
- * @remarks Time O(N), visits every node. Space O(H) for recursive stack or O(N) for iterative queue.
8104
+ * @remarks Time O(N), visits every node. Space O(H) for recursive or iterative stack.
7855
8105
  *
7856
8106
  * @template C - The type of the callback function.
7857
8107
  * @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each leaf node.
@@ -7874,15 +8124,15 @@ var BinaryTree = class extends IterableEntryBase {
7874
8124
  }, "dfs");
7875
8125
  dfs(startNode);
7876
8126
  } else {
7877
- const queue = new Queue([startNode]);
7878
- while (queue.length > 0) {
7879
- const cur = queue.shift();
8127
+ const stack = [startNode];
8128
+ while (stack.length > 0) {
8129
+ const cur = stack.pop();
7880
8130
  if (this.isRealNode(cur)) {
7881
8131
  if (this.isLeaf(cur)) {
7882
8132
  leaves.push(callback(cur));
7883
8133
  }
7884
- if (this.isRealNode(cur.left)) queue.push(cur.left);
7885
- if (this.isRealNode(cur.right)) queue.push(cur.right);
8134
+ if (this.isRealNode(cur.right)) stack.push(cur.right);
8135
+ if (this.isRealNode(cur.left)) stack.push(cur.left);
7886
8136
  }
7887
8137
  }
7888
8138
  }
@@ -8344,42 +8594,98 @@ var BinaryTree = class extends IterableEntryBase {
8344
8594
  _displayAux(node, options) {
8345
8595
  const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8346
8596
  const emptyDisplayLayout = [["\u2500"], 1, 0, 0];
8347
- if (node === null && !isShowNull) {
8348
- return emptyDisplayLayout;
8349
- } else if (node === void 0 && !isShowUndefined) {
8350
- return emptyDisplayLayout;
8351
- } else if (this.isNIL(node) && !isShowRedBlackNIL) {
8352
- return emptyDisplayLayout;
8353
- } else if (node !== null && node !== void 0) {
8354
- const key = node.key, line = this.isNIL(node) ? "S" : String(key), width = line.length;
8355
- return _buildNodeDisplay(
8356
- line,
8357
- width,
8358
- this._displayAux(node.left, options),
8359
- this._displayAux(node.right, options)
8360
- );
8361
- } else {
8362
- const line = node === void 0 ? "U" : "N", width = line.length;
8363
- return _buildNodeDisplay(line, width, [[""], 1, 0, 0], [[""], 1, 0, 0]);
8364
- }
8365
- function _buildNodeDisplay(line, width, left, right) {
8366
- const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
8367
- const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
8368
- const firstLine = " ".repeat(Math.max(0, leftMiddle + 1)) + "_".repeat(Math.max(0, leftWidth - leftMiddle - 1)) + line + "_".repeat(Math.max(0, rightMiddle)) + " ".repeat(Math.max(0, rightWidth - rightMiddle));
8369
- const secondLine = (leftHeight > 0 ? " ".repeat(leftMiddle) + "/" + " ".repeat(leftWidth - leftMiddle - 1) : " ".repeat(leftWidth)) + " ".repeat(width) + (rightHeight > 0 ? " ".repeat(rightMiddle) + "\\" + " ".repeat(rightWidth - rightMiddle - 1) : " ".repeat(rightWidth));
8370
- const mergedLines = [firstLine, secondLine];
8371
- for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
8372
- const leftLine = i < leftHeight ? leftLines[i] : " ".repeat(leftWidth);
8373
- const rightLine = i < rightHeight ? rightLines[i] : " ".repeat(rightWidth);
8374
- mergedLines.push(leftLine + " ".repeat(width) + rightLine);
8597
+ const newFrame = /* @__PURE__ */ __name((n) => ({
8598
+ node: n,
8599
+ stage: 0,
8600
+ leftLayout: emptyDisplayLayout,
8601
+ rightLayout: emptyDisplayLayout
8602
+ }), "newFrame");
8603
+ const stack = [newFrame(node)];
8604
+ let result = emptyDisplayLayout;
8605
+ const setChildResult = /* @__PURE__ */ __name((layout) => {
8606
+ if (stack.length === 0) {
8607
+ result = layout;
8608
+ return;
8609
+ }
8610
+ const parent = stack[stack.length - 1];
8611
+ if (parent.stage === 1) parent.leftLayout = layout;
8612
+ else parent.rightLayout = layout;
8613
+ }, "setChildResult");
8614
+ while (stack.length > 0) {
8615
+ const frame = stack[stack.length - 1];
8616
+ const cur = frame.node;
8617
+ if (frame.stage === 0) {
8618
+ if (this._isDisplayLeaf(cur, options)) {
8619
+ stack.pop();
8620
+ const layout = this._resolveDisplayLeaf(cur, options, emptyDisplayLayout);
8621
+ setChildResult(layout);
8622
+ continue;
8623
+ }
8624
+ frame.stage = 1;
8625
+ stack.push(newFrame(cur.left));
8626
+ } else if (frame.stage === 1) {
8627
+ frame.stage = 2;
8628
+ stack.push(newFrame(cur.right));
8629
+ } else {
8630
+ stack.pop();
8631
+ const line = this.isNIL(cur) ? "S" : String(cur.key);
8632
+ const layout = _BinaryTree._buildNodeDisplay(line, line.length, frame.leftLayout, frame.rightLayout);
8633
+ setChildResult(layout);
8375
8634
  }
8376
- return [
8377
- mergedLines,
8378
- leftWidth + width + rightWidth,
8379
- Math.max(leftHeight, rightHeight) + 2,
8380
- leftWidth + Math.floor(width / 2)
8381
- ];
8382
8635
  }
8636
+ return result;
8637
+ }
8638
+ static _buildNodeDisplay(line, width, left, right) {
8639
+ const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
8640
+ const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
8641
+ const firstLine = " ".repeat(Math.max(0, leftMiddle + 1)) + "_".repeat(Math.max(0, leftWidth - leftMiddle - 1)) + line + "_".repeat(Math.max(0, rightMiddle)) + " ".repeat(Math.max(0, rightWidth - rightMiddle));
8642
+ const secondLine = (leftHeight > 0 ? " ".repeat(leftMiddle) + "/" + " ".repeat(leftWidth - leftMiddle - 1) : " ".repeat(leftWidth)) + " ".repeat(width) + (rightHeight > 0 ? " ".repeat(rightMiddle) + "\\" + " ".repeat(rightWidth - rightMiddle - 1) : " ".repeat(rightWidth));
8643
+ const mergedLines = [firstLine, secondLine];
8644
+ for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
8645
+ const leftLine = i < leftHeight ? leftLines[i] : " ".repeat(leftWidth);
8646
+ const rightLine = i < rightHeight ? rightLines[i] : " ".repeat(rightWidth);
8647
+ mergedLines.push(leftLine + " ".repeat(width) + rightLine);
8648
+ }
8649
+ return [
8650
+ mergedLines,
8651
+ leftWidth + width + rightWidth,
8652
+ Math.max(leftHeight, rightHeight) + 2,
8653
+ leftWidth + Math.floor(width / 2)
8654
+ ];
8655
+ }
8656
+ /**
8657
+ * Check if a node is a display leaf (empty, null, undefined, NIL, or real leaf).
8658
+ */
8659
+ _isDisplayLeaf(node, options) {
8660
+ const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8661
+ if (node === null && !isShowNull) return true;
8662
+ if (node === void 0 && !isShowUndefined) return true;
8663
+ if (this.isNIL(node) && !isShowRedBlackNIL) return true;
8664
+ if (node === null || node === void 0) return true;
8665
+ const hasDisplayableLeft = this._hasDisplayableChild(node.left, options);
8666
+ const hasDisplayableRight = this._hasDisplayableChild(node.right, options);
8667
+ return !hasDisplayableLeft && !hasDisplayableRight;
8668
+ }
8669
+ _hasDisplayableChild(child, options) {
8670
+ if (child === null) return !!options.isShowNull;
8671
+ if (child === void 0) return !!options.isShowUndefined;
8672
+ if (this.isNIL(child)) return !!options.isShowRedBlackNIL;
8673
+ return true;
8674
+ }
8675
+ /**
8676
+ * Resolve a display leaf node to its layout.
8677
+ */
8678
+ _resolveDisplayLeaf(node, options, emptyDisplayLayout) {
8679
+ const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
8680
+ if (node === null && !isShowNull) return emptyDisplayLayout;
8681
+ if (node === void 0 && !isShowUndefined) return emptyDisplayLayout;
8682
+ if (this.isNIL(node) && !isShowRedBlackNIL) return emptyDisplayLayout;
8683
+ if (node !== null && node !== void 0) {
8684
+ const line2 = this.isNIL(node) ? "S" : String(node.key);
8685
+ return _BinaryTree._buildNodeDisplay(line2, line2.length, emptyDisplayLayout, emptyDisplayLayout);
8686
+ }
8687
+ const line = node === void 0 ? "U" : "N";
8688
+ return _BinaryTree._buildNodeDisplay(line, line.length, [[""], 1, 0, 0], [[""], 1, 0, 0]);
8383
8689
  }
8384
8690
  /**
8385
8691
  * (Protected) Swaps the key/value properties of two nodes.
@@ -9385,9 +9691,15 @@ var BST = class extends BinaryTree {
9385
9691
  if (a < b) return -1;
9386
9692
  return 0;
9387
9693
  }
9694
+ if (a instanceof Date && b instanceof Date) {
9695
+ const ta = a.getTime();
9696
+ const tb = b.getTime();
9697
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("BST"));
9698
+ return ta > tb ? 1 : ta < tb ? -1 : 0;
9699
+ }
9388
9700
  if (typeof a === "object" || typeof b === "object") {
9389
- throw TypeError(
9390
- `When comparing object type keys, a custom comparator must be provided in the constructor's options!`
9701
+ throw new TypeError(
9702
+ ERR.comparatorRequired("BST")
9391
9703
  );
9392
9704
  }
9393
9705
  return 0;
@@ -9899,7 +10211,7 @@ var BinaryIndexedTree = class {
9899
10211
  */
9900
10212
  read(count) {
9901
10213
  if (!Number.isInteger(count)) {
9902
- throw new Error("Invalid count");
10214
+ throw new Error(ERR.invalidArgument("count must be an integer", "BinaryIndexedTree"));
9903
10215
  }
9904
10216
  return this._read(Math.max(Math.min(count, this.max), 0));
9905
10217
  }
@@ -9911,7 +10223,7 @@ var BinaryIndexedTree = class {
9911
10223
  */
9912
10224
  lowerBound(sum) {
9913
10225
  if (this.negativeCount > 0) {
9914
- throw new Error("Sequence is not non-descending");
10226
+ throw new Error(ERR.invalidOperation("Sequence is not non-descending.", "BinaryIndexedTree"));
9915
10227
  }
9916
10228
  return this._binarySearch(sum, (x, y) => x < y);
9917
10229
  }
@@ -9924,7 +10236,7 @@ var BinaryIndexedTree = class {
9924
10236
  */
9925
10237
  upperBound(sum) {
9926
10238
  if (this.negativeCount > 0) {
9927
- throw new Error("Must not be descending");
10239
+ throw new Error(ERR.invalidOperation("Sequence must not be descending.", "BinaryIndexedTree"));
9928
10240
  }
9929
10241
  return this._binarySearch(sum, (x, y) => x <= y);
9930
10242
  }
@@ -9975,10 +10287,10 @@ var BinaryIndexedTree = class {
9975
10287
  */
9976
10288
  _checkIndex(index) {
9977
10289
  if (!Number.isInteger(index)) {
9978
- throw new Error("Invalid index: Index must be an integer.");
10290
+ throw new TypeError(ERR.invalidIndex("BinaryIndexedTree"));
9979
10291
  }
9980
10292
  if (index < 0 || index >= this.max) {
9981
- throw new Error("Index out of range: Index must be within the range [0, this.max).");
10293
+ throw new RangeError(ERR.indexOutOfRange(index, 0, this.max - 1, "BinaryIndexedTree"));
9982
10294
  }
9983
10295
  }
9984
10296
  /**
@@ -11570,6 +11882,24 @@ var RedBlackTree = class extends BST {
11570
11882
  * @param [thisArg] - See parameter type for details.
11571
11883
  * @returns A new RedBlackTree with mapped entries.
11572
11884
  */
11885
+ /**
11886
+ * Red-Black trees are self-balancing — `perfectlyBalance` rebuilds via
11887
+ * sorted bulk insert, which naturally produces a balanced RBT.
11888
+ * @remarks Time O(N), Space O(N)
11889
+ */
11890
+ perfectlyBalance(iterationType) {
11891
+ const entries = [];
11892
+ for (const [key, value] of this) entries.push([key, value]);
11893
+ if (entries.length <= 1) return true;
11894
+ this.clear();
11895
+ this.setMany(
11896
+ entries.map(([k]) => k),
11897
+ entries.map(([, v]) => v),
11898
+ true
11899
+ // isBalanceAdd
11900
+ );
11901
+ return true;
11902
+ }
11573
11903
  map(callback, options, thisArg) {
11574
11904
  const out = this._createLike([], options);
11575
11905
  let index = 0;
@@ -11891,7 +12221,7 @@ var TreeSet = class _TreeSet {
11891
12221
  static createDefaultComparator() {
11892
12222
  return (a, b) => {
11893
12223
  if (typeof a === "number" && typeof b === "number") {
11894
- if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError("TreeSet: NaN is not a valid key");
12224
+ if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("TreeSet"));
11895
12225
  const aa = Object.is(a, -0) ? 0 : a;
11896
12226
  const bb = Object.is(b, -0) ? 0 : b;
11897
12227
  return aa > bb ? 1 : aa < bb ? -1 : 0;
@@ -11902,10 +12232,10 @@ var TreeSet = class _TreeSet {
11902
12232
  if (a instanceof Date && b instanceof Date) {
11903
12233
  const ta = a.getTime();
11904
12234
  const tb = b.getTime();
11905
- if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError("TreeSet: invalid Date key");
12235
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("TreeSet"));
11906
12236
  return ta > tb ? 1 : ta < tb ? -1 : 0;
11907
12237
  }
11908
- throw new TypeError("TreeSet: comparator is required for non-number/non-string/non-Date keys");
12238
+ throw new TypeError(ERR.comparatorRequired("TreeSet"));
11909
12239
  };
11910
12240
  }
11911
12241
  /**
@@ -11923,15 +12253,15 @@ var TreeSet = class _TreeSet {
11923
12253
  _validateKey(key) {
11924
12254
  if (!this.#isDefaultComparator) return;
11925
12255
  if (typeof key === "number") {
11926
- if (Number.isNaN(key)) throw new TypeError("TreeSet: NaN is not a valid key");
12256
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeSet"));
11927
12257
  return;
11928
12258
  }
11929
12259
  if (typeof key === "string") return;
11930
12260
  if (key instanceof Date) {
11931
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeSet: invalid Date key");
12261
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeSet"));
11932
12262
  return;
11933
12263
  }
11934
- throw new TypeError("TreeSet: comparator is required for non-number/non-string/non-Date keys");
12264
+ throw new TypeError(ERR.comparatorRequired("TreeSet"));
11935
12265
  }
11936
12266
  /**
11937
12267
  * Add a key to the set (no-op if already present).
@@ -12250,15 +12580,15 @@ var TreeMultiMap = class _TreeMultiMap {
12250
12580
  _validateKey(key) {
12251
12581
  if (!this.#isDefaultComparator) return;
12252
12582
  if (typeof key === "number") {
12253
- if (Number.isNaN(key)) throw new TypeError("TreeMultiMap: NaN is not a valid key");
12583
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMultiMap"));
12254
12584
  return;
12255
12585
  }
12256
12586
  if (typeof key === "string") return;
12257
12587
  if (key instanceof Date) {
12258
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMultiMap: invalid Date key");
12588
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMultiMap"));
12259
12589
  return;
12260
12590
  }
12261
- throw new TypeError("TreeMultiMap: comparator is required for non-number/non-string/non-Date keys");
12591
+ throw new TypeError(ERR.comparatorRequired("TreeMultiMap"));
12262
12592
  }
12263
12593
  /**
12264
12594
  * Number of distinct keys.
@@ -12680,7 +13010,7 @@ var TreeMap = class _TreeMap {
12680
13010
  [k, v] = toEntryFn(item);
12681
13011
  } else {
12682
13012
  if (!Array.isArray(item) || item.length < 2) {
12683
- throw new TypeError("TreeMap: each entry must be a [key, value] tuple");
13013
+ throw new TypeError(ERR.invalidEntry("TreeMap"));
12684
13014
  }
12685
13015
  k = item[0];
12686
13016
  v = item[1];
@@ -12701,7 +13031,7 @@ var TreeMap = class _TreeMap {
12701
13031
  static createDefaultComparator() {
12702
13032
  return (a, b) => {
12703
13033
  if (typeof a === "number" && typeof b === "number") {
12704
- if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError("TreeMap: NaN is not a valid key");
13034
+ if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("TreeMap"));
12705
13035
  const aa = Object.is(a, -0) ? 0 : a;
12706
13036
  const bb = Object.is(b, -0) ? 0 : b;
12707
13037
  return aa > bb ? 1 : aa < bb ? -1 : 0;
@@ -12712,24 +13042,24 @@ var TreeMap = class _TreeMap {
12712
13042
  if (a instanceof Date && b instanceof Date) {
12713
13043
  const ta = a.getTime();
12714
13044
  const tb = b.getTime();
12715
- if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError("TreeMap: invalid Date key");
13045
+ if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("TreeMap"));
12716
13046
  return ta > tb ? 1 : ta < tb ? -1 : 0;
12717
13047
  }
12718
- throw new TypeError("TreeMap: comparator is required for non-number/non-string/non-Date keys");
13048
+ throw new TypeError(ERR.comparatorRequired("TreeMap"));
12719
13049
  };
12720
13050
  }
12721
13051
  _validateKey(key) {
12722
13052
  if (!this.#isDefaultComparator) return;
12723
13053
  if (typeof key === "number") {
12724
- if (Number.isNaN(key)) throw new TypeError("TreeMap: NaN is not a valid key");
13054
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMap"));
12725
13055
  return;
12726
13056
  }
12727
13057
  if (typeof key === "string") return;
12728
13058
  if (key instanceof Date) {
12729
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMap: invalid Date key");
13059
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMap"));
12730
13060
  return;
12731
13061
  }
12732
- throw new TypeError("TreeMap: comparator is required for non-number/non-string/non-Date keys");
13062
+ throw new TypeError(ERR.comparatorRequired("TreeMap"));
12733
13063
  }
12734
13064
  /**
12735
13065
  * Number of entries in the map.
@@ -13053,22 +13383,22 @@ var TreeMultiSet = class _TreeMultiSet {
13053
13383
  _validateKey(key) {
13054
13384
  if (!this.#isDefaultComparator) return;
13055
13385
  if (typeof key === "number") {
13056
- if (Number.isNaN(key)) throw new TypeError("TreeMultiSet: NaN is not a valid key");
13386
+ if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN("TreeMultiSet"));
13057
13387
  return;
13058
13388
  }
13059
13389
  if (typeof key === "string") return;
13060
13390
  if (key instanceof Date) {
13061
- if (Number.isNaN(key.getTime())) throw new TypeError("TreeMultiSet: invalid Date key");
13391
+ if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate("TreeMultiSet"));
13062
13392
  return;
13063
13393
  }
13064
- throw new TypeError("TreeMultiSet: comparator is required for non-number/non-string/non-Date keys");
13394
+ throw new TypeError(ERR.comparatorRequired("TreeMultiSet"));
13065
13395
  }
13066
13396
  /**
13067
13397
  * Validates that count is a non-negative safe integer.
13068
13398
  * @remarks Time O(1), Space O(1)
13069
13399
  */
13070
13400
  _validateCount(n) {
13071
- if (!Number.isSafeInteger(n) || n < 0) throw new RangeError("TreeMultiSet: count must be a safe integer >= 0");
13401
+ if (!Number.isSafeInteger(n) || n < 0) throw new RangeError(ERR.invalidArgument("count must be a safe integer >= 0.", "TreeMultiSet"));
13072
13402
  }
13073
13403
  /**
13074
13404
  * Total occurrences (sumCounts).
@@ -13492,9 +13822,7 @@ var MaxPriorityQueue = class extends PriorityQueue {
13492
13822
  super(elements, {
13493
13823
  comparator: /* @__PURE__ */ __name((a, b) => {
13494
13824
  if (typeof a === "object" || typeof b === "object") {
13495
- throw TypeError(
13496
- `When comparing object types, a custom comparator must be defined in the constructor's options parameter.`
13497
- );
13825
+ throw new TypeError(ERR.comparatorRequired("MaxPriorityQueue"));
13498
13826
  }
13499
13827
  if (a < b) return 1;
13500
13828
  if (a > b) return -1;
@@ -13635,7 +13963,7 @@ var Matrix = class _Matrix {
13635
13963
  */
13636
13964
  add(matrix) {
13637
13965
  if (!this.isMatchForCalculate(matrix)) {
13638
- throw new Error("Matrix dimensions must match for addition.");
13966
+ throw new Error(ERR.matrixDimensionMismatch("addition"));
13639
13967
  }
13640
13968
  const resultData = [];
13641
13969
  for (let i = 0; i < this.rows; i++) {
@@ -13667,7 +13995,7 @@ var Matrix = class _Matrix {
13667
13995
  */
13668
13996
  subtract(matrix) {
13669
13997
  if (!this.isMatchForCalculate(matrix)) {
13670
- throw new Error("Matrix dimensions must match for subtraction.");
13998
+ throw new Error(ERR.matrixDimensionMismatch("subtraction"));
13671
13999
  }
13672
14000
  const resultData = [];
13673
14001
  for (let i = 0; i < this.rows; i++) {
@@ -13698,7 +14026,7 @@ var Matrix = class _Matrix {
13698
14026
  */
13699
14027
  multiply(matrix) {
13700
14028
  if (this.cols !== matrix.rows) {
13701
- throw new Error("Matrix dimensions must be compatible for multiplication (A.cols = B.rows).");
14029
+ throw new Error(ERR.matrixDimensionMismatch("multiplication (A.cols must equal B.rows)"));
13702
14030
  }
13703
14031
  const resultData = [];
13704
14032
  for (let i = 0; i < this.rows; i++) {
@@ -13732,7 +14060,7 @@ var Matrix = class _Matrix {
13732
14060
  */
13733
14061
  transpose() {
13734
14062
  if (this.data.some((row) => row.length !== this.rows)) {
13735
- throw new Error("Matrix must be rectangular for transposition.");
14063
+ throw new Error(ERR.matrixNotRectangular());
13736
14064
  }
13737
14065
  const resultData = [];
13738
14066
  for (let j = 0; j < this.cols; j++) {
@@ -13756,7 +14084,7 @@ var Matrix = class _Matrix {
13756
14084
  */
13757
14085
  inverse() {
13758
14086
  if (this.rows !== this.cols) {
13759
- throw new Error("Matrix must be square for inversion.");
14087
+ throw new Error(ERR.matrixNotSquare());
13760
14088
  }
13761
14089
  const augmentedMatrixData = [];
13762
14090
  for (let i = 0; i < this.rows; i++) {
@@ -13778,12 +14106,12 @@ var Matrix = class _Matrix {
13778
14106
  pivotRow++;
13779
14107
  }
13780
14108
  if (pivotRow === this.rows) {
13781
- throw new Error("Matrix is singular, and its inverse does not exist.");
14109
+ throw new Error(ERR.matrixSingular());
13782
14110
  }
13783
14111
  augmentedMatrix._swapRows(i, pivotRow);
13784
14112
  const pivotElement = augmentedMatrix.get(i, i) ?? 1;
13785
14113
  if (pivotElement === 0) {
13786
- throw new Error("Matrix is singular, and its inverse does not exist (division by zero).");
14114
+ throw new Error(ERR.matrixSingular());
13787
14115
  }
13788
14116
  augmentedMatrix._scaleRow(i, 1 / pivotElement);
13789
14117
  for (let j = 0; j < this.rows; j++) {
@@ -13813,9 +14141,7 @@ var Matrix = class _Matrix {
13813
14141
  */
13814
14142
  dot(matrix) {
13815
14143
  if (this.cols !== matrix.rows) {
13816
- throw new Error(
13817
- "Number of columns in the first matrix must be equal to the number of rows in the second matrix for dot product."
13818
- );
14144
+ throw new Error(ERR.matrixDimensionMismatch("dot product (A.cols must equal B.rows)"));
13819
14145
  }
13820
14146
  const resultData = [];
13821
14147
  for (let i = 0; i < this.rows; i++) {
@@ -14441,7 +14767,7 @@ var Trie = class extends IterableElementBase {
14441
14767
  for (const x of this) {
14442
14768
  const v = thisArg === void 0 ? callback(x, i++, this) : callback.call(thisArg, x, i++, this);
14443
14769
  if (typeof v !== "string") {
14444
- throw new TypeError(`Trie.map callback must return string; got ${typeof v}`);
14770
+ throw new TypeError(ERR.callbackReturnType("string", typeof v, "Trie.map"));
14445
14771
  }
14446
14772
  newTrie.add(v);
14447
14773
  }
@@ -14691,6 +15017,7 @@ exports.DirectedGraph = DirectedGraph;
14691
15017
  exports.DirectedVertex = DirectedVertex;
14692
15018
  exports.DoublyLinkedList = DoublyLinkedList;
14693
15019
  exports.DoublyLinkedListNode = DoublyLinkedListNode;
15020
+ exports.ERR = ERR;
14694
15021
  exports.FibonacciHeap = FibonacciHeap;
14695
15022
  exports.FibonacciHeapNode = FibonacciHeapNode;
14696
15023
  exports.HashMap = HashMap;