data-structure-typed 2.2.7 → 2.3.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 (181) hide show
  1. package/.github/workflows/ci.yml +9 -0
  2. package/CHANGELOG.md +1 -1
  3. package/README.md +14 -3
  4. package/README_CN.md +119 -275
  5. package/benchmark/report.html +1 -1
  6. package/benchmark/report.json +20 -324
  7. package/dist/cjs/index.cjs +689 -182
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs-legacy/index.cjs +693 -185
  10. package/dist/cjs-legacy/index.cjs.map +1 -1
  11. package/dist/esm/index.mjs +689 -182
  12. package/dist/esm/index.mjs.map +1 -1
  13. package/dist/esm-legacy/index.mjs +693 -185
  14. package/dist/esm-legacy/index.mjs.map +1 -1
  15. package/dist/leetcode/avl-tree-counter.mjs +2957 -0
  16. package/dist/leetcode/avl-tree-multi-map.mjs +2889 -0
  17. package/dist/leetcode/avl-tree.mjs +2720 -0
  18. package/dist/leetcode/binary-tree.mjs +1594 -0
  19. package/dist/leetcode/bst.mjs +2398 -0
  20. package/dist/leetcode/deque.mjs +683 -0
  21. package/dist/leetcode/directed-graph.mjs +1733 -0
  22. package/dist/leetcode/doubly-linked-list.mjs +709 -0
  23. package/dist/leetcode/hash-map.mjs +493 -0
  24. package/dist/leetcode/heap.mjs +542 -0
  25. package/dist/leetcode/max-heap.mjs +375 -0
  26. package/dist/leetcode/max-priority-queue.mjs +383 -0
  27. package/dist/leetcode/min-heap.mjs +363 -0
  28. package/dist/leetcode/min-priority-queue.mjs +371 -0
  29. package/dist/leetcode/priority-queue.mjs +363 -0
  30. package/dist/leetcode/queue.mjs +943 -0
  31. package/dist/leetcode/red-black-tree.mjs +2765 -0
  32. package/dist/leetcode/singly-linked-list.mjs +754 -0
  33. package/dist/leetcode/stack.mjs +217 -0
  34. package/dist/leetcode/tree-counter.mjs +3039 -0
  35. package/dist/leetcode/tree-multi-map.mjs +2913 -0
  36. package/dist/leetcode/trie.mjs +413 -0
  37. package/dist/leetcode/undirected-graph.mjs +1650 -0
  38. package/dist/types/data-structures/base/linear-base.d.ts +6 -6
  39. package/dist/types/data-structures/binary-tree/avl-tree-counter.d.ts +1 -1
  40. package/dist/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +2 -2
  41. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +10 -10
  42. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +25 -27
  43. package/dist/types/data-structures/binary-tree/bst.d.ts +13 -12
  44. package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +151 -21
  45. package/dist/types/data-structures/binary-tree/tree-counter.d.ts +4 -4
  46. package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +2 -2
  47. package/dist/types/interfaces/binary-tree.d.ts +1 -1
  48. package/dist/umd/data-structure-typed.js +689 -181
  49. package/dist/umd/data-structure-typed.js.map +1 -1
  50. package/dist/umd/data-structure-typed.min.js +3 -3
  51. package/dist/umd/data-structure-typed.min.js.map +1 -1
  52. package/package.json +50 -172
  53. package/src/data-structures/base/linear-base.ts +2 -12
  54. package/src/data-structures/binary-tree/avl-tree-counter.ts +6 -6
  55. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +13 -13
  56. package/src/data-structures/binary-tree/avl-tree.ts +15 -15
  57. package/src/data-structures/binary-tree/binary-tree.ts +57 -60
  58. package/src/data-structures/binary-tree/bst.ts +100 -26
  59. package/src/data-structures/binary-tree/red-black-tree.ts +586 -76
  60. package/src/data-structures/binary-tree/tree-counter.ts +25 -13
  61. package/src/data-structures/binary-tree/tree-multi-map.ts +13 -13
  62. package/src/data-structures/queue/deque.ts +10 -0
  63. package/src/interfaces/binary-tree.ts +1 -1
  64. package/test/performance/data-structures/binary-tree/red-black-tree.test.ts +1 -2
  65. package/test/unit/data-structures/base/iterable-element-base.coverage.test.ts +106 -0
  66. package/test/unit/data-structures/base/iterable-element-base.more-branches.coverage.test.ts +61 -0
  67. package/test/unit/data-structures/base/linear-base.array.coverage.test.ts +168 -0
  68. package/test/unit/data-structures/base/linear-base.concat-else.coverage.test.ts +82 -0
  69. package/test/unit/data-structures/base/linear-base.coverage.test.ts +72 -0
  70. package/test/unit/data-structures/base/linear-base.more-branches.coverage.test.ts +417 -0
  71. package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches-3.coverage.test.ts +146 -0
  72. package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches.coverage.test.ts +93 -0
  73. package/test/unit/data-structures/binary-tree/avl-tree-counter.test.ts +30 -30
  74. package/test/unit/data-structures/binary-tree/avl-tree-multi-map.coverage.test.ts +108 -0
  75. package/test/unit/data-structures/binary-tree/avl-tree-multi-map.more-branches-2.coverage.test.ts +85 -0
  76. package/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts +46 -46
  77. package/test/unit/data-structures/binary-tree/avl-tree-node.familyPosition-root-left.coverage.test.ts +17 -0
  78. package/test/unit/data-structures/binary-tree/avl-tree.more-branches-2.coverage.test.ts +99 -0
  79. package/test/unit/data-structures/binary-tree/avl-tree.test.ts +43 -43
  80. package/test/unit/data-structures/binary-tree/binary-indexed-tree.more-branches.coverage.test.ts +18 -0
  81. package/test/unit/data-structures/binary-tree/binary-tree.more-branches.coverage.test.ts +56 -0
  82. package/test/unit/data-structures/binary-tree/binary-tree.remaining-branches.coverage.test.ts +229 -0
  83. package/test/unit/data-structures/binary-tree/binary-tree.test.ts +151 -151
  84. package/test/unit/data-structures/binary-tree/bst.bound-by-predicate.coverage.test.ts +33 -0
  85. package/test/unit/data-structures/binary-tree/bst.coverage.test.ts +94 -0
  86. package/test/unit/data-structures/binary-tree/bst.deletebykey.coverage.test.ts +70 -0
  87. package/test/unit/data-structures/binary-tree/bst.deletewhere.coverage.test.ts +37 -0
  88. package/test/unit/data-structures/binary-tree/bst.floor-lower-predicate.coverage.test.ts +29 -0
  89. package/test/unit/data-structures/binary-tree/bst.floor-setmany.coverage.test.ts +72 -0
  90. package/test/unit/data-structures/binary-tree/bst.getnode.range-ensure.coverage.test.ts +22 -0
  91. package/test/unit/data-structures/binary-tree/bst.misc-branches.coverage.test.ts +100 -0
  92. package/test/unit/data-structures/binary-tree/bst.more-branches-2.coverage.test.ts +133 -0
  93. package/test/unit/data-structures/binary-tree/bst.more-branches-3.coverage.test.ts +45 -0
  94. package/test/unit/data-structures/binary-tree/bst.more-branches-4.coverage.test.ts +36 -0
  95. package/test/unit/data-structures/binary-tree/bst.more-branches-5.coverage.test.ts +40 -0
  96. package/test/unit/data-structures/binary-tree/bst.more.coverage.test.ts +39 -0
  97. package/test/unit/data-structures/binary-tree/bst.node-family.coverage.test.ts +29 -0
  98. package/test/unit/data-structures/binary-tree/bst.range-pruning.coverage.test.ts +43 -0
  99. package/test/unit/data-structures/binary-tree/bst.search-fastpath.coverage.test.ts +30 -0
  100. package/test/unit/data-structures/binary-tree/bst.test.ts +124 -154
  101. package/test/unit/data-structures/binary-tree/overall.test.ts +20 -20
  102. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-corruption-repair.coverage.test.ts +66 -0
  103. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-max-update.coverage.test.ts +18 -0
  104. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-null.coverage.test.ts +53 -0
  105. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-stale-cache.coverage.test.ts +25 -0
  106. package/test/unit/data-structures/binary-tree/red-black-tree.boundary-update.coverage.test.ts +23 -0
  107. package/test/unit/data-structures/binary-tree/red-black-tree.cache-delete.coverage.test.ts +49 -0
  108. package/test/unit/data-structures/binary-tree/red-black-tree.cache-edge.coverage.test.ts +37 -0
  109. package/test/unit/data-structures/binary-tree/red-black-tree.cache-stale-insert.coverage.test.ts +39 -0
  110. package/test/unit/data-structures/binary-tree/red-black-tree.coverage.test.ts +334 -0
  111. package/test/unit/data-structures/binary-tree/red-black-tree.delete-fixup.coverage.test.ts +68 -0
  112. package/test/unit/data-structures/binary-tree/red-black-tree.delete-successor.coverage.test.ts +75 -0
  113. package/test/unit/data-structures/binary-tree/red-black-tree.factories.coverage.test.ts +26 -0
  114. package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-compare-update.coverage.test.ts +74 -0
  115. package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-no-update.coverage.test.ts +44 -0
  116. package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-nullish.coverage.test.ts +61 -0
  117. package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-defined.coverage.test.ts +35 -0
  118. package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-undefined.coverage.test.ts +43 -0
  119. package/test/unit/data-structures/binary-tree/red-black-tree.hint-more.coverage.test.ts +99 -0
  120. package/test/unit/data-structures/binary-tree/red-black-tree.hint.coverage.test.ts +60 -0
  121. package/test/unit/data-structures/binary-tree/red-black-tree.insert-cache-nullish.coverage.test.ts +29 -0
  122. package/test/unit/data-structures/binary-tree/red-black-tree.insert-header-parent-nullish.coverage.test.ts +17 -0
  123. package/test/unit/data-structures/binary-tree/red-black-tree.internal-walk.coverage.test.ts +57 -0
  124. package/test/unit/data-structures/binary-tree/red-black-tree.minmax-cache.test.ts +65 -0
  125. package/test/unit/data-structures/binary-tree/red-black-tree.misc-inputs.coverage.test.ts +17 -0
  126. package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-2.coverage.test.ts +121 -0
  127. package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-3.coverage.test.ts +55 -0
  128. package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-4.coverage.test.ts +44 -0
  129. package/test/unit/data-structures/binary-tree/red-black-tree.predsucc.coverage.test.ts +40 -0
  130. package/test/unit/data-structures/binary-tree/red-black-tree.remaining-branches.coverage.test.ts +123 -0
  131. package/test/unit/data-structures/binary-tree/red-black-tree.set-inputs.coverage.test.ts +64 -0
  132. package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-parent-cache.coverage.test.ts +79 -0
  133. package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-remaining.coverage.test.ts +44 -0
  134. package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-uncovered.coverage.test.ts +74 -0
  135. package/test/unit/data-structures/binary-tree/red-black-tree.test.ts +141 -141
  136. package/test/unit/data-structures/binary-tree/red-black-tree.update-branches.coverage.test.ts +30 -0
  137. package/test/unit/data-structures/binary-tree/segment-tree.more-branches.coverage.test.ts +31 -0
  138. package/test/unit/data-structures/binary-tree/tree-counter.coverage.test.ts +115 -0
  139. package/test/unit/data-structures/binary-tree/tree-counter.more-branches.coverage.test.ts +244 -0
  140. package/test/unit/data-structures/binary-tree/tree-counter.test.ts +41 -39
  141. package/test/unit/data-structures/binary-tree/tree-multi-map.coverage.test.ts +104 -0
  142. package/test/unit/data-structures/binary-tree/tree-multi-map.more-branches-2.coverage.test.ts +59 -0
  143. package/test/unit/data-structures/binary-tree/tree-multi-map.test.ts +145 -145
  144. package/test/unit/data-structures/graph/abstract-graph.more-branches-2.coverage.test.ts +40 -0
  145. package/test/unit/data-structures/graph/abstract-graph.more-branches-3.coverage.test.ts +65 -0
  146. package/test/unit/data-structures/graph/abstract-graph.more-branches-4.coverage.test.ts +98 -0
  147. package/test/unit/data-structures/graph/abstract-graph.more-branches-5.coverage.test.ts +51 -0
  148. package/test/unit/data-structures/graph/abstract-graph.more-branches.coverage.test.ts +62 -0
  149. package/test/unit/data-structures/graph/directed-graph.more-branches-2.coverage.test.ts +38 -0
  150. package/test/unit/data-structures/graph/directed-graph.more-branches-3.coverage.test.ts +25 -0
  151. package/test/unit/data-structures/graph/directed-graph.more-branches.coverage.test.ts +82 -0
  152. package/test/unit/data-structures/graph/map-graph.more-branches.coverage.test.ts +22 -0
  153. package/test/unit/data-structures/graph/undirected-graph.more-branches-2.coverage.test.ts +35 -0
  154. package/test/unit/data-structures/graph/undirected-graph.more-branches.coverage.test.ts +87 -0
  155. package/test/unit/data-structures/hash/hash-map.more-branches.coverage.test.ts +64 -0
  156. package/test/unit/data-structures/hash/hash-map.toEntryFn-branch.coverage.test.ts +9 -0
  157. package/test/unit/data-structures/heap/heap.misc-branches.coverage.test.ts +110 -0
  158. package/test/unit/data-structures/heap/heap.remaining-branches.coverage.test.ts +22 -0
  159. package/test/unit/data-structures/heap/max-heap.coverage.test.ts +29 -0
  160. package/test/unit/data-structures/linked-list/doubly-linked-list.more-branches.coverage.test.ts +72 -0
  161. package/test/unit/data-structures/linked-list/linked-list.unshiftMany-else.coverage.test.ts +15 -0
  162. package/test/unit/data-structures/linked-list/singly-linked-list.coverage.test.ts +221 -0
  163. package/test/unit/data-structures/linked-list/singly-linked-list.more-branches.coverage.test.ts +86 -0
  164. package/test/unit/data-structures/linked-list/skip-linked-list.more-branches.coverage.test.ts +31 -0
  165. package/test/unit/data-structures/matrix/matrix.more-branches.coverage.test.ts +81 -0
  166. package/test/unit/data-structures/matrix/matrix.pivotElement-nullish.coverage.test.ts +28 -0
  167. package/test/unit/data-structures/priority-queue/max-priority-queue.more-branches.coverage.test.ts +10 -0
  168. package/test/unit/data-structures/priority-queue/priority-queue.coverage.test.ts +21 -0
  169. package/test/unit/data-structures/queue/deque.coverage.test.ts +173 -0
  170. package/test/unit/data-structures/queue/deque.more-branches-2.coverage.test.ts +39 -0
  171. package/test/unit/data-structures/queue/deque.more-branches-3.coverage.test.ts +9 -0
  172. package/test/unit/data-structures/queue/deque.more-branches.coverage.test.ts +95 -0
  173. package/test/unit/data-structures/queue/queue.coverage.test.ts +138 -0
  174. package/test/unit/data-structures/queue/queue.more-branches-2.coverage.test.ts +27 -0
  175. package/test/unit/data-structures/stack/stack.coverage.test.ts +112 -0
  176. package/test/unit/data-structures/tree/tree.more-branches.coverage.test.ts +9 -0
  177. package/test/unit/data-structures/trie/trie.more-branches-2.coverage.test.ts +51 -0
  178. package/test/utils/patch.ts +33 -0
  179. package/tsup.config.js +50 -21
  180. package/tsup.umd.config.js +29 -0
  181. package/tsup.node.config.js +0 -83
@@ -8,17 +8,17 @@
8
8
 
9
9
  import type {
10
10
  BinaryTreeDeleteResult,
11
- BSTNOptKeyOrNode,
11
+ BSTNOptKeyOrNode, BTNRep,
12
12
  EntryCallback,
13
13
  FamilyPosition,
14
- IterationType,
14
+ IterationType, NodePredicate,
15
15
  OptNode,
16
16
  RBTNColor,
17
17
  TreeCounterOptions
18
18
  } from '../../types';
19
19
  import { BSTNode } from './bst';
20
20
  import { IBinaryTree } from '../../interfaces';
21
- import { RedBlackTree } from './red-black-tree';
21
+ import { RedBlackTree, RedBlackTreeNode } from './red-black-tree';
22
22
 
23
23
  /**
24
24
  * RB-tree node with an extra 'count' field; keeps parent/child links.
@@ -204,7 +204,7 @@ export class TreeCounter<K = any, V = any, R = any> extends RedBlackTree<K, V, R
204
204
  options?: TreeCounterOptions<K, V, R>
205
205
  ) {
206
206
  super([], options);
207
- if (keysNodesEntriesOrRaws) this.addMany(keysNodesEntriesOrRaws);
207
+ if (keysNodesEntriesOrRaws) this.setMany(keysNodesEntriesOrRaws);
208
208
  }
209
209
 
210
210
  protected _count = 0;
@@ -255,14 +255,14 @@ export class TreeCounter<K = any, V = any, R = any> extends RedBlackTree<K, V, R
255
255
  * @param [count] - How much to increase the node's count (default 1).
256
256
  * @returns True if inserted/updated; false if ignored.
257
257
  */
258
- override add(
258
+ override set(
259
259
  keyNodeOrEntry: K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
260
260
  value?: V,
261
261
  count = 1
262
262
  ): boolean {
263
263
  const [newNode, newValue] = this._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value, count);
264
264
  const orgCount = newNode?.count || 0;
265
- const isSuccessAdded = super.add(newNode, newValue);
265
+ const isSuccessAdded = super.set(newNode, newValue);
266
266
  if (isSuccessAdded) {
267
267
  this._count += orgCount;
268
268
  return true;
@@ -274,21 +274,21 @@ export class TreeCounter<K = any, V = any, R = any> extends RedBlackTree<K, V, R
274
274
  /**
275
275
  * Delete a node (or decrement its count) and rebalance if needed.
276
276
  * @remarks Time O(log N), Space O(1)
277
- * @param keyNodeOrEntry - Key, node, or [key, value] entry identifying the node.
277
+ * @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node.
278
278
  * @param [ignoreCount] - If true, remove the node regardless of its count.
279
279
  * @returns Array of deletion results including deleted node and a rebalance hint when present.
280
280
  */
281
281
  override delete(
282
- keyNodeOrEntry: K | TreeCounterNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
282
+ keyNodeEntryRawOrPredicate: BTNRep<K, V, TreeCounterNode<K, V>> | NodePredicate<TreeCounterNode<K, V> | null>,
283
283
  ignoreCount = false
284
284
  ): BinaryTreeDeleteResult<TreeCounterNode<K, V>>[] {
285
- if (keyNodeOrEntry === null) return [];
285
+ if (keyNodeEntryRawOrPredicate === null) return [];
286
286
 
287
287
  const results: BinaryTreeDeleteResult<TreeCounterNode<K, V>>[] = [];
288
288
 
289
289
  let nodeToDelete: OptNode<TreeCounterNode<K, V>>;
290
- if (this._isPredicate(keyNodeOrEntry)) nodeToDelete = this.getNode(keyNodeOrEntry);
291
- else nodeToDelete = this.isRealNode(keyNodeOrEntry) ? keyNodeOrEntry : this.getNode(keyNodeOrEntry);
290
+ if (this._isPredicate(keyNodeEntryRawOrPredicate)) nodeToDelete = this.getNode(keyNodeEntryRawOrPredicate);
291
+ else nodeToDelete = this.isRealNode(keyNodeEntryRawOrPredicate) ? keyNodeEntryRawOrPredicate : this.getNode(keyNodeEntryRawOrPredicate);
292
292
  if (!nodeToDelete) {
293
293
  return results;
294
294
  }
@@ -331,9 +331,10 @@ export class TreeCounter<K = any, V = any, R = any> extends RedBlackTree<K, V, R
331
331
  }
332
332
  } else {
333
333
  if (ignoreCount || nodeToDelete.count <= 1) {
334
+ // Removing the successor from its original position should NOT change total count;
335
+ // only removing the target node should affect the aggregate count.
334
336
  if (successor.right !== null) {
335
337
  this._transplant(successor, successor.right);
336
- this._count -= nodeToDelete.count;
337
338
  }
338
339
  } else {
339
340
  nodeToDelete.count--;
@@ -437,7 +438,7 @@ export class TreeCounter<K = any, V = any, R = any> extends RedBlackTree<K, V, R
437
438
 
438
439
  let index = 0;
439
440
  for (const [key, value] of this) {
440
- out.add(callback.call(thisArg, value, key, index++, this));
441
+ out.set(callback.call(thisArg, value, key, index++, this));
441
442
  }
442
443
  return out;
443
444
  }
@@ -450,7 +451,18 @@ export class TreeCounter<K = any, V = any, R = any> extends RedBlackTree<K, V, R
450
451
  override clone(): this {
451
452
  const out = this._createInstance<K, V, R>();
452
453
  this._clone(out as unknown as any);
454
+
455
+ // Preserve aggregate count and per-node counts.
453
456
  (out as any)._count = (this as any)._count;
457
+
458
+ // NOTE: RedBlackTree._clone copies structure/keys/values, but TreeCounter nodes also track `count`.
459
+ // Copy counts by key to keep getComputedCount() consistent.
460
+ for (const node of this.dfs(n => n, 'IN')) {
461
+ if (!node) continue;
462
+ const outNode = (out as unknown as TreeCounter<K, V, R>).getNode(node.key) as any;
463
+ if (outNode) outNode.count = node.count;
464
+ }
465
+
454
466
  return out as unknown as this;
455
467
  }
456
468
 
@@ -364,7 +364,7 @@ export class TreeMultiMap<K = any, V = any, R = any> extends RedBlackTree<K, V[]
364
364
  ) {
365
365
  super([], { ...options });
366
366
  if (keysNodesEntriesOrRaws) {
367
- this.addMany(keysNodesEntriesOrRaws);
367
+ this.setMany(keysNodesEntriesOrRaws);
368
368
  }
369
369
  }
370
370
 
@@ -385,29 +385,29 @@ export class TreeMultiMap<K = any, V = any, R = any> extends RedBlackTree<K, V[]
385
385
  return keyNodeOrEntry instanceof TreeMultiMapNode;
386
386
  }
387
387
 
388
- override add(
388
+ override set(
389
389
  keyNodeOrEntry: K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined
390
390
  ): boolean;
391
391
 
392
- override add(key: K, value: V): boolean;
392
+ override set(key: K, value: V): boolean;
393
393
 
394
394
  /**
395
395
  * Insert a value or a list of values into the multimap. If the key exists, values are appended.
396
396
  * @remarks Time O(log N + M), Space O(1)
397
397
  * @param keyNodeOrEntry - Key, node, or [key, values] entry.
398
- * @param [value] - Single value to add when a bare key is provided.
398
+ * @param [value] - Single value to set when a bare key is provided.
399
399
  * @returns True if inserted or appended; false if ignored.
400
400
  */
401
- override add(
401
+ override set(
402
402
  keyNodeOrEntry: K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined,
403
403
  value?: V
404
404
  ): boolean {
405
- if (this.isRealNode(keyNodeOrEntry)) return super.add(keyNodeOrEntry);
405
+ if (this.isRealNode(keyNodeOrEntry)) return super.set(keyNodeOrEntry);
406
406
 
407
407
  const _commonAdd = (key?: BTNOptKeyOrNull<K>, values?: V[]) => {
408
408
  if (key === undefined || key === null) return false;
409
409
 
410
- const _addToValues = () => {
410
+ const _setToValues = () => {
411
411
  const existingValues = this.get(key);
412
412
  if (existingValues !== undefined && values !== undefined) {
413
413
  for (const value of values) existingValues.push(value);
@@ -416,12 +416,12 @@ export class TreeMultiMap<K = any, V = any, R = any> extends RedBlackTree<K, V[]
416
416
  return false;
417
417
  };
418
418
 
419
- const _addByNode = () => {
419
+ const _setByNode = () => {
420
420
  const existingNode = this.getNode(key);
421
421
  if (this.isRealNode(existingNode)) {
422
422
  const existingValues = this.get(existingNode);
423
423
  if (existingValues === undefined) {
424
- super.add(key, values);
424
+ super.set(key, values);
425
425
  return true;
426
426
  }
427
427
  if (values !== undefined) {
@@ -431,14 +431,14 @@ export class TreeMultiMap<K = any, V = any, R = any> extends RedBlackTree<K, V[]
431
431
  return false;
432
432
  }
433
433
  } else {
434
- return super.add(key, values);
434
+ return super.set(key, values);
435
435
  }
436
436
  };
437
437
 
438
438
  if (this._isMapMode) {
439
- return _addByNode() || _addToValues();
439
+ return _setByNode() || _setToValues();
440
440
  }
441
- return _addToValues() || _addByNode();
441
+ return _setToValues() || _setByNode();
442
442
  };
443
443
 
444
444
  if (this.isEntry(keyNodeOrEntry)) {
@@ -503,7 +503,7 @@ export class TreeMultiMap<K = any, V = any, R = any> extends RedBlackTree<K, V[]
503
503
  ): RedBlackTree<MK, MV, MR> {
504
504
  const out = this._createLike<MK, MV, MR>([], options);
505
505
  let i = 0;
506
- for (const [k, v] of this) out.add(callback.call(thisArg, v, k, i++, this));
506
+ for (const [k, v] of this) out.set(callback.call(thisArg, v, k, i++, this));
507
507
  return out;
508
508
  }
509
509
 
@@ -880,6 +880,16 @@ export class Deque<E = any, R = any> extends LinearBase<E, R> {
880
880
 
881
881
  protected _setBucketSize(size: number): void {
882
882
  this._bucketSize = size;
883
+
884
+ // When adjusting bucketSize on a freshly created empty deque (common in helpers like cut/splice/clone),
885
+ // we must also realign internal pointers/buckets to avoid `_getBucketAndPosition` producing out-of-range
886
+ // indices based on the previous bucketSize.
887
+ if (this._length === 0) {
888
+ this._buckets = [new Array(this._bucketSize)];
889
+ this._bucketCount = 1;
890
+ this._bucketFirst = this._bucketLast = 0;
891
+ this._firstInBucket = this._lastInBucket = this._bucketSize >> 1;
892
+ }
883
893
  }
884
894
 
885
895
  /**
@@ -50,7 +50,7 @@ export interface IBinaryTree<K = any, V = any, R = any> {
50
50
 
51
51
  // Accept BTNRep, predicate, or raw R for deletion
52
52
  delete(
53
- keyNodeEntryRawOrPredicate: R | BTNRep<K, V, BinaryTreeNode<K, V>> | NodePredicate<BinaryTreeNode<K, V> | null>
53
+ keyNodeEntryRawOrPredicate: BTNRep<K, V, BinaryTreeNode<K, V>> | NodePredicate<BinaryTreeNode<K, V> | null>
54
54
  ): BinaryTreeDeleteResult<BinaryTreeNode<K, V>>[];
55
55
 
56
56
  clear(): void;
@@ -17,8 +17,7 @@ suite
17
17
  // for (let i = 0; i < randomArray.length; i++) rbTree.set(randomArray[i]);
18
18
  // })
19
19
  .add(`${MILLION.toLocaleString()} set`, () => {
20
- rbTree.clear();
21
- for (let i = 0; i < randomArray.length; i++) rbTree.set(i);
20
+ for (let i = 0; i < randomArray.length; i++) rbTree.set(randomArray[i], randomArray[i]);
22
21
  })
23
22
  .add(`${MILLION.toLocaleString()} get`, () => {
24
23
  for (let i = 0; i < randomArray.length; i++) rbTree.get(randomArray[i]);
@@ -0,0 +1,106 @@
1
+ import { IterableElementBase } from '../../../../src/data-structures/base/iterable-element-base';
2
+
3
+ class TestIterable extends IterableElementBase<number, number> {
4
+ private _arr: number[];
5
+
6
+ constructor(arr: number[] = [], opts?: any) {
7
+ super(opts);
8
+ this._arr = [...arr];
9
+ }
10
+
11
+ protected *_getIterator(): IterableIterator<number> {
12
+ yield* this._arr;
13
+ }
14
+
15
+ isEmpty(): boolean {
16
+ return this._arr.length === 0;
17
+ }
18
+
19
+ clear(): void {
20
+ this._arr.length = 0;
21
+ }
22
+
23
+ clone(): this {
24
+ return new TestIterable(this._arr, { toElementFn: this.toElementFn }) as unknown as this;
25
+ }
26
+
27
+ map<EM, RM>(cb: any, options?: any, thisArg?: unknown): IterableElementBase<EM, RM> {
28
+ const out = this._arr.map((v, i) => cb.call(thisArg, v, i, this));
29
+ // For tests we keep it minimal; toElementFn unused.
30
+ return new TestIterable(out as any, options) as any;
31
+ }
32
+
33
+ mapSame(cb: any, thisArg?: unknown): this {
34
+ return new TestIterable(this._arr.map((v, i) => cb.call(thisArg, v, i, this))) as unknown as this;
35
+ }
36
+
37
+ filter(pred: any, thisArg?: unknown): this {
38
+ const out: number[] = [];
39
+ let i = 0;
40
+ for (const v of this) {
41
+ if (pred.call(thisArg, v, i++, this)) out.push(v);
42
+ }
43
+ return new TestIterable(out) as unknown as this;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Coverage-focused tests for IterableElementBase.
49
+ * Keep existing @example tests intact.
50
+ */
51
+ describe('IterableElementBase coverage', () => {
52
+ it('constructor rejects non-function toElementFn when truthy', () => {
53
+ expect(() => new TestIterable([], { toElementFn: 123 as any })).toThrow(TypeError);
54
+ });
55
+
56
+ it('every/some/forEach/find cover thisArg and non-thisArg paths', () => {
57
+ const t = new TestIterable([1, 2, 3]);
58
+
59
+ // thisArg === undefined path
60
+ expect(t.every(v => v > 0)).toBe(true);
61
+ expect(t.some(v => v === 2)).toBe(true);
62
+
63
+ // thisArg path
64
+ const ctx = { mul: 2, seen: [] as number[] };
65
+ expect(
66
+ t.every(function (this: any, v: number) {
67
+ return v * this.mul > 0;
68
+ }, ctx)
69
+ ).toBe(true);
70
+
71
+ t.forEach(function (this: any, v: number) {
72
+ this.seen.push(v);
73
+ }, ctx);
74
+ expect(ctx.seen).toEqual([1, 2, 3]);
75
+
76
+ const found = t.find(function (this: any, v: number) {
77
+ return v === 3;
78
+ }, ctx);
79
+ expect(found).toBe(3);
80
+ });
81
+
82
+ it('reduce throws on empty without initialValue, works with/without initialValue', () => {
83
+ const empty = new TestIterable([]);
84
+ expect(() => empty.reduce((acc: number, v: number) => acc + v)).toThrow(TypeError);
85
+
86
+ const t = new TestIterable([1, 2, 3]);
87
+ expect(t.reduce((acc: number, v: number) => acc + v, 0)).toBe(6);
88
+
89
+ // no initialValue uses first element
90
+ expect(t.reduce((acc: number, v: number) => acc + v)).toBe(6);
91
+ });
92
+
93
+ it('values/toArray/toVisual/print/has basics', () => {
94
+ const t = new TestIterable([1, 2]);
95
+ expect([...t.values()]).toEqual([1, 2]);
96
+ expect(t.toArray()).toEqual([1, 2]);
97
+ expect(t.toVisual()).toEqual([1, 2]);
98
+ expect(t.has(2)).toBe(true);
99
+ expect(t.has(3)).toBe(false);
100
+
101
+ const spy = jest.spyOn(console, 'log').mockImplementation(() => undefined);
102
+ t.print();
103
+ expect(spy).toHaveBeenCalled();
104
+ spy.mockRestore();
105
+ });
106
+ });
@@ -0,0 +1,61 @@
1
+ import { ElementCallback, IterableElementBaseOptions } from 'src';
2
+ import { IterableElementBase } from '../../../../src/data-structures/base/iterable-element-base';
3
+
4
+ class NumIter extends IterableElementBase<number, number> {
5
+ override isEmpty(): boolean {
6
+ throw new Error('Method not implemented.');
7
+ }
8
+ override clear(): void {
9
+ throw new Error('Method not implemented.');
10
+ }
11
+ override clone(): this {
12
+ throw new Error('Method not implemented.');
13
+ }
14
+ override map<EM, RM>(
15
+ callback: ElementCallback<number, number, EM>,
16
+ options?: IterableElementBaseOptions<EM, RM> | undefined,
17
+ thisArg?: unknown
18
+ ): IterableElementBase<EM, RM> {
19
+ throw new Error('Method not implemented.');
20
+ }
21
+ override mapSame(callback: ElementCallback<number, number, number>, thisArg?: unknown): this {
22
+ throw new Error('Method not implemented.');
23
+ }
24
+ override filter(predicate: ElementCallback<number, number, boolean>, thisArg?: unknown): this {
25
+ throw new Error('Method not implemented.');
26
+ }
27
+ protected override _getIterator(...args: unknown[]): IterableIterator<number> {
28
+ throw new Error('Method not implemented.');
29
+ }
30
+ constructor(private readonly data: number[]) {
31
+ super();
32
+ }
33
+
34
+ override *[Symbol.iterator](): IterableIterator<number> {
35
+ for (const n of this.data) yield n;
36
+ }
37
+ }
38
+
39
+ describe('IterableElementBase remaining branch coverage', () => {
40
+ it('every() uses thisArg branch (fn.call) and can early-return false', () => {
41
+ const it = new NumIter([1, 2, 3]);
42
+
43
+ const ctx = { limit: 2 };
44
+ const res = it.every(function (this: any, v: number) {
45
+ return v <= this.limit;
46
+ }, ctx);
47
+
48
+ expect(res).toBe(false);
49
+ });
50
+
51
+ it('some() uses thisArg branch (fn.call) and can early-return true', () => {
52
+ const it = new NumIter([1, 2, 3]);
53
+
54
+ const ctx = { pick: 2 };
55
+ const res = it.some(function (this: any, v: number) {
56
+ return v === this.pick;
57
+ }, ctx);
58
+
59
+ expect(res).toBe(true);
60
+ });
61
+ });
@@ -0,0 +1,168 @@
1
+ import { IterableElementBase } from 'src';
2
+ import { LinearBase } from '../../../../src/data-structures/base/linear-base';
3
+ import type { ElementCallback, IterableElementBaseOptions, LinearBaseOptions } from '../../../../src/types';
4
+
5
+ class TestArrayLinear extends LinearBase<number, number> {
6
+ override isEmpty(): boolean {
7
+ throw new Error('Method not implemented.');
8
+ }
9
+ override map<EM, RM>(
10
+ callback: ElementCallback<number, number, EM>,
11
+ options?: IterableElementBaseOptions<EM, RM> | undefined,
12
+ thisArg?: unknown
13
+ ): IterableElementBase<EM, RM> {
14
+ throw new Error('Method not implemented.');
15
+ }
16
+ override mapSame(callback: ElementCallback<number, number, number>, thisArg?: unknown): this {
17
+ throw new Error('Method not implemented.');
18
+ }
19
+ override filter(predicate: ElementCallback<number, number, boolean>, thisArg?: unknown): this {
20
+ throw new Error('Method not implemented.');
21
+ }
22
+ private _arr: number[];
23
+
24
+ constructor(values: number[] = [], options?: LinearBaseOptions<number, number>) {
25
+ super(options);
26
+ this._arr = values.slice();
27
+ }
28
+
29
+ get length(): number {
30
+ return this._arr.length;
31
+ }
32
+
33
+ clear(): void {
34
+ this._arr.length = 0;
35
+ }
36
+
37
+ setAt(index: number, value: number): boolean {
38
+ if (index < 0 || index >= this._arr.length) return false;
39
+ this._arr[index] = value;
40
+ return true;
41
+ }
42
+
43
+ clone(): this {
44
+ const out = this._createInstance();
45
+ out.pushMany(this._arr);
46
+ return out;
47
+ }
48
+
49
+ reverse(): this {
50
+ this._arr.reverse();
51
+ return this;
52
+ }
53
+
54
+ push(elementOrNode: number): boolean {
55
+ if (this.maxLen > 0 && this._arr.length >= this.maxLen) return false;
56
+ this._arr.push(elementOrNode);
57
+ return true;
58
+ }
59
+
60
+ pushMany(elements: Iterable<number>): boolean[] {
61
+ const out: boolean[] = [];
62
+ for (const e of elements) out.push(this.push(e));
63
+ return out;
64
+ }
65
+
66
+ delete(elementOrNode: number | undefined): boolean {
67
+ if (elementOrNode === undefined) return false;
68
+ const idx = this._arr.indexOf(elementOrNode);
69
+ if (idx === -1) return false;
70
+ this._arr.splice(idx, 1);
71
+ return true;
72
+ }
73
+
74
+ at(index: number): number | undefined {
75
+ return this._arr[index];
76
+ }
77
+
78
+ deleteAt(pos: number): number | undefined {
79
+ if (pos < 0 || pos >= this._arr.length) return undefined;
80
+ return this._arr.splice(pos, 1)[0];
81
+ }
82
+
83
+ addAt(index: number, newElementOrNode: number): boolean {
84
+ if (this.maxLen > 0 && this._arr.length >= this.maxLen) return false;
85
+ if (index < 0) index = 0;
86
+ if (index > this._arr.length) index = this._arr.length;
87
+ this._arr.splice(index, 0, newElementOrNode);
88
+ return true;
89
+ }
90
+
91
+ override toArray(): number[] {
92
+ return this._arr.slice();
93
+ }
94
+
95
+ protected _createInstance(options?: LinearBaseOptions<number, number>): this {
96
+ return new TestArrayLinear([], options) as unknown as this;
97
+ }
98
+
99
+ protected *_getIterator(): IterableIterator<number> {
100
+ for (const v of this._arr) yield v;
101
+ }
102
+
103
+ protected *_getReverseIterator(): IterableIterator<number> {
104
+ for (let i = this._arr.length - 1; i >= 0; i--) yield this._arr[i];
105
+ }
106
+ }
107
+
108
+ describe('LinearBase coverage (array-backed subclass)', () => {
109
+ it('constructor maxLen branch: accept positive int and ignore non-int/invalid', () => {
110
+ const a = new TestArrayLinear([], { maxLen: 3 });
111
+ expect(a.maxLen).toBe(3);
112
+
113
+ const b = new TestArrayLinear([], { maxLen: 2.2 } as any);
114
+ expect(b.maxLen).toBe(-1);
115
+
116
+ const c = new TestArrayLinear([], { maxLen: -5 } as any);
117
+ expect(c.maxLen).toBe(-1);
118
+ });
119
+
120
+ it('indexOf/lastIndexOf cover empty and fromIndex normalization', () => {
121
+ const empty = new TestArrayLinear();
122
+ expect(empty.indexOf(1)).toBe(-1);
123
+ expect(empty.lastIndexOf(1)).toBe(-1);
124
+
125
+ const list = new TestArrayLinear([1, 2, 3, 2, 1]);
126
+
127
+ expect(list.indexOf(2, -2)).toBe(3); // length + (-2) => 3
128
+ expect(list.indexOf(1, -999)).toBe(0); // clamp to 0
129
+ expect(list.lastIndexOf(2, 999)).toBe(3); // clamp to length-1
130
+
131
+ // fromIndex < 0 => length + fromIndex (may still be negative) -> returns -1
132
+ expect(list.lastIndexOf(2, -999)).toBe(-1);
133
+ });
134
+
135
+ it('concat/sort/join/toReversedArray exercise LinearBase helpers', () => {
136
+ const a = new TestArrayLinear([3, 1, 2]);
137
+ const b = new TestArrayLinear([9]);
138
+
139
+ const c = a.concat(b, 7);
140
+ expect(c.toArray()).toEqual([3, 1, 2, 9, 7]);
141
+
142
+ expect(c.join('-')).toBe('3-1-2-9-7');
143
+ expect(c.toReversedArray()).toEqual([7, 9, 2, 1, 3]);
144
+
145
+ c.sort((x, y) => x - y);
146
+ expect(c.toArray()).toEqual([1, 2, 3, 7, 9]);
147
+ });
148
+
149
+ it('slice/splice/fill cover negative indices and early-return branches', () => {
150
+ const list = new TestArrayLinear([1, 2, 3, 4]);
151
+
152
+ // slice negative end/start
153
+ expect(list.slice(1, -1).toArray()).toEqual([2, 3]);
154
+ expect(list.slice(-1, -1).toArray()).toEqual([]);
155
+
156
+ // splice clamps start/deleteCount
157
+ const removed = list.splice(-2, 999, 8, 9);
158
+ expect(removed.toArray()).toEqual([3, 4]);
159
+ expect(list.toArray()).toEqual([1, 2, 8, 9]);
160
+
161
+ // fill clamps and early return when start>=end
162
+ list.fill(0, 3, 2);
163
+ expect(list.toArray()).toEqual([1, 2, 8, 9]);
164
+
165
+ list.fill(5, -999, 999);
166
+ expect(list.toArray()).toEqual([5, 5, 5, 5]);
167
+ });
168
+ });
@@ -0,0 +1,82 @@
1
+ import { ElementCallback, IterableElementBaseOptions, IterableElementBase } from 'src';
2
+ import { LinearBase, LinkedListNode } from '../../../../src/data-structures/base/linear-base';
3
+
4
+ type R = number;
5
+
6
+ class ArrayLinear extends LinearBase<number, R> {
7
+ override setAt(index: number, value: number): boolean {
8
+ throw new Error('Method not implemented.');
9
+ }
10
+ override reverse(): this {
11
+ throw new Error('Method not implemented.');
12
+ }
13
+ override delete(elementOrNode: number | LinkedListNode<number> | undefined): boolean {
14
+ throw new Error('Method not implemented.');
15
+ }
16
+ override deleteAt(pos: number): number | undefined {
17
+ throw new Error('Method not implemented.');
18
+ }
19
+ override addAt(index: number, newElementOrNode: number | LinkedListNode<number>): boolean {
20
+ throw new Error('Method not implemented.');
21
+ }
22
+ protected override _getReverseIterator(...args: any[]): IterableIterator<number> {
23
+ throw new Error('Method not implemented.');
24
+ }
25
+ override isEmpty(): boolean {
26
+ throw new Error('Method not implemented.');
27
+ }
28
+ override clear(): void {
29
+ throw new Error('Method not implemented.');
30
+ }
31
+ override map<EM, RM>(
32
+ callback: ElementCallback<number, number, EM>,
33
+ options?: IterableElementBaseOptions<EM, RM> | undefined,
34
+ thisArg?: unknown
35
+ ): IterableElementBase<EM, RM> {
36
+ throw new Error('Method not implemented.');
37
+ }
38
+ override mapSame(callback: ElementCallback<number, number, number>, thisArg?: unknown): this {
39
+ throw new Error('Method not implemented.');
40
+ }
41
+ override filter(predicate: ElementCallback<number, number, boolean>, thisArg?: unknown): this {
42
+ throw new Error('Method not implemented.');
43
+ }
44
+ protected _data: number[];
45
+ constructor(iter: Iterable<number> = []) {
46
+ super();
47
+ this._data = Array.from(iter);
48
+ }
49
+ override get length(): number {
50
+ return this._data.length;
51
+ }
52
+ protected _getIterator(): IterableIterator<number> {
53
+ return this._data[Symbol.iterator]();
54
+ }
55
+ protected _createInstance(): this {
56
+ return new ArrayLinear() as any;
57
+ }
58
+ override clone(): this {
59
+ return new ArrayLinear(this._data) as any;
60
+ }
61
+ override push(element: number): boolean {
62
+ this._data.push(element);
63
+ return true;
64
+ }
65
+ override pushMany(elements: Iterable<number>): boolean[] {
66
+ const ans: boolean[] = [];
67
+ for (const e of elements) ans.push(this.push(e));
68
+ return ans;
69
+ }
70
+ override at(index: number): number | undefined {
71
+ return this._data[index];
72
+ }
73
+ }
74
+
75
+ describe('LinearBase concat else-branch coverage', () => {
76
+ it('concat(item) uses else-branch when item is not a LinearBase', () => {
77
+ const l = new ArrayLinear([1, 2]);
78
+ // Use any-call to avoid TS overload narrowing affecting runtime call site.
79
+ const out = (l as any).concat(3);
80
+ expect(out.toArray()).toEqual([1, 2, 3]);
81
+ });
82
+ });