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
|
@@ -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.
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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(
|
|
291
|
-
else nodeToDelete = this.isRealNode(
|
|
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.
|
|
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.
|
|
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
|
|
388
|
+
override set(
|
|
389
389
|
keyNodeOrEntry: K | TreeMultiMapNode<K, V> | [K | null | undefined, V[] | undefined] | null | undefined
|
|
390
390
|
): boolean;
|
|
391
391
|
|
|
392
|
-
override
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
434
|
+
return super.set(key, values);
|
|
435
435
|
}
|
|
436
436
|
};
|
|
437
437
|
|
|
438
438
|
if (this._isMapMode) {
|
|
439
|
-
return
|
|
439
|
+
return _setByNode() || _setToValues();
|
|
440
440
|
}
|
|
441
|
-
return
|
|
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.
|
|
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:
|
|
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.
|
|
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
|
+
});
|