Skip to content

Commit 5a221a4

Browse files
committed
fix:#128,unify callback parameter order to (value, key) across all collections
Standardize the callback signatures for forEach, find, some, map, reduce, and filter methods to align with ES6 Map/Array standards. - Changed parameter order from (key, value) to (value, key) - Updated RedBlackTree, HashMap, and LinkedStack implementations - Refactored internal library calls to prevent regressions - Updated unit tests to reflect the new API signature This is a breaking change to ensure API consistency and predictability.
1 parent b4cb346 commit 5a221a4

27 files changed

+180
-631
lines changed

README.md

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -798,11 +798,8 @@ Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key) // ['A', 'B', '
798798

799799
```
800800

801-
[//]: # (No deletion!!! Start of Example Replace Section)
802801

803802

804-
[//]: # (No deletion!!! End of Example Replace Section)
805-
806803
## API docs & Examples
807804

808805
[API Docs](https://data-structure-typed-docs.vercel.app)
@@ -823,29 +820,16 @@ Graphics Radeon Pro 555X 4 GB
823820

824821
Intel UHD Graphics 630 1536 MB
825822

826-
macOS Big Sur
823+
macOS Sequoia 15.7.2
827824

828-
Version 11.7.9
825+
## Performance & Runtime Compatibility
829826

830-
***Our performance testing is conducted directly on the TypeScript source code. The actual performance of the compiled JavaScript code is generally 3 times higher. We have compared it with C++, and it is only 30% slower than C++.***
831-
Try it
827+
[//]: # (No deletion!!! Start of Replace Section)
832828

833-
Just run
829+
<h2>red-black-tree</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>1,000,000 add</td><td>410.34</td><td>0.41</td><td>0.01</td></tr><tr><td>1,000,000 get</td><td>5.20</td><td>0.01</td><td>8.16e-5</td></tr><tr><td>1,000,000 iterator</td><td>154.25</td><td>0.15</td><td>0.02</td></tr><tr><td>CPT 1,000,000 add</td><td>656.43</td><td>0.66</td><td>0.00</td></tr><tr><td>CPT 1,000,000 add</td><td>684.17</td><td>0.68</td><td>0.01</td></tr></tbody></table><h2>queue</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>1,000,000 push</td><td>26.97</td><td>0.03</td><td>0.00</td></tr><tr><td>100,000 push & shift</td><td>2.87</td><td>0.00</td><td>2.71e-4</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>1120.94</td><td>1.12</td><td>0.20</td></tr></tbody></table><h2>deque</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>1,000,000 push</td><td>8.75</td><td>0.01</td><td>6.99e-4</td></tr><tr><td>1,000,000 push & pop</td><td>12.95</td><td>0.01</td><td>4.21e-4</td></tr><tr><td>1,000,000 push & shift</td><td>13.73</td><td>0.01</td><td>4.53e-4</td></tr><tr><td>100,000 push & shift</td><td>1.36</td><td>0.00</td><td>5.42e-5</td></tr><tr><td>Native JS Array 100,000 push & shift</td><td>1167.06</td><td>1.17</td><td>0.26</td></tr><tr><td>100,000 unshift & shift</td><td>1.31</td><td>0.00</td><td>4.73e-5</td></tr><tr><td>Native JS Array 100,000 unshift & shift</td><td>1911.47</td><td>1.91</td><td>0.02</td></tr></tbody></table><h2>heap</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>100,000 add</td><td>4.60</td><td>0.00</td><td>1.07e-4</td></tr><tr><td>100,000 add & poll</td><td>16.96</td><td>0.02</td><td>3.45e-4</td></tr></tbody></table><h2>avl-tree</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>100,000 add randomly</td><td>324.51</td><td>0.32</td><td>0.01</td></tr><tr><td>100,000 add</td><td>299.76</td><td>0.30</td><td>0.02</td></tr><tr><td>100,000 get</td><td>0.26</td><td>2.58e-4</td><td>3.65e-6</td></tr><tr><td>100,000 getNode</td><td>169.33</td><td>0.17</td><td>0.00</td></tr><tr><td>100,000 iterator</td><td>14.43</td><td>0.01</td><td>0.00</td></tr><tr><td>100,000 add & delete orderly</td><td>434.44</td><td>0.43</td><td>0.01</td></tr><tr><td>100,000 add & delete randomly</td><td>541.78</td><td>0.54</td><td>0.01</td></tr></tbody></table><h2>hash-map</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>1,000,000 set</td><td>43.23</td><td>0.04</td><td>0.01</td></tr><tr><td>Native JS Map 1,000,000 set</td><td>147.12</td><td>0.15</td><td>0.01</td></tr><tr><td>Native JS Set 1,000,000 add</td><td>116.18</td><td>0.12</td><td>0.01</td></tr><tr><td>1,000,000 set & get</td><td>46.39</td><td>0.05</td><td>0.01</td></tr><tr><td>Native JS Map 1,000,000 set & get</td><td>196.92</td><td>0.20</td><td>0.01</td></tr><tr><td>Native JS Set 1,000,000 add & has</td><td>163.92</td><td>0.16</td><td>0.01</td></tr><tr><td>1,000,000 ObjKey set & get</td><td>243.36</td><td>0.24</td><td>0.03</td></tr><tr><td>Native JS Map 1,000,000 ObjKey set & get</td><td>211.66</td><td>0.21</td><td>0.02</td></tr><tr><td>Native JS Set 1,000,000 ObjKey add & has</td><td>196.57</td><td>0.20</td><td>0.01</td></tr></tbody></table><h2>directed-graph</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>1,000 addVertex</td><td>0.05</td><td>4.60e-5</td><td>6.59e-7</td></tr><tr><td>1,000 addEdge</td><td>3.02</td><td>0.00</td><td>2.85e-4</td></tr><tr><td>1,000 getVertex</td><td>0.04</td><td>3.77e-5</td><td>4.66e-7</td></tr><tr><td>1,000 getEdge</td><td>41.48</td><td>0.04</td><td>0.01</td></tr><tr><td>tarjan</td><td>240.33</td><td>0.24</td><td>0.01</td></tr><tr><td>topologicalSort</td><td>195.62</td><td>0.20</td><td>0.01</td></tr></tbody></table><h2>trie</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>100,000 push</td><td>27.15</td><td>0.03</td><td>6.61e-4</td></tr><tr><td>100,000 getWords</td><td>41.18</td><td>0.04</td><td>0.00</td></tr></tbody></table><h2>stack</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>1,000,000 push</td><td>25.21</td><td>0.03</td><td>0.00</td></tr><tr><td>1,000,000 push & pop</td><td>29.12</td><td>0.03</td><td>0.00</td></tr></tbody></table>
834830

835-
```shell
836-
pnpm perf:rbtree
837-
```
838-
839-
```html
840-
1,000,000 add randomly: 1.367s
841-
1,000,000 add: 374.859ms
842-
1,000,000 get: 8.025ms
843-
1,000,000 getNode: 1.293s
844-
```
831+
[//]: # (No deletion!!! End of Replace Section)
845832

846-
[//]: # (No deletion!!! Start of Replace Section)
847-
<h2>comparison</h2><table><thead><tr><th>test name</th><th>time taken (ms)</th><th>sample mean (secs)</th><th>sample deviation</th></tr></thead><tbody><tr><td>SRC PQ 1,000,000 add</td><td>36.30</td><td>0.04</td><td>0.01</td></tr><tr><td>CJS PQ 100,000 add</td><td>2.76</td><td>0.00</td><td>1.11e-4</td></tr><tr><td>MJS PQ 100,000 add</td><td>14.33</td><td>0.01</td><td>2.60e-4</td></tr><tr><td>CPT PQ 100,000 add</td><td>4.81</td><td>0.00</td><td>1.36e-4</td></tr><tr><td>SRC PQ 100,000 add & poll</td><td>22.57</td><td>0.02</td><td>4.66e-4</td></tr><tr><td>CJS PQ 100,000 add & poll</td><td>22.84</td><td>0.02</td><td>6.65e-4</td></tr><tr><td>MJS PQ 100,000 add & poll</td><td>23.43</td><td>0.02</td><td>0.00</td></tr><tr><td>CPT PQ 1,000,000 add & pop</td><td>181.14</td><td>0.18</td><td>0.03</td></tr><tr><td>CPT OM 100,000 add</td><td>26.64</td><td>0.03</td><td>0.00</td></tr><tr><td>CPT HM 100,000 set</td><td>5.90</td><td>0.01</td><td>8.46e-4</td></tr><tr><td>CPT HM 100,000 set & get</td><td>
848-
6.69</td><td>0.01</td><td>7.52e-4</td></tr><tr><td>CPT LL 1,000,000 unshift</td><td>19.78</td><td>0.02</td><td>0.01</td></tr><tr><td>CPT PQ 100,000 add & pop</td><td>14.36</td><td>0.01</td><td>0.00</td></tr><tr><td>CPT DQ 1,000,000 push</td><td>8.11</td><td>0.01</td><td>5.23e-4</td></tr><tr><td>CPT Q 1,000,000 push</td><td>30.25</td><td>0.03</td><td>0.01</td></tr><tr><td>CPT ST 1,000,000 push</td><td>27.10</td><td>0.03</td><td>0.00</td></tr><tr><td>CPT ST 1,000,000 push & pop</td><td>30.19</td><td>0.03</td><td>0.00</td></tr></tbody></table>[//]: # (No deletion!!! End of Replace Section)
849833

850834
## The corresponding relationships between data structures in different language standard libraries.
851835

@@ -1107,6 +1091,67 @@ pnpm perf:rbtree
11071091
</tbody>
11081092
</table>
11091093

1094+
Starting from v2.2.0, `data-structure-typed` ships **two runtime targets** to balance
1095+
maximum performance on modern engines with broad compatibility for older Node.js
1096+
and browsers.
1097+
1098+
### Build Targets
1099+
1100+
| Target | Output | Recommended runtime | Minimum runtime | Notes |
1101+
|---|---|---:|---:|---|
1102+
| **Modern (ES2022)** | `dist/esm` / `dist/cjs` | **Node.js 18+** | Node.js 16+ | Best performance. Enables V8 to fully optimize hot paths (JIT-friendly class semantics). |
1103+
| **Legacy (ES2018)** | `dist/esm-legacy` / `dist/cjs-legacy` | Node.js 16+ | **Node.js 12+** | Maximum compatibility. Slightly slower due to older compilation target and reduced JIT opportunities. |
1104+
1105+
### Benchmarks (Insertion-heavy workloads)
1106+
1107+
The modern build (ES2022) is significantly faster for insertion-heavy operations
1108+
(e.g. Red-Black Tree `add/insert`) because it avoids performance overhead from
1109+
transpiled class field initialization and improves JIT optimization.
1110+
1111+
| Benchmark | Legacy (ES2018) | Modern (ES2022) | Speedup |
1112+
|---|---:|---:|---:|
1113+
| Red-Black Tree `add` (1,000,000 inserts) | **~1100 ms** *(example)* | **473.12 ms** | **~2.3×** |
1114+
1115+
> Notes:
1116+
> - Results vary by hardware and Node version.
1117+
> - We recommend running benchmarks on **Node.js 18+** for stable, modern V8 behavior.
1118+
1119+
### Node.js Support Policy
1120+
1121+
- **Supported:** Node.js **12+** (via the legacy build)
1122+
- **Recommended:** Node.js **18+** (modern build, best performance and stability)
1123+
- **Best experience:** Node.js **20+** (latest V8 improvements)
1124+
1125+
If you target Node.js 18+ only, you will get the best performance out of the box.
1126+
1127+
### Browser Support
1128+
1129+
- **Modern browsers (Evergreen):** use the **Modern (ES2022)** ESM build.
1130+
- **Older browsers / conservative bundlers:** use the **Legacy (ES2018)** ESM build.
1131+
1132+
In most bundler setups, the correct build is resolved automatically via `exports`.
1133+
If you need to force a specific target, use the explicit entry points:
1134+
1135+
```js
1136+
// Force modern build (ES2022)
1137+
import { RedBlackTree } from "data-structure-typed/modern";
1138+
1139+
// Force legacy build (ES2018)
1140+
import { RedBlackTree } from "data-structure-typed/legacy";
1141+
```
1142+
1143+
Just run
1144+
1145+
```shell
1146+
pnpm test:perf red-black-tree.test.ts
1147+
```
1148+
1149+
```html
1150+
1,000,000 add randomly: 1.141s
1151+
1,000,000 add: 374.859ms
1152+
1,000,000 get: 5.99ms
1153+
```
1154+
11101155
## Software Engineering Design Standards
11111156

11121157
We strictly adhere to computer science theory and software development standards. Our LinkedList is designed in the

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "data-structure-typed",
3-
"version": "2.2.0",
3+
"version": "2.2.1",
44
"description": "Standard data structure",
55
"browser": "dist/umd/data-structure-typed.min.js",
66
"umd:main": "dist/umd/data-structure-typed.min.js",

src/data-structures/base/iterable-entry-base.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export abstract class IterableEntryBase<K = any, V = any> {
6666
every(predicate: EntryCallback<K, V, boolean>, thisArg?: any): boolean {
6767
let index = 0;
6868
for (const item of this) {
69-
if (!predicate.call(thisArg, item[0], item[1], index++, this)) {
69+
if (!predicate.call(thisArg, item[1], item[0], index++, this)) {
7070
return false;
7171
}
7272
}
@@ -83,7 +83,7 @@ export abstract class IterableEntryBase<K = any, V = any> {
8383
some(predicate: EntryCallback<K, V, boolean>, thisArg?: any): boolean {
8484
let index = 0;
8585
for (const item of this) {
86-
if (predicate.call(thisArg, item[0], item[1], index++, this)) {
86+
if (predicate.call(thisArg, item[1], item[0], index++, this)) {
8787
return true;
8888
}
8989
}
@@ -100,7 +100,7 @@ export abstract class IterableEntryBase<K = any, V = any> {
100100
let index = 0;
101101
for (const item of this) {
102102
const [key, value] = item;
103-
callbackfn.call(thisArg, key, value, index++, this);
103+
callbackfn.call(thisArg, value, key, index++, this);
104104
}
105105
}
106106

@@ -115,7 +115,7 @@ export abstract class IterableEntryBase<K = any, V = any> {
115115
let index = 0;
116116
for (const item of this) {
117117
const [key, value] = item;
118-
if (callbackfn.call(thisArg, key, value, index++, this)) return item;
118+
if (callbackfn.call(thisArg, value, key, index++, this)) return item;
119119
}
120120
return;
121121
}

src/data-structures/binary-tree/avl-tree-counter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ export class AVLTreeCounter<K = any, V = any, R = any> extends AVLTree<K, V, R>
411411

412412
let index = 0;
413413
for (const [key, value] of this) {
414-
out.add(callback.call(thisArg, key, value, index++, this));
414+
out.add(callback.call(thisArg, value, key, index++, this));
415415
}
416416
return out;
417417
}

src/data-structures/binary-tree/avl-tree-multi-map.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ export class AVLTreeMultiMap<K = any, V = any, R = any> extends AVLTree<K, V[],
393393
): AVLTree<MK, MV, MR> {
394394
const out = this._createLike<MK, MV, MR>([], options);
395395
let i = 0;
396-
for (const [k, v] of this) out.add(callback.call(thisArg, k, v, i++, this));
396+
for (const [k, v] of this) out.add(callback.call(thisArg, v, k, i++, this));
397397
return out;
398398
}
399399

src/data-structures/binary-tree/avl-tree.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ export class AVLTreeNode<K = any, V = any> {
195195
* 4. Order Preservation: Maintains the binary search tree property where left child values are less than the parent, and right child values are greater.
196196
* 5. Efficient Lookups: Offers O(log n) search time, where 'n' is the number of nodes, due to its balanced nature.
197197
* 6. Complex Insertions and Deletions: Due to rebalancing, these operations are more complex than in a regular BST.
198-
* 7. Path Length: The path length from the root to any leaf is longer compared to an unbalanced BST, but shorter than a linear chain of nodes.@example
198+
* 7. Path Length: The path length from the root to any leaf is longer compared to an unbalanced BST, but shorter than a linear chain of nodes.
199+
*
200+
* @example
199201
* // Find elements in a range
200202
* // In interval queries, AVL trees, with their strictly balanced structure and lower height, offer better query efficiency, making them ideal for frequent and high-performance interval queries. In contrast, Red-Black trees, with lower update costs, are more suitable for scenarios involving frequent insertions and deletions where the requirements for interval queries are less demanding.
201203
* type Datum = { timestamp: Date; temperature: number };
@@ -403,7 +405,7 @@ export class AVLTree<K = any, V = any, R = any> extends BST<K, V, R> implements
403405
// Iterates in-order
404406
for (const [key, value] of this) {
405407
// `add` on the new tree will be O(log N) and will self-balance.
406-
out.add(callback.call(thisArg, key, value, index++, this));
408+
out.add(callback.call(thisArg, value, key, index++, this));
407409
}
408410
return out;
409411
}

src/data-structures/binary-tree/binary-tree.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ export class BinaryTreeNode<K = any, V = any> {
203203
* 3. Depth and Height: Depth is the number of edges from the root to a node; height is the maximum depth in the tree.
204204
* 4. Subtrees: Each child of a node forms the root of a subtree.
205205
* 5. Leaf Nodes: Nodes without children are leaves.
206+
*
206207
* @example
207208
* // determine loan approval using a decision tree
208209
* // Decision tree structure
@@ -1673,7 +1674,7 @@ export class BinaryTree<K = any, V = any, R = any>
16731674
filter(predicate: EntryCallback<K, V | undefined, boolean>, thisArg?: unknown): this {
16741675
const out = this._createInstance<K, V, R>();
16751676
let i = 0;
1676-
for (const [k, v] of this) if (predicate.call(thisArg, k, v, i++, this)) out.add([k, v]);
1677+
for (const [k, v] of this) if (predicate.call(thisArg, v, k, i++, this)) out.add([k, v]);
16771678
return out;
16781679
}
16791680

@@ -1696,7 +1697,7 @@ export class BinaryTree<K = any, V = any, R = any>
16961697
): BinaryTree<MK, MV, MR> {
16971698
const out = this._createLike<MK, MV, MR>([], options);
16981699
let i = 0;
1699-
for (const [k, v] of this) out.add(cb.call(thisArg, k, v, i++, this));
1700+
for (const [k, v] of this) out.add(cb.call(thisArg, v, k, i++, this));
17001701
return out;
17011702
}
17021703

src/data-structures/binary-tree/bst.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ export class BSTNode<K = any, V = any> {
199199
* 5. Logarithmic Operations: Ideal operations like insertion, deletion, and searching are O(log n) time-efficient.
200200
* 6. Balance Variability: Can become unbalanced; special types maintain balance.
201201
* 7. No Auto-Balancing: Standard BSTs don't automatically balance themselves.
202+
*
202203
* @example
203204
* // Merge 3 sorted datasets
204205
* const dataset1 = new BST<number, string>([
@@ -908,7 +909,7 @@ export class BST<K = any, V = any, R = any> extends BinaryTree<K, V, R> implemen
908909
let index = 0;
909910
// Iterates in-order
910911
for (const [key, value] of this) {
911-
out.add(callback.call(thisArg, key, value, index++, this));
912+
out.add(callback.call(thisArg, value, key, index++, this));
912913
}
913914
return out;
914915
}

src/data-structures/binary-tree/red-black-tree.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ export class RedBlackTreeNode<K = any, V = any> {
186186
* @template R
187187
* 1. Efficient self-balancing, but not completely balanced. Compared with AVLTree, the addition and deletion efficiency is high, but the query efficiency is slightly lower.
188188
* 2. It is BST itself. Compared with Heap which is not completely ordered, RedBlackTree is completely ordered.
189+
*
189190
* @example
190191
* // using Red-Black Tree as a price-based index for stock data
191192
* // Define the structure of individual stock records
@@ -420,7 +421,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
420421

421422
let index = 0;
422423
for (const [key, value] of this) {
423-
out.add(callback.call(thisArg, key, value, index++, this));
424+
out.add(callback.call(thisArg, value, key, index++, this));
424425
}
425426
return out;
426427
}

src/data-structures/binary-tree/tree-counter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ export class TreeCounter<K = any, V = any, R = any> extends RedBlackTree<K, V, R
439439

440440
let index = 0;
441441
for (const [key, value] of this) {
442-
out.add(callback.call(thisArg, key, value, index++, this));
442+
out.add(callback.call(thisArg, value, key, index++, this));
443443
}
444444
return out;
445445
}

0 commit comments

Comments
 (0)