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.
- package/.github/workflows/ci.yml +9 -0
- package/CHANGELOG.md +1 -1
- package/README.md +14 -3
- package/README_CN.md +119 -275
- package/benchmark/report.html +1 -1
- package/benchmark/report.json +20 -324
- package/dist/cjs/index.cjs +689 -182
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +693 -185
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +689 -182
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +693 -185
- package/dist/esm-legacy/index.mjs.map +1 -1
- package/dist/leetcode/avl-tree-counter.mjs +2957 -0
- package/dist/leetcode/avl-tree-multi-map.mjs +2889 -0
- package/dist/leetcode/avl-tree.mjs +2720 -0
- package/dist/leetcode/binary-tree.mjs +1594 -0
- package/dist/leetcode/bst.mjs +2398 -0
- package/dist/leetcode/deque.mjs +683 -0
- package/dist/leetcode/directed-graph.mjs +1733 -0
- package/dist/leetcode/doubly-linked-list.mjs +709 -0
- package/dist/leetcode/hash-map.mjs +493 -0
- package/dist/leetcode/heap.mjs +542 -0
- package/dist/leetcode/max-heap.mjs +375 -0
- package/dist/leetcode/max-priority-queue.mjs +383 -0
- package/dist/leetcode/min-heap.mjs +363 -0
- package/dist/leetcode/min-priority-queue.mjs +371 -0
- package/dist/leetcode/priority-queue.mjs +363 -0
- package/dist/leetcode/queue.mjs +943 -0
- package/dist/leetcode/red-black-tree.mjs +2765 -0
- package/dist/leetcode/singly-linked-list.mjs +754 -0
- package/dist/leetcode/stack.mjs +217 -0
- package/dist/leetcode/tree-counter.mjs +3039 -0
- package/dist/leetcode/tree-multi-map.mjs +2913 -0
- package/dist/leetcode/trie.mjs +413 -0
- package/dist/leetcode/undirected-graph.mjs +1650 -0
- package/dist/types/data-structures/base/linear-base.d.ts +6 -6
- package/dist/types/data-structures/binary-tree/avl-tree-counter.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +2 -2
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +10 -10
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +25 -27
- package/dist/types/data-structures/binary-tree/bst.d.ts +13 -12
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +151 -21
- package/dist/types/data-structures/binary-tree/tree-counter.d.ts +4 -4
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +2 -2
- package/dist/types/interfaces/binary-tree.d.ts +1 -1
- package/dist/umd/data-structure-typed.js +689 -181
- package/dist/umd/data-structure-typed.js.map +1 -1
- package/dist/umd/data-structure-typed.min.js +3 -3
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +50 -172
- package/src/data-structures/base/linear-base.ts +2 -12
- package/src/data-structures/binary-tree/avl-tree-counter.ts +6 -6
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +13 -13
- package/src/data-structures/binary-tree/avl-tree.ts +15 -15
- package/src/data-structures/binary-tree/binary-tree.ts +57 -60
- package/src/data-structures/binary-tree/bst.ts +100 -26
- package/src/data-structures/binary-tree/red-black-tree.ts +586 -76
- package/src/data-structures/binary-tree/tree-counter.ts +25 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +13 -13
- package/src/data-structures/queue/deque.ts +10 -0
- package/src/interfaces/binary-tree.ts +1 -1
- package/test/performance/data-structures/binary-tree/red-black-tree.test.ts +1 -2
- package/test/unit/data-structures/base/iterable-element-base.coverage.test.ts +106 -0
- package/test/unit/data-structures/base/iterable-element-base.more-branches.coverage.test.ts +61 -0
- package/test/unit/data-structures/base/linear-base.array.coverage.test.ts +168 -0
- package/test/unit/data-structures/base/linear-base.concat-else.coverage.test.ts +82 -0
- package/test/unit/data-structures/base/linear-base.coverage.test.ts +72 -0
- package/test/unit/data-structures/base/linear-base.more-branches.coverage.test.ts +417 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches-3.coverage.test.ts +146 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches.coverage.test.ts +93 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.test.ts +30 -30
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.coverage.test.ts +108 -0
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.more-branches-2.coverage.test.ts +85 -0
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts +46 -46
- package/test/unit/data-structures/binary-tree/avl-tree-node.familyPosition-root-left.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/avl-tree.more-branches-2.coverage.test.ts +99 -0
- package/test/unit/data-structures/binary-tree/avl-tree.test.ts +43 -43
- package/test/unit/data-structures/binary-tree/binary-indexed-tree.more-branches.coverage.test.ts +18 -0
- package/test/unit/data-structures/binary-tree/binary-tree.more-branches.coverage.test.ts +56 -0
- package/test/unit/data-structures/binary-tree/binary-tree.remaining-branches.coverage.test.ts +229 -0
- package/test/unit/data-structures/binary-tree/binary-tree.test.ts +151 -151
- package/test/unit/data-structures/binary-tree/bst.bound-by-predicate.coverage.test.ts +33 -0
- package/test/unit/data-structures/binary-tree/bst.coverage.test.ts +94 -0
- package/test/unit/data-structures/binary-tree/bst.deletebykey.coverage.test.ts +70 -0
- package/test/unit/data-structures/binary-tree/bst.deletewhere.coverage.test.ts +37 -0
- package/test/unit/data-structures/binary-tree/bst.floor-lower-predicate.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/bst.floor-setmany.coverage.test.ts +72 -0
- package/test/unit/data-structures/binary-tree/bst.getnode.range-ensure.coverage.test.ts +22 -0
- package/test/unit/data-structures/binary-tree/bst.misc-branches.coverage.test.ts +100 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-2.coverage.test.ts +133 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-3.coverage.test.ts +45 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-4.coverage.test.ts +36 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-5.coverage.test.ts +40 -0
- package/test/unit/data-structures/binary-tree/bst.more.coverage.test.ts +39 -0
- package/test/unit/data-structures/binary-tree/bst.node-family.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/bst.range-pruning.coverage.test.ts +43 -0
- package/test/unit/data-structures/binary-tree/bst.search-fastpath.coverage.test.ts +30 -0
- package/test/unit/data-structures/binary-tree/bst.test.ts +124 -154
- package/test/unit/data-structures/binary-tree/overall.test.ts +20 -20
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-corruption-repair.coverage.test.ts +66 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-max-update.coverage.test.ts +18 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-null.coverage.test.ts +53 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-stale-cache.coverage.test.ts +25 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-update.coverage.test.ts +23 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-delete.coverage.test.ts +49 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-edge.coverage.test.ts +37 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-stale-insert.coverage.test.ts +39 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.coverage.test.ts +334 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.delete-fixup.coverage.test.ts +68 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.delete-successor.coverage.test.ts +75 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.factories.coverage.test.ts +26 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-compare-update.coverage.test.ts +74 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-no-update.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-nullish.coverage.test.ts +61 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-defined.coverage.test.ts +35 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-undefined.coverage.test.ts +43 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-more.coverage.test.ts +99 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint.coverage.test.ts +60 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.insert-cache-nullish.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.insert-header-parent-nullish.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.internal-walk.coverage.test.ts +57 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.minmax-cache.test.ts +65 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.misc-inputs.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-2.coverage.test.ts +121 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-3.coverage.test.ts +55 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-4.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.predsucc.coverage.test.ts +40 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.remaining-branches.coverage.test.ts +123 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.set-inputs.coverage.test.ts +64 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-parent-cache.coverage.test.ts +79 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-remaining.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-uncovered.coverage.test.ts +74 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.test.ts +141 -141
- package/test/unit/data-structures/binary-tree/red-black-tree.update-branches.coverage.test.ts +30 -0
- package/test/unit/data-structures/binary-tree/segment-tree.more-branches.coverage.test.ts +31 -0
- package/test/unit/data-structures/binary-tree/tree-counter.coverage.test.ts +115 -0
- package/test/unit/data-structures/binary-tree/tree-counter.more-branches.coverage.test.ts +244 -0
- package/test/unit/data-structures/binary-tree/tree-counter.test.ts +41 -39
- package/test/unit/data-structures/binary-tree/tree-multi-map.coverage.test.ts +104 -0
- package/test/unit/data-structures/binary-tree/tree-multi-map.more-branches-2.coverage.test.ts +59 -0
- package/test/unit/data-structures/binary-tree/tree-multi-map.test.ts +145 -145
- package/test/unit/data-structures/graph/abstract-graph.more-branches-2.coverage.test.ts +40 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-3.coverage.test.ts +65 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-4.coverage.test.ts +98 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-5.coverage.test.ts +51 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches.coverage.test.ts +62 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches-2.coverage.test.ts +38 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches-3.coverage.test.ts +25 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches.coverage.test.ts +82 -0
- package/test/unit/data-structures/graph/map-graph.more-branches.coverage.test.ts +22 -0
- package/test/unit/data-structures/graph/undirected-graph.more-branches-2.coverage.test.ts +35 -0
- package/test/unit/data-structures/graph/undirected-graph.more-branches.coverage.test.ts +87 -0
- package/test/unit/data-structures/hash/hash-map.more-branches.coverage.test.ts +64 -0
- package/test/unit/data-structures/hash/hash-map.toEntryFn-branch.coverage.test.ts +9 -0
- package/test/unit/data-structures/heap/heap.misc-branches.coverage.test.ts +110 -0
- package/test/unit/data-structures/heap/heap.remaining-branches.coverage.test.ts +22 -0
- package/test/unit/data-structures/heap/max-heap.coverage.test.ts +29 -0
- package/test/unit/data-structures/linked-list/doubly-linked-list.more-branches.coverage.test.ts +72 -0
- package/test/unit/data-structures/linked-list/linked-list.unshiftMany-else.coverage.test.ts +15 -0
- package/test/unit/data-structures/linked-list/singly-linked-list.coverage.test.ts +221 -0
- package/test/unit/data-structures/linked-list/singly-linked-list.more-branches.coverage.test.ts +86 -0
- package/test/unit/data-structures/linked-list/skip-linked-list.more-branches.coverage.test.ts +31 -0
- package/test/unit/data-structures/matrix/matrix.more-branches.coverage.test.ts +81 -0
- package/test/unit/data-structures/matrix/matrix.pivotElement-nullish.coverage.test.ts +28 -0
- package/test/unit/data-structures/priority-queue/max-priority-queue.more-branches.coverage.test.ts +10 -0
- package/test/unit/data-structures/priority-queue/priority-queue.coverage.test.ts +21 -0
- package/test/unit/data-structures/queue/deque.coverage.test.ts +173 -0
- package/test/unit/data-structures/queue/deque.more-branches-2.coverage.test.ts +39 -0
- package/test/unit/data-structures/queue/deque.more-branches-3.coverage.test.ts +9 -0
- package/test/unit/data-structures/queue/deque.more-branches.coverage.test.ts +95 -0
- package/test/unit/data-structures/queue/queue.coverage.test.ts +138 -0
- package/test/unit/data-structures/queue/queue.more-branches-2.coverage.test.ts +27 -0
- package/test/unit/data-structures/stack/stack.coverage.test.ts +112 -0
- package/test/unit/data-structures/tree/tree.more-branches.coverage.test.ts +9 -0
- package/test/unit/data-structures/trie/trie.more-branches-2.coverage.test.ts +51 -0
- package/test/utils/patch.ts +33 -0
- package/tsup.config.js +50 -21
- package/tsup.umd.config.js +29 -0
- package/tsup.node.config.js +0 -83
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree predecessor/successor coverage', () => {
|
|
4
|
+
it('covers predecessor/successor: subtree-walk, parent-climb, and undefined edges', () => {
|
|
5
|
+
const t = new RedBlackTree<number, string>([], { isMapMode: false });
|
|
6
|
+
|
|
7
|
+
// Build a tree with nodes that have (and do not have) left/right subtrees.
|
|
8
|
+
// 20
|
|
9
|
+
// / \
|
|
10
|
+
// 10 30
|
|
11
|
+
// / \ / \
|
|
12
|
+
// 5 15 25 35
|
|
13
|
+
// /
|
|
14
|
+
// 13
|
|
15
|
+
for (const k of [20, 10, 30, 5, 15, 25, 35, 13]) t.set(k, String(k));
|
|
16
|
+
|
|
17
|
+
const n20 = t.getNode(20)!;
|
|
18
|
+
const n15 = t.getNode(15)!;
|
|
19
|
+
const n5 = t.getNode(5)!;
|
|
20
|
+
const n35 = t.getNode(35)!;
|
|
21
|
+
|
|
22
|
+
// predecessor: has left subtree -> walk to right-most of left.
|
|
23
|
+
expect((t as any)._predecessorOf(n15)?.key).toBe(13);
|
|
24
|
+
|
|
25
|
+
// predecessor: no left subtree -> climb parents.
|
|
26
|
+
expect((t as any)._predecessorOf(n20)?.key).toBe(15);
|
|
27
|
+
|
|
28
|
+
// predecessor of min -> undefined.
|
|
29
|
+
expect((t as any)._predecessorOf(n5)).toBeUndefined();
|
|
30
|
+
|
|
31
|
+
// successor: has right subtree -> walk to left-most of right.
|
|
32
|
+
expect((t as any)._successorOf(n20)?.key).toBe(25);
|
|
33
|
+
|
|
34
|
+
// successor: no right subtree -> climb parents.
|
|
35
|
+
expect((t as any)._successorOf(n15)?.key).toBe(20);
|
|
36
|
+
|
|
37
|
+
// successor of max -> undefined.
|
|
38
|
+
expect((t as any)._successorOf(n35)).toBeUndefined();
|
|
39
|
+
});
|
|
40
|
+
});
|
package/test/unit/data-structures/binary-tree/red-black-tree.remaining-branches.coverage.test.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
class RBTTransplantCorruptRoot extends RedBlackTree<number, number> {
|
|
4
|
+
protected override _transplant(u: any, v: any): void {
|
|
5
|
+
super._transplant(u, v);
|
|
6
|
+
// Corrupt _root only (header.parent remains canonical), so delete() fallback cond-expr
|
|
7
|
+
// `this.isRealNode(this._root) ? ... : undefined` can take the false branch.
|
|
8
|
+
(this as any)._root = this.NIL;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('RedBlackTree remaining-branch coverage', () => {
|
|
13
|
+
it('covers hint cache-maintenance binary-expr false paths (no cache update)', () => {
|
|
14
|
+
// direct attach left: hint.left empty, but extremes exist elsewhere.
|
|
15
|
+
const t1 = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
16
|
+
for (const k of [50, 1, 100, 60]) t1.set(k, k);
|
|
17
|
+
const h60 = t1.getNode(60)!;
|
|
18
|
+
|
|
19
|
+
// Force hint.left to be empty (but keep global min/max as real).
|
|
20
|
+
h60._left = t1.NIL as any;
|
|
21
|
+
|
|
22
|
+
const min1 = (t1 as any)._header._left.key;
|
|
23
|
+
const max1 = (t1 as any)._header._right.key;
|
|
24
|
+
|
|
25
|
+
t1.setWithHintNode(55, 55, h60);
|
|
26
|
+
expect((t1 as any)._header._left.key).toBe(min1);
|
|
27
|
+
expect((t1 as any)._header._right.key).toBe(max1);
|
|
28
|
+
|
|
29
|
+
// direct attach right: hint.right empty.
|
|
30
|
+
const t2 = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
31
|
+
for (const k of [50, 1, 100, 40]) t2.set(k, k);
|
|
32
|
+
const h40 = t2.getNode(40)!;
|
|
33
|
+
|
|
34
|
+
h40._right = t2.NIL as any;
|
|
35
|
+
|
|
36
|
+
const min2 = (t2 as any)._header._left.key;
|
|
37
|
+
const max2 = (t2 as any)._header._right.key;
|
|
38
|
+
|
|
39
|
+
t2.setWithHintNode(45, 45, h40);
|
|
40
|
+
expect((t2 as any)._header._left.key).toBe(min2);
|
|
41
|
+
expect((t2 as any)._header._right.key).toBe(max2);
|
|
42
|
+
|
|
43
|
+
// pred.right attach: force hint.left to be a predecessor whose right slot is empty.
|
|
44
|
+
const t3 = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
45
|
+
for (const k of [50, 1, 100, 60]) t3.set(k, k);
|
|
46
|
+
const h60b = t3.getNode(60)!;
|
|
47
|
+
const pred40 = t3.getNode(50)!; // reuse an existing real node as predecessor anchor
|
|
48
|
+
|
|
49
|
+
pred40.parent = h60b as any;
|
|
50
|
+
pred40._right = t3.NIL as any;
|
|
51
|
+
h60b._left = pred40 as any;
|
|
52
|
+
|
|
53
|
+
const min3 = (t3 as any)._header._left.key;
|
|
54
|
+
const max3 = (t3 as any)._header._right.key;
|
|
55
|
+
|
|
56
|
+
t3.setWithHintNode(55, 55, h60b);
|
|
57
|
+
expect((t3 as any)._header._left.key).toBe(min3);
|
|
58
|
+
expect((t3 as any)._header._right.key).toBe(max3);
|
|
59
|
+
|
|
60
|
+
// succ.left attach: force hint.right to be a successor whose left slot is empty.
|
|
61
|
+
const t4 = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
62
|
+
for (const k of [50, 1, 100, 40]) t4.set(k, k);
|
|
63
|
+
const h40b = t4.getNode(40)!;
|
|
64
|
+
const succ60 = t4.getNode(50)!; // reuse an existing real node as successor anchor
|
|
65
|
+
|
|
66
|
+
succ60.parent = h40b as any;
|
|
67
|
+
succ60._left = t4.NIL as any;
|
|
68
|
+
h40b._right = succ60 as any;
|
|
69
|
+
|
|
70
|
+
const min4 = (t4 as any)._header._left.key;
|
|
71
|
+
const max4 = (t4 as any)._header._right.key;
|
|
72
|
+
|
|
73
|
+
t4.setWithHintNode(45, 45, h40b);
|
|
74
|
+
expect((t4 as any)._header._left.key).toBe(min4);
|
|
75
|
+
expect((t4 as any)._header._right.key).toBe(max4);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('covers _setKVNode boundary max update mapMode branches (defined + undefined)', () => {
|
|
79
|
+
const t = new RedBlackTree<number, string>(); // mapMode default
|
|
80
|
+
t.set(10, 'mid');
|
|
81
|
+
t.set(5, 'min');
|
|
82
|
+
t.set(15, 'max');
|
|
83
|
+
|
|
84
|
+
// defined: should store.set
|
|
85
|
+
t.set(15, 'max2');
|
|
86
|
+
expect(t.get(15)).toBe('max2');
|
|
87
|
+
|
|
88
|
+
// undefined: should go through _setValue branch, preserving existing value
|
|
89
|
+
t.set(15, undefined as any);
|
|
90
|
+
expect(t.get(15)).toBe('max2');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('covers delete(predicate) path and delete(node) ternary branch', () => {
|
|
94
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
95
|
+
for (const k of [10, 5, 15]) t.set(k, k);
|
|
96
|
+
|
|
97
|
+
// delete(predicate)
|
|
98
|
+
const r1 = t.delete((node) => node?.key === 5);
|
|
99
|
+
expect(r1.length).toBe(1);
|
|
100
|
+
expect(t.has(5)).toBe(false);
|
|
101
|
+
|
|
102
|
+
// delete(node)
|
|
103
|
+
const n15 = t.getNode(15)!;
|
|
104
|
+
const r2 = t.delete(n15);
|
|
105
|
+
expect(r2.length).toBe(1);
|
|
106
|
+
expect(t.has(15)).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('covers delete cache fallback cond-expr false branch when _root is corrupted to NIL', () => {
|
|
110
|
+
const t = new RBTTransplantCorruptRoot([], { isMapMode: false });
|
|
111
|
+
for (const k of [10, 5, 15, 1, 20]) t.set(k, k);
|
|
112
|
+
|
|
113
|
+
// Force fallback recompute block by corrupting min/max nodes.
|
|
114
|
+
(t as any)._minNode = undefined;
|
|
115
|
+
(t as any)._maxNode = undefined;
|
|
116
|
+
|
|
117
|
+
// Delete a node so size remains >0.
|
|
118
|
+
t.delete(1);
|
|
119
|
+
|
|
120
|
+
// Restore root so subsequent operations/tests aren't affected.
|
|
121
|
+
(t as any)._root = (t as any)._header.parent;
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { RedBlackTree, RedBlackTreeNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
class RBTWithBadInsert extends RedBlackTree<number, number> {
|
|
4
|
+
// Simulate an internal failure where _insert reports CREATED but does not establish a real root.
|
|
5
|
+
// This is purely to cover the defensive branch in set(node).
|
|
6
|
+
protected override _insert(_node: RedBlackTreeNode<number, number>): any {
|
|
7
|
+
// Ensure root stays NIL/undefined
|
|
8
|
+
(this as any)._setRoot(undefined);
|
|
9
|
+
return 'CREATED';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('RedBlackTree set() input/defensive branches coverage', () => {
|
|
14
|
+
it('returns false for nullish key inputs in key/entry paths', () => {
|
|
15
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
16
|
+
|
|
17
|
+
expect(t.set(null as any)).toBe(false);
|
|
18
|
+
expect(t.set(undefined as any)).toBe(false);
|
|
19
|
+
|
|
20
|
+
// entry with null/undefined key
|
|
21
|
+
expect(t.set([null as any, 1] as any)).toBe(false);
|
|
22
|
+
expect(t.set([undefined as any, 1] as any)).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('key-only path delegates to _setKV and supports mapMode fast path', () => {
|
|
26
|
+
const t = new RedBlackTree<number, number>(); // mapMode default
|
|
27
|
+
|
|
28
|
+
// insert
|
|
29
|
+
expect(t.set(1, 10)).toBe(true);
|
|
30
|
+
expect(t.get(1)).toBe(10);
|
|
31
|
+
|
|
32
|
+
// update should hit _setKV fast-path (store.has)
|
|
33
|
+
expect(t.set(1, 20)).toBe(true);
|
|
34
|
+
expect(t.get(1)).toBe(20);
|
|
35
|
+
|
|
36
|
+
// update for missing key must fall through to _setKVNode
|
|
37
|
+
expect(t.set(2, 200)).toBe(true);
|
|
38
|
+
expect(t.get(2)).toBe(200);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('node insertion path: defensive branch returns false when root is not real after CREATED', () => {
|
|
42
|
+
const t = new RBTWithBadInsert([], { isMapMode: false });
|
|
43
|
+
const n = new RedBlackTreeNode<number, number>(1, 1, 'BLACK');
|
|
44
|
+
|
|
45
|
+
expect(t.set(n)).toBe(false);
|
|
46
|
+
expect(t.size).toBe(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('node insertion path: UPDATED branch returns true and updates mapMode store via _setValue', () => {
|
|
50
|
+
const t = new RedBlackTree<number, number>();
|
|
51
|
+
|
|
52
|
+
// First insert via node
|
|
53
|
+
const n1 = new RedBlackTreeNode<number, number>(1, 0 as any, 'BLACK');
|
|
54
|
+
expect(t.set(n1, 10)).toBe(true);
|
|
55
|
+
expect(t.get(1)).toBe(10);
|
|
56
|
+
|
|
57
|
+
// Second node with same key should trigger UPDATED in _insert -> set() UPDATED branch.
|
|
58
|
+
const n1b = new RedBlackTreeNode<number, number>(1, 0 as any, 'BLACK');
|
|
59
|
+
expect(t.set(n1b, 99)).toBe(true);
|
|
60
|
+
|
|
61
|
+
// mapMode uses _setValue, so value should reflect newValue.
|
|
62
|
+
expect(t.get(1)).toBe(99);
|
|
63
|
+
});
|
|
64
|
+
});
|
package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-parent-cache.coverage.test.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { RedBlackTree, RedBlackTreeNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
class RBTBadKeyValue extends RedBlackTree<number, number> {
|
|
4
|
+
// Force set(node) to hit `if (!this.isRealNode(newNode)) return false;`
|
|
5
|
+
protected override _keyValueNodeOrEntryToNodeAndValue(
|
|
6
|
+
_keyNodeOrEntry: any,
|
|
7
|
+
_value?: any
|
|
8
|
+
): [RedBlackTreeNode<number, number> | undefined, number | undefined] {
|
|
9
|
+
return [undefined, undefined];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe('RedBlackTree _setKVNode parent==hMin/hMax cache maintenance coverage', () => {
|
|
14
|
+
it('post-insert cache maintenance: parent===hMax && lastCompared>0 updates max cache when header._right is corrupted to an interior node', () => {
|
|
15
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
16
|
+
for (const k of [10, 5, 15, 1, 20]) t.set(k, k);
|
|
17
|
+
|
|
18
|
+
const n10 = t.getNode(10)!;
|
|
19
|
+
|
|
20
|
+
// Corrupt header max cache to an interior node that already has a right subtree,
|
|
21
|
+
// so boundary max attach fast-path is skipped.
|
|
22
|
+
(t as any)._header._right = n10;
|
|
23
|
+
|
|
24
|
+
// Insert a key that will attach as the right child of 10 in the normal path.
|
|
25
|
+
// (10.right exists (15), so it will descend; but 13 will attach as left of 15, not 10.
|
|
26
|
+
// So ensure 10.right is empty for parent===hMax; but that would re-enable boundary.
|
|
27
|
+
// Instead, force shape: make 10.right NIL temporarily (only for this coverage test).
|
|
28
|
+
n10._right = t.NIL as any;
|
|
29
|
+
|
|
30
|
+
// With corrupted hMax=10 and 10.right NIL, boundary block would try to attach as right of maxN;
|
|
31
|
+
// but boundary block only runs when cMin>0 with minN=header._left. Keep minN such that cMin<=0 by corrupting min to a larger key.
|
|
32
|
+
(t as any)._header._left = n10;
|
|
33
|
+
|
|
34
|
+
t.set(12, 12);
|
|
35
|
+
|
|
36
|
+
// Should have updated max cache to the newly inserted node via parent===hMax branch.
|
|
37
|
+
expect((t as any)._header._right.key).toBe(12);
|
|
38
|
+
|
|
39
|
+
// Repair caches (best-effort).
|
|
40
|
+
const root = (t as any)._header.parent;
|
|
41
|
+
(t as any)._root = root;
|
|
42
|
+
(t as any)._setMinCache(t.getLeftMost((x: any) => x, root));
|
|
43
|
+
(t as any)._setMaxCache(t.getRightMost((x: any) => x, root));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('post-insert cache maintenance: parent===hMin && lastCompared<0 updates min cache when header._left is corrupted to an interior node', () => {
|
|
47
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
48
|
+
for (const k of [10, 5, 15, 1, 20]) t.set(k, k);
|
|
49
|
+
|
|
50
|
+
const n10 = t.getNode(10)!;
|
|
51
|
+
|
|
52
|
+
// Corrupt header min cache to an interior node.
|
|
53
|
+
(t as any)._header._left = n10;
|
|
54
|
+
// Ensure boundary min attach is skipped: 10.left is real by default (5), so ok.
|
|
55
|
+
|
|
56
|
+
// Insert a key that will attach as the left child of 10 (normal path):
|
|
57
|
+
// force 10.left to be NIL temporarily to make parent===10.
|
|
58
|
+
n10._left = t.NIL as any;
|
|
59
|
+
|
|
60
|
+
// Also corrupt max so we don't enter max boundary block.
|
|
61
|
+
(t as any)._header._right = n10;
|
|
62
|
+
|
|
63
|
+
t.set(7, 7);
|
|
64
|
+
|
|
65
|
+
expect((t as any)._header._left.key).toBe(7);
|
|
66
|
+
|
|
67
|
+
// Repair caches.
|
|
68
|
+
const root = (t as any)._header.parent;
|
|
69
|
+
(t as any)._root = root;
|
|
70
|
+
(t as any)._setMinCache(t.getLeftMost((x: any) => x, root));
|
|
71
|
+
(t as any)._setMaxCache(t.getRightMost((x: any) => x, root));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('set(node) early-return branch: _keyValueNodeOrEntryToNodeAndValue returns undefined node', () => {
|
|
75
|
+
const t = new RBTBadKeyValue([], { isMapMode: false });
|
|
76
|
+
const n = new RedBlackTreeNode<number, number>(1, 1, 'BLACK');
|
|
77
|
+
expect(t.set(n, 1)).toBe(false);
|
|
78
|
+
});
|
|
79
|
+
});
|
package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-remaining.coverage.test.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('RedBlackTree _setKVNode remaining branch coverage', () => {
|
|
4
|
+
it('normal search loop takes `current.right ?? NIL` with a real right child (covers binary-expr branch)', () => {
|
|
5
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
6
|
+
// Build a tree where root has a real right child.
|
|
7
|
+
t.set(10, 10);
|
|
8
|
+
t.set(15, 15);
|
|
9
|
+
t.set(20, 20);
|
|
10
|
+
|
|
11
|
+
// Skip boundary fast paths so we go through the normal search loop.
|
|
12
|
+
(t as any)._header._left = undefined;
|
|
13
|
+
|
|
14
|
+
// Insert a key greater than root so traversal takes the right-child branch with a real node.
|
|
15
|
+
expect(t.set(25, 25)).toBe(true);
|
|
16
|
+
expect(t.has(25)).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('normal update path (mapMode) hits `_setValue` when nextValue is undefined (covers if/else at update)', () => {
|
|
20
|
+
const t = new RedBlackTree<number, string>(); // mapMode default
|
|
21
|
+
t.set(10, 'a');
|
|
22
|
+
t.set(5, 'b');
|
|
23
|
+
t.set(15, 'c');
|
|
24
|
+
|
|
25
|
+
// Ensure we do NOT take boundary min/max update fast paths.
|
|
26
|
+
(t as any)._header._left = undefined;
|
|
27
|
+
(t as any)._header._right = undefined;
|
|
28
|
+
|
|
29
|
+
// Update an existing key with undefined => mapMode uses _setValue branch and preserves existing value.
|
|
30
|
+
t.set(10, undefined as any);
|
|
31
|
+
expect(t.get(10)).toBe('a');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('boundary max-key update (mapMode) hits `_setValue` branch when nextValue is undefined', () => {
|
|
35
|
+
const t = new RedBlackTree<number, string>(); // mapMode default
|
|
36
|
+
t.set(10, 'mid');
|
|
37
|
+
t.set(5, 'min');
|
|
38
|
+
t.set(15, 'max');
|
|
39
|
+
|
|
40
|
+
// Update existing max key with undefined should take boundary cMax===0 fast-path and go through _setValue.
|
|
41
|
+
t.set(15, undefined as any);
|
|
42
|
+
expect(t.get(15)).toBe('max');
|
|
43
|
+
});
|
|
44
|
+
});
|
package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-uncovered.coverage.test.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { RedBlackTree } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
class RBTBadFixup extends RedBlackTree<number, number> {
|
|
4
|
+
// Simulate an unexpected internal failure so `_setKVNode` hits the defensive `else return undefined`.
|
|
5
|
+
protected override _insertFixup(_node: any): void {
|
|
6
|
+
// Blow away root after "fixup".
|
|
7
|
+
(this as any)._setRoot(undefined);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('RedBlackTree _setKVNode uncovered-branch coverage', () => {
|
|
12
|
+
it('covers normal-path current=header.parent ?? NIL when header.parent is undefined (starts at NIL)', () => {
|
|
13
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
14
|
+
|
|
15
|
+
// Force normal path (minN becomes NIL via ??) and start walk from NIL.
|
|
16
|
+
(t as any)._header._left = undefined;
|
|
17
|
+
(t as any)._header.parent = undefined;
|
|
18
|
+
|
|
19
|
+
expect(t.set(1, 1)).toBe(true);
|
|
20
|
+
expect(t.getNode(1)?.key).toBe(1);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('covers normal-path `current.left ?? NIL` / `current.right ?? NIL` in the search loop', () => {
|
|
24
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false });
|
|
25
|
+
t.set(10, 10);
|
|
26
|
+
|
|
27
|
+
// Skip boundary fast paths so we go through the normal search loop.
|
|
28
|
+
(t as any)._header._left = undefined;
|
|
29
|
+
|
|
30
|
+
// Force missing children so `?? NIL` branches are taken.
|
|
31
|
+
const root = (t as any)._header.parent;
|
|
32
|
+
root._left = undefined;
|
|
33
|
+
root._right = undefined;
|
|
34
|
+
|
|
35
|
+
expect(t.set(5, 5)).toBe(true);
|
|
36
|
+
expect(t.set(15, 15)).toBe(true);
|
|
37
|
+
|
|
38
|
+
expect(t.has(5)).toBe(true);
|
|
39
|
+
expect(t.has(15)).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('covers boundary max-path reading `header._right ?? NIL` when header._right is undefined (safe comparator)', () => {
|
|
43
|
+
// Comparator that tolerates undefined keys from NIL.
|
|
44
|
+
const comparator = (a: number, b: any) => {
|
|
45
|
+
if (b === undefined || b === null) return -1; // ensures cMax < 0 so we do not attach/update under NIL
|
|
46
|
+
return a - b;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const t = new RedBlackTree<number, number>([], { isMapMode: false, comparator });
|
|
50
|
+
t.set(10, 10);
|
|
51
|
+
t.set(5, 5); // establish min
|
|
52
|
+
|
|
53
|
+
// Corrupt max cache only; boundary block should read `header._right ?? NIL`.
|
|
54
|
+
(t as any)._header._right = undefined;
|
|
55
|
+
|
|
56
|
+
// Key > min so we enter the max boundary block, but safe comparator prevents NIL-attach.
|
|
57
|
+
expect(t.set(8, 8)).toBe(true);
|
|
58
|
+
expect(t.has(8)).toBe(true);
|
|
59
|
+
|
|
60
|
+
// Repair max cache so we don't leak corruption.
|
|
61
|
+
const root = (t as any)._root;
|
|
62
|
+
(t as any)._setMaxCache(t.isRealNode(root) ? t.getRightMost((n: any) => n, root) : undefined);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('covers defensive `return undefined` after fixup when root is not real (set returns false)', () => {
|
|
66
|
+
const t = new RBTBadFixup([], { isMapMode: false });
|
|
67
|
+
|
|
68
|
+
// Force normal path (avoid boundary attach) so we reach the fixup block.
|
|
69
|
+
(t as any)._header._left = undefined;
|
|
70
|
+
|
|
71
|
+
expect(t.set(1, 1)).toBe(false);
|
|
72
|
+
expect(t.size).toBe(0);
|
|
73
|
+
});
|
|
74
|
+
});
|