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
@@ -0,0 +1,115 @@
1
+ import { TreeCounter, TreeCounterNode } from '../../../../src';
2
+
3
+ /**
4
+ * Coverage-focused tests for TreeCounter branches (count aggregation + delete paths).
5
+ * Keep existing @example tests intact.
6
+ */
7
+ describe('TreeCounter coverage', () => {
8
+ it('TreeCounterNode.familyPosition covers ROOT/LEFT/RIGHT/ISOLATED cases', () => {
9
+ const isolated = new TreeCounterNode<number, number>(1);
10
+ expect(isolated.familyPosition).toBe('ISOLATED');
11
+
12
+ const root = new TreeCounterNode<number, number>(10);
13
+ const left = new TreeCounterNode<number, number>(5);
14
+ root.left = left;
15
+ expect(root.familyPosition).toBe('ROOT');
16
+ expect(left.familyPosition).toBe('LEFT');
17
+
18
+ left.left = new TreeCounterNode<number, number>(2);
19
+ expect(left.familyPosition).toBe('ROOT_LEFT');
20
+
21
+ const right = new TreeCounterNode<number, number>(15);
22
+ root.right = right;
23
+ expect(right.familyPosition).toBe('RIGHT');
24
+
25
+ right.right = new TreeCounterNode<number, number>(20);
26
+ expect(right.familyPosition).toBe('ROOT_RIGHT');
27
+ });
28
+
29
+ it('set increments aggregate count and createNode respects mapMode', () => {
30
+ const tc = new TreeCounter<number, string>();
31
+ tc.set(1, 'a', 2);
32
+ tc.set(2, 'b', 3);
33
+
34
+ expect(tc.count).toBe(5);
35
+ expect(tc.getComputedCount()).toBe(5);
36
+
37
+ // mapMode ignores node.value
38
+ const tcMap = new TreeCounter<number, string>([], { isMapMode: true });
39
+ tcMap.set(1, 'a', 2);
40
+ expect(tcMap.getNode(1)?.value).toBe(undefined);
41
+ });
42
+
43
+ it('delete decrements count when node.count>1 unless ignoreCount=true', () => {
44
+ const tc = new TreeCounter<number, number>();
45
+ tc.set(10, 10, 3);
46
+ expect(tc.count).toBe(3);
47
+
48
+ // decrement path
49
+ const r1 = tc.delete(10);
50
+ expect(r1).toHaveLength(1);
51
+ expect(tc.getNode(10)?.count).toBe(2);
52
+ expect(tc.count).toBe(2);
53
+
54
+ // ignoreCount removes node
55
+ const r2 = tc.delete(10, true);
56
+ expect(r2).toHaveLength(1);
57
+ expect(tc.getNode(10)).toBeUndefined();
58
+ expect(tc.count).toBe(0);
59
+ });
60
+
61
+ it('delete covers left-only/right-only and two-child paths', () => {
62
+ const tc = new TreeCounter<number, number>();
63
+
64
+ // right-only child case
65
+ tc.set(10, 10, 1);
66
+ tc.set(20, 20, 1);
67
+ expect(tc.delete(10, true)).toHaveLength(1);
68
+ expect(tc.getNode(10)).toBeUndefined();
69
+
70
+ tc.clear();
71
+
72
+ // left-only child case
73
+ tc.set(10, 10, 1);
74
+ tc.set(5, 5, 1);
75
+ expect(tc.delete(10, true)).toHaveLength(1);
76
+ expect(tc.getNode(10)).toBeUndefined();
77
+
78
+ tc.clear();
79
+
80
+ // two children successor path
81
+ for (const k of [10, 5, 15, 12, 18]) tc.set(k, k, 1);
82
+ expect(tc.delete(10, true)).toHaveLength(1);
83
+ expect(tc.getNode(10)).toBeUndefined();
84
+ expect(tc.count).toBe(4);
85
+ });
86
+
87
+ it('perfectlyBalance returns false on empty and true on non-empty (preserves count)', () => {
88
+ const tcEmpty = new TreeCounter<number, number>();
89
+ expect(tcEmpty.perfectlyBalance()).toBe(false);
90
+
91
+ const tc = new TreeCounter<number, number>();
92
+ tc.set(3, 3, 2);
93
+ tc.set(1, 1, 1);
94
+ tc.set(4, 4, 1);
95
+ expect(tc.count).toBe(4);
96
+
97
+ expect(tc.perfectlyBalance('ITERATIVE')).toBe(true);
98
+ expect(tc.count).toBe(4);
99
+ expect(tc.getComputedCount()).toBe(4);
100
+ });
101
+
102
+ it('map/clone exercise _createLike/_createInstance and preserve aggregate count', () => {
103
+ const tc = new TreeCounter<number, number>();
104
+ tc.set(1, 10, 2);
105
+ tc.set(2, 20, 1);
106
+
107
+ const mapped = tc.map((v, k) => [k + 1, (v ?? 0) + 1]);
108
+ expect(mapped.get(2)).toBe(11);
109
+ expect(mapped.get(3)).toBe(21);
110
+
111
+ const cloned = tc.clone();
112
+ expect(cloned.count).toBe(tc.count);
113
+ expect(cloned.getComputedCount()).toBe(tc.count);
114
+ });
115
+ });
@@ -0,0 +1,244 @@
1
+ import { TreeCounter, TreeCounterNode } from '../../../../src';
2
+
3
+ describe('TreeCounter additional branch coverage', () => {
4
+ it('getComputedCount sums 0 for null nodes (covers node ? node.count : 0 false arm)', () => {
5
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
6
+
7
+ // Force dfs callback to receive a null once, so ternary false arm is executed.
8
+ const origDfs = (t as any).dfs;
9
+ (t as any).dfs = (cb: any) => {
10
+ cb(null);
11
+ return [];
12
+ };
13
+
14
+ try {
15
+ expect(t.getComputedCount()).toBe(0);
16
+ } finally {
17
+ (t as any).dfs = origDfs;
18
+ }
19
+ });
20
+
21
+ it('createNode default color arg branch and mapMode=true forces value undefined', () => {
22
+ const t = new TreeCounter<number, number>([], { isMapMode: true } as any);
23
+ const n = t.createNode(1, 123); // default color arg
24
+ expect(n.value).toBeUndefined();
25
+ });
26
+
27
+ it('set() with null/undefined keyNodeOrEntry makes orgCount=0 and returns false (covers orgCount false arm)', () => {
28
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
29
+ expect(t.set(undefined as any)).toBe(false);
30
+ expect(t.set(null as any)).toBe(false);
31
+ });
32
+
33
+ it('delete(null) returns [] (covers early return)', () => {
34
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
35
+ expect(t.delete(null as any)).toEqual([]);
36
+ });
37
+
38
+ it('delete(predicate) uses predicate branch and returns [] when predicate matches none', () => {
39
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
40
+ t.set(1, 1);
41
+ expect(t.delete((n) => n?.key === 999)).toEqual([]);
42
+ });
43
+
44
+ it('delete(realNode) uses the isRealNode(keyNodeOrEntry) ? keyNodeOrEntry : getNode(...) true arm', () => {
45
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
46
+ t.set(10, 10);
47
+ t.set(5, 5);
48
+ t.set(15, 15);
49
+
50
+ const n = t.getNode(5)!;
51
+ const res = t.delete(n as any, true);
52
+ expect(res.length).toBe(1);
53
+ expect(t.has(5)).toBe(false);
54
+ });
55
+
56
+ it('delete(decrement count) path when node.count>1 and ignoreCount=false', () => {
57
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
58
+ t.set(1, 1);
59
+ t.set(1, 1);
60
+ expect(t.count).toBe(2);
61
+
62
+ const res = t.delete(1, false);
63
+ expect(res.length).toBe(1);
64
+ expect(t.count).toBe(1);
65
+ expect(t.getNode(1)!.count).toBe(1);
66
+ });
67
+
68
+ it('delete(two children) else-branch with successor.parent !== nodeToDelete and ignoreCount=true', () => {
69
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
70
+
71
+ // Build a BST-shape manually to avoid balancing changing successor relationships.
72
+ // nodeToDelete = 10, right subtree has left chain so successor.parent !== nodeToDelete
73
+ const n10: any = t.createNode(10, 10);
74
+ const n5: any = t.createNode(5, 5);
75
+ const n15: any = t.createNode(15, 15);
76
+ const n12: any = t.createNode(12, 12);
77
+ const n11: any = t.createNode(11, 11);
78
+
79
+ n10.left = n5;
80
+ n10.right = n15;
81
+ n5.parent = n10;
82
+ n15.parent = n10;
83
+
84
+ n15.left = n12;
85
+ n12.parent = n15;
86
+
87
+ n12.left = n11;
88
+ n11.parent = n12;
89
+
90
+ (t as any)._setRoot(n10);
91
+ (t as any)._size = 5;
92
+ (t as any)._count = 5;
93
+
94
+ const out = t.delete(10, true);
95
+ expect(out.length).toBe(1);
96
+ expect(t.has(10)).toBe(false);
97
+ });
98
+
99
+ it('perfectlyBalance uses default iterationType arg and recomputes _count (also covers nd?nd.count:0 false arm via dfs monkeypatch)', () => {
100
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
101
+ expect(t.perfectlyBalance('ITERATIVE' as any)).toBe(false);
102
+
103
+ t.set(3, 3);
104
+ t.set(1, 1);
105
+ t.set(2, 2);
106
+
107
+ // call without arg to cover default-arg branch (iterationType = this.iterationType)
108
+ expect(t.perfectlyBalance()).toBe(true);
109
+ expect(t.count).toBe(3);
110
+
111
+ // additionally, cover the nd ? nd.count : 0 false arm in the internal total recompute loop,
112
+ // without breaking index-based access during tree rebuild.
113
+ const origDfs = (t as any).dfs;
114
+ (t as any).dfs = (...args: any[]) => {
115
+ const nodes: any[] = origDfs.apply(t, args);
116
+ const origIter = nodes[Symbol.iterator].bind(nodes);
117
+ // @ts-ignore
118
+ nodes[Symbol.iterator] = function* () {
119
+ yield null;
120
+ yield* origIter();
121
+ };
122
+ return nodes;
123
+ };
124
+ try {
125
+ expect(t.perfectlyBalance()).toBe(true);
126
+ } finally {
127
+ (t as any).dfs = origDfs;
128
+ }
129
+ });
130
+
131
+ it('map() uses thisArg + _createLike options path', () => {
132
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
133
+ t.set(1, 10);
134
+ t.set(2, 20);
135
+
136
+ const ctx = { mul: 3 };
137
+ const out = t.map(function (this: any, v: any, k: any) {
138
+ return [k + 10, v * this.mul];
139
+ }, { isMapMode: false } as any, ctx);
140
+
141
+ expect(out.has(11)).toBe(true);
142
+ expect(out.get(11)).toBe(30);
143
+ });
144
+
145
+ it('clone() covers both `if (!node) continue` and outNode missing branch', () => {
146
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
147
+ t.set(1, 1);
148
+ t.set(1, 1);
149
+ t.set(2, 2);
150
+
151
+ // Force dfs() used by clone() to yield a null once to hit `if (!node) continue`.
152
+ const origDfs = (t as any).dfs;
153
+ (t as any).dfs = (...args: any[]) => {
154
+ const nodes: any[] = origDfs.apply(t, args);
155
+ const origIter = nodes[Symbol.iterator].bind(nodes);
156
+ // @ts-ignore
157
+ nodes[Symbol.iterator] = function* () {
158
+ yield null;
159
+ yield* origIter();
160
+ };
161
+ return nodes;
162
+ };
163
+
164
+ const origCreateInstance = (t as any)._createInstance;
165
+ (t as any)._createInstance = () => {
166
+ const out = origCreateInstance.call(t);
167
+ // Make getNode return undefined so `if (outNode)` is false.
168
+ (out as any).getNode = () => undefined;
169
+ return out;
170
+ };
171
+
172
+ try {
173
+ const c = t.clone();
174
+ expect((c as any)._count).toBe((t as any)._count);
175
+ } finally {
176
+ (t as any)._createInstance = origCreateInstance;
177
+ (t as any).dfs = origDfs;
178
+ }
179
+ });
180
+
181
+ it('_createInstance uses options merge (covers options ?? {} merge)', () => {
182
+ const t = new TreeCounter<number, number>([], { isMapMode: false } as any);
183
+ const inst = (t as any)._createInstance({ iterationType: 'RECURSIVE' });
184
+ expect(inst).toBeDefined();
185
+ });
186
+
187
+ it('_createLike default-arg path can be called with no args', () => {
188
+ const t = new TreeCounter<number, number>([], { isMapMode: false } as any);
189
+ const like = (t as any)._createLike();
190
+ expect(like).toBeDefined();
191
+ });
192
+
193
+ it('_keyValueNodeOrEntryToNodeAndValue entry null key returns [undefined, undefined]', () => {
194
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
195
+ const out = (t as any)._keyValueNodeOrEntryToNodeAndValue([null, 1] as any);
196
+ expect(out).toEqual([undefined, undefined]);
197
+ });
198
+
199
+ it('_swapProperties returns undefined when ensureNode fails', () => {
200
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
201
+ expect((t as any)._swapProperties(null, null)).toBeUndefined();
202
+
203
+ // src ok, dest missing
204
+ t.set(1, 1);
205
+ const src = t.getNode(1)!;
206
+ expect((t as any)._swapProperties(src, 9999)).toBeUndefined();
207
+ });
208
+
209
+ it('_swapProperties in mapMode=true skips value-copy branches (covers !this._isMapMode false arms)', () => {
210
+ const t = new TreeCounter<number, number>([], { isMapMode: true } as any);
211
+ const a: any = t.createNode(1, 10);
212
+ const b: any = t.createNode(2, 20);
213
+ // attach as a tiny tree so ensureNode works
214
+ (t as any)._setRoot(a);
215
+ a.right = b;
216
+ b.parent = a;
217
+
218
+ const out = (t as any)._swapProperties(a, b);
219
+ expect(out).toBeDefined();
220
+ });
221
+
222
+ it('_swapProperties in mapMode=false executes value-copy branches (covers !this._isMapMode true arms)', () => {
223
+ const t = new TreeCounter<number, number>([], { isMapMode: false } as any);
224
+ const a: any = t.createNode(1, 10);
225
+ const b: any = t.createNode(2, 20);
226
+ (t as any)._setRoot(a);
227
+ a.right = b;
228
+ b.parent = a;
229
+
230
+ const out = (t as any)._swapProperties(a, b);
231
+ expect(out).toBeDefined();
232
+ // After swap, values should have been copied.
233
+ expect(a.value).toBe(20);
234
+ expect(b.value).toBe(10);
235
+ });
236
+
237
+ it('_replaceNode increments newNode.count before delegating', () => {
238
+ const t = new TreeCounter<number, number>([], { isMapMode: false });
239
+ const oldN = new TreeCounterNode(1, 1, 2, 'BLACK');
240
+ const newN = new TreeCounterNode(1, 1, 3, 'BLACK');
241
+ const out = (t as any)._replaceNode(oldN, newN);
242
+ expect(out.count).toBe(5);
243
+ });
244
+ });
@@ -12,7 +12,7 @@ describe('TreeCounter count', () => {
12
12
  });
13
13
 
14
14
  it('Should added node count ', () => {
15
- treeCounter.addMany([
15
+ treeCounter.setMany([
16
16
  [1, 1],
17
17
  [2, 2],
18
18
  [3, 3],
@@ -20,14 +20,14 @@ describe('TreeCounter count', () => {
20
20
  [5, 5]
21
21
  ]);
22
22
  const newNode = new TreeCounterNode(3, 33, 10);
23
- treeCounter.add(newNode);
23
+ treeCounter.set(newNode);
24
24
  expect(treeCounter.count).toBe(15);
25
25
  expect(treeCounter.getComputedCount()).toBe(15);
26
26
  expect(treeCounter.getNode(3)?.count).toBe(11);
27
27
  });
28
28
 
29
29
  it('Should count', () => {
30
- treeCounter.addMany([
30
+ treeCounter.setMany([
31
31
  [1, 1],
32
32
  [2, 2],
33
33
  [3, 3]
@@ -44,7 +44,7 @@ describe('TreeCounter operations test1', () => {
44
44
  expect(treeCounter.getHeight()).toBe(-1);
45
45
  expect(treeCounter.getMinHeight()).toBe(-1);
46
46
 
47
- treeCounter.addMany([1, 6, 7, 2, 3, 4, 9, 11, 8, 5, 10, 12, 16, 14, 13, 15]);
47
+ treeCounter.setMany([1, 6, 7, 2, 3, 4, 9, 11, 8, 5, 10, 12, 16, 14, 13, 15]);
48
48
  // treeCounter.print()
49
49
  expect(treeCounter.getHeight()).toBe(5);
50
50
  expect(treeCounter.getMinHeight()).toBe(2);
@@ -55,8 +55,8 @@ describe('TreeCounter operations test1', () => {
55
55
 
56
56
  expect(treeCounter instanceof TreeCounter);
57
57
 
58
- treeCounter.add([11, 11]);
59
- treeCounter.add([3, 3]);
58
+ treeCounter.set([11, 11]);
59
+ treeCounter.set([3, 3]);
60
60
  expect(treeCounter.count).toBe(2);
61
61
  expect(treeCounter.getComputedCount()).toBe(2);
62
62
  expect(treeCounter.size).toBe(2);
@@ -80,7 +80,7 @@ describe('TreeCounter operations test1', () => {
80
80
  [5, 5]
81
81
  ];
82
82
 
83
- treeCounter.addMany(keyValuePairs);
83
+ treeCounter.setMany(keyValuePairs);
84
84
  expect(treeCounter.size).toBe(16);
85
85
  expect(treeCounter.count).toBe(18);
86
86
  expect(treeCounter.getComputedCount()).toBe(18);
@@ -97,8 +97,8 @@ describe('TreeCounter operations test1', () => {
97
97
 
98
98
  expect(treeCounter instanceof TreeCounter);
99
99
 
100
- treeCounter.add([11, 11]);
101
- treeCounter.add([3, 3]);
100
+ treeCounter.set([11, 11]);
101
+ treeCounter.set([3, 3]);
102
102
  const idAndValues: [number, number][] = [
103
103
  [11, 11],
104
104
  [3, 3],
@@ -117,7 +117,7 @@ describe('TreeCounter operations test1', () => {
117
117
  [10, 10],
118
118
  [5, 5]
119
119
  ];
120
- treeCounter.addMany(idAndValues);
120
+ treeCounter.setMany(idAndValues);
121
121
  expect(treeCounter.root instanceof TreeCounterNode);
122
122
 
123
123
  if (treeCounter.root) expect(treeCounter.root.key == 11);
@@ -309,15 +309,16 @@ describe('TreeCounter operations test1', () => {
309
309
  expect(bfsNodes[1].key).toBe(2);
310
310
  expect(bfsNodes[2].key).toBe(16);
311
311
 
312
- expect(treeCounter.count).toBe(6);
312
+ // Aggregate count should match computed count.
313
+ expect(treeCounter.count).toBe(8);
313
314
  expect(treeCounter.getComputedCount()).toBe(8);
314
315
  });
315
316
 
316
317
  it('should perform various operations on a TreeCounter with object values', () => {
317
318
  const objTreeCounter = new TreeCounter<number, { key: number; keyA: number }>();
318
319
  expect(objTreeCounter).toBeInstanceOf(TreeCounter);
319
- objTreeCounter.add([11, { key: 11, keyA: 11 }]);
320
- objTreeCounter.add([3, { key: 3, keyA: 3 }]);
320
+ objTreeCounter.set([11, { key: 11, keyA: 11 }]);
321
+ objTreeCounter.set([3, { key: 3, keyA: 3 }]);
321
322
  const values: [number, { key: number; keyA: number }][] = [
322
323
  [15, { key: 15, keyA: 15 }],
323
324
  [1, { key: 1, keyA: 1 }],
@@ -335,7 +336,7 @@ describe('TreeCounter operations test1', () => {
335
336
  [5, { key: 5, keyA: 5 }]
336
337
  ];
337
338
 
338
- objTreeCounter.addMany(values);
339
+ objTreeCounter.setMany(values);
339
340
 
340
341
  expect(objTreeCounter.root).toBeInstanceOf(TreeCounterNode);
341
342
 
@@ -355,8 +356,8 @@ describe('TreeCounter operations test recursively1', () => {
355
356
  });
356
357
 
357
358
  expect(treeCounter instanceof TreeCounter);
358
- treeCounter.add([11, 11]);
359
- treeCounter.add([3, 3]);
359
+ treeCounter.set([11, 11]);
360
+ treeCounter.set([3, 3]);
360
361
  const idAndValues: [number, number][] = [
361
362
  [11, 11],
362
363
  [3, 3],
@@ -375,7 +376,7 @@ describe('TreeCounter operations test recursively1', () => {
375
376
  [10, 10],
376
377
  [5, 5]
377
378
  ];
378
- treeCounter.addMany(idAndValues);
379
+ treeCounter.setMany(idAndValues);
379
380
  expect(treeCounter.root).toBeInstanceOf(TreeCounterNode);
380
381
 
381
382
  if (treeCounter.root) expect(treeCounter.root.key).toBe(5);
@@ -576,15 +577,16 @@ describe('TreeCounter operations test recursively1', () => {
576
577
  expect(bfsNodes[1].key).toBe(2);
577
578
  expect(bfsNodes[2].key).toBe(16);
578
579
 
579
- expect(treeCounter.count).toBe(6);
580
+ // Aggregate count should match computed count.
581
+ expect(treeCounter.count).toBe(8);
580
582
  expect(treeCounter.getComputedCount()).toBe(8);
581
583
  });
582
584
 
583
585
  it('should perform various operations on a TreeCounter with object values', () => {
584
586
  const objTreeCounter = new TreeCounter<number, { key: number; keyA: number }>();
585
587
  expect(objTreeCounter).toBeInstanceOf(TreeCounter);
586
- objTreeCounter.add([11, { key: 11, keyA: 11 }]);
587
- objTreeCounter.add([3, { key: 3, keyA: 3 }]);
588
+ objTreeCounter.set([11, { key: 11, keyA: 11 }]);
589
+ objTreeCounter.set([3, { key: 3, keyA: 3 }]);
588
590
  const values: [number, { key: number; keyA: number }][] = [
589
591
  [15, { key: 15, keyA: 15 }],
590
592
  [1, { key: 1, keyA: 1 }],
@@ -602,7 +604,7 @@ describe('TreeCounter operations test recursively1', () => {
602
604
  [5, { key: 5, keyA: 5 }]
603
605
  ];
604
606
 
605
- objTreeCounter.addMany(values);
607
+ objTreeCounter.setMany(values);
606
608
 
607
609
  expect(objTreeCounter.root).toBeInstanceOf(TreeCounterNode);
608
610
 
@@ -631,7 +633,7 @@ describe('TreeCounter delete test', function () {
631
633
 
632
634
  it('The structure remains normal after random deletion', function () {
633
635
  for (let i = 0; i < inputSize; i++) {
634
- treeCounter.add(i);
636
+ treeCounter.set(i);
635
637
  }
636
638
 
637
639
  expect(treeCounter.size).toBe(inputSize);
@@ -660,7 +662,7 @@ describe('TreeCounter delete test', function () {
660
662
  for (let i = 0; i < inputSize; i++) {
661
663
  const num = getRandomInt(0, inputSize - 1);
662
664
  if (i === 0 && isDebug) console.log(`first:`, num);
663
- treeCounter.add(num);
665
+ treeCounter.set(num);
664
666
  }
665
667
 
666
668
  for (let i = 0; i < inputSize; i++) {
@@ -686,7 +688,7 @@ describe('TreeCounter delete test', function () {
686
688
  for (let i = 0; i < inputSize; i++) {
687
689
  const num = getRandomInt(0, inputSize - 1);
688
690
  if (i === 0 && isDebug) console.log(`first:`, num);
689
- treeCounter.add(num);
691
+ treeCounter.set(num);
690
692
  }
691
693
 
692
694
  for (let i = 0; i < inputSize; i++) {
@@ -721,7 +723,7 @@ describe('TreeCounter delete test', function () {
721
723
  }
722
724
 
723
725
  const treeCounter = new TreeCounter<string, number>();
724
- treeCounter.addMany([
726
+ treeCounter.setMany([
725
727
  ['2', 2],
726
728
  ['4', 4],
727
729
  ['5', 5],
@@ -750,9 +752,9 @@ describe('TreeCounter iterative methods test', () => {
750
752
  let treeCounter: TreeCounter<number, string>;
751
753
  beforeEach(() => {
752
754
  treeCounter = new TreeCounter<number, string>();
753
- treeCounter.add(1, 'a', 10);
754
- treeCounter.add([2, 'b'], undefined, 10);
755
- treeCounter.add([3, 'c'], undefined, 1);
755
+ treeCounter.set(1, 'a', 10);
756
+ treeCounter.set([2, 'b'], undefined, 10);
757
+ treeCounter.set([3, 'c'], undefined, 1);
756
758
  });
757
759
 
758
760
  it('The node obtained by get Node should match the node type', () => {
@@ -845,7 +847,7 @@ describe('TreeCounter count not map mode', () => {
845
847
  });
846
848
 
847
849
  it('Should added node count ', () => {
848
- treeCounter.addMany([
850
+ treeCounter.setMany([
849
851
  [1, 1],
850
852
  [2, 2],
851
853
  [3, 3],
@@ -853,7 +855,7 @@ describe('TreeCounter count not map mode', () => {
853
855
  [5, 5]
854
856
  ]);
855
857
  const newNode = new TreeCounterNode(3, undefined, 10);
856
- treeCounter.add(newNode, 33, 20);
858
+ treeCounter.set(newNode, 33, 20);
857
859
  // TODO expect(treeCounter.count).toBe(25);
858
860
  expect(treeCounter.count).toBe(15);
859
861
  expect(treeCounter.getComputedCount()).toBe(15);
@@ -867,8 +869,8 @@ describe('TreeCounter operations test1 not map mode', () => {
867
869
 
868
870
  expect(treeCounter instanceof TreeCounter);
869
871
 
870
- treeCounter.add([11, 11]);
871
- treeCounter.add([3, 3]);
872
+ treeCounter.set([11, 11]);
873
+ treeCounter.set([3, 3]);
872
874
  const idAndValues: [number, number][] = [
873
875
  [11, 11],
874
876
  [3, 3],
@@ -887,7 +889,7 @@ describe('TreeCounter operations test1 not map mode', () => {
887
889
  [10, 10],
888
890
  [5, 5]
889
891
  ];
890
- treeCounter.addMany(idAndValues);
892
+ treeCounter.setMany(idAndValues);
891
893
  expect(treeCounter.root instanceof TreeCounterNode);
892
894
 
893
895
  if (treeCounter.root) expect(treeCounter.root.key == 11);
@@ -916,8 +918,8 @@ describe('TreeCounter operations test recursively1 not map mode', () => {
916
918
  });
917
919
 
918
920
  expect(treeCounter instanceof TreeCounter);
919
- treeCounter.add([11, 11]);
920
- treeCounter.add([3, 3]);
921
+ treeCounter.set([11, 11]);
922
+ treeCounter.set([3, 3]);
921
923
  const idAndValues: [number, number][] = [
922
924
  [11, 11],
923
925
  [3, 3],
@@ -936,7 +938,7 @@ describe('TreeCounter operations test recursively1 not map mode', () => {
936
938
  [10, 10],
937
939
  [5, 5]
938
940
  ];
939
- treeCounter.addMany(idAndValues);
941
+ treeCounter.setMany(idAndValues);
940
942
  expect(treeCounter.root).toBeInstanceOf(TreeCounterNode);
941
943
 
942
944
  if (treeCounter.root) expect(treeCounter.root.key).toBe(5);
@@ -961,9 +963,9 @@ describe('TreeCounter iterative methods test not map mode', () => {
961
963
  let treeCounter: TreeCounter<number, string>;
962
964
  beforeEach(() => {
963
965
  treeCounter = new TreeCounter<number, string>([], { isMapMode: false });
964
- treeCounter.add(1, 'a', 10);
965
- treeCounter.add([2, 'b'], undefined, 10);
966
- treeCounter.add([3, 'c'], undefined, 1);
966
+ treeCounter.set(1, 'a', 10);
967
+ treeCounter.set([2, 'b'], undefined, 10);
968
+ treeCounter.set([3, 'c'], undefined, 1);
967
969
  });
968
970
 
969
971
  it('should clone work well', () => {