data-structure-typed 2.0.1 → 2.0.2
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/CHANGELOG.md +1 -1
- package/dist/cjs/data-structures/binary-tree/binary-tree.js +8 -9
- package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/cjs/types/utils/utils.d.ts +1 -7
- package/dist/cjs/utils/utils.d.ts +3 -49
- package/dist/cjs/utils/utils.js +13 -82
- package/dist/cjs/utils/utils.js.map +1 -1
- package/dist/esm/data-structures/binary-tree/binary-tree.js +8 -9
- package/dist/esm/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/esm/types/utils/utils.d.ts +1 -7
- package/dist/esm/utils/utils.d.ts +3 -49
- package/dist/esm/utils/utils.js +10 -68
- package/dist/esm/utils/utils.js.map +1 -1
- package/dist/umd/data-structure-typed.js +18 -66
- package/dist/umd/data-structure-typed.min.js +2 -2
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +1 -1
- package/src/data-structures/binary-tree/binary-tree.ts +9 -10
- package/src/types/utils/utils.ts +1 -6
- package/src/utils/utils.ts +11 -83
- package/test/unit/data-structures/queue/queue.test.ts +1 -1
- package/test/unit/utils/utils.test.ts +35 -2
- package/dist/individuals/binary-tree/avl-tree-counter.mjs +0 -4701
- package/dist/individuals/binary-tree/avl-tree-multi-map.mjs +0 -4514
- package/dist/individuals/binary-tree/avl-tree.mjs +0 -4321
- package/dist/individuals/binary-tree/binary-tree.mjs +0 -3097
- package/dist/individuals/binary-tree/bst.mjs +0 -3858
- package/dist/individuals/binary-tree/red-black-tree.mjs +0 -4391
- package/dist/individuals/binary-tree/tree-counter.mjs +0 -4806
- package/dist/individuals/binary-tree/tree-multi-map.mjs +0 -4582
- package/dist/individuals/graph/directed-graph.mjs +0 -2910
- package/dist/individuals/graph/undirected-graph.mjs +0 -2745
- package/dist/individuals/hash/hash-map.mjs +0 -1040
- package/dist/individuals/heap/heap.mjs +0 -909
- package/dist/individuals/heap/max-heap.mjs +0 -671
- package/dist/individuals/heap/min-heap.mjs +0 -659
- package/dist/individuals/linked-list/doubly-linked-list.mjs +0 -1495
- package/dist/individuals/linked-list/singly-linked-list.mjs +0 -1479
- package/dist/individuals/priority-queue/max-priority-queue.mjs +0 -768
- package/dist/individuals/priority-queue/min-priority-queue.mjs +0 -757
- package/dist/individuals/priority-queue/priority-queue.mjs +0 -670
- package/dist/individuals/queue/deque.mjs +0 -1262
- package/dist/individuals/queue/queue.mjs +0 -1865
- package/dist/individuals/stack/stack.mjs +0 -415
- package/dist/individuals/trie/trie.mjs +0 -687
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@ import type {
|
|
|
20
20
|
NodeDisplayLayout,
|
|
21
21
|
NodePredicate,
|
|
22
22
|
OptNodeOrNull,
|
|
23
|
-
RBTNColor,
|
|
23
|
+
RBTNColor, Thunk,
|
|
24
24
|
ToEntryFn
|
|
25
25
|
} from '../../types';
|
|
26
26
|
import { IBinaryTree } from '../../interfaces';
|
|
@@ -1304,12 +1304,12 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1304
1304
|
return callback(dfs(startNode));
|
|
1305
1305
|
} else {
|
|
1306
1306
|
// Indirect implementation of iteration using tail recursion optimization
|
|
1307
|
-
const dfs =
|
|
1307
|
+
const dfs = (cur: BinaryTreeNode<K, V>): BinaryTreeNode<K, V> | Thunk<BinaryTreeNode<K, V>> => {
|
|
1308
1308
|
if (!this.isRealNode(cur.left)) return cur;
|
|
1309
|
-
return dfs
|
|
1310
|
-
}
|
|
1309
|
+
return () => dfs(cur.left!);
|
|
1310
|
+
};
|
|
1311
1311
|
|
|
1312
|
-
return callback(dfs(startNode));
|
|
1312
|
+
return callback(trampoline(() => dfs(startNode)));
|
|
1313
1313
|
}
|
|
1314
1314
|
}
|
|
1315
1315
|
|
|
@@ -1352,13 +1352,12 @@ export class BinaryTree<K = any, V = any, R = object, MK = any, MV = any, MR = o
|
|
|
1352
1352
|
|
|
1353
1353
|
return callback(dfs(startNode));
|
|
1354
1354
|
} else {
|
|
1355
|
-
|
|
1356
|
-
const dfs = trampoline((cur: BinaryTreeNode<K, V>) => {
|
|
1355
|
+
const dfs = (cur: BinaryTreeNode<K, V>) => {
|
|
1357
1356
|
if (!this.isRealNode(cur.right)) return cur;
|
|
1358
|
-
return dfs
|
|
1359
|
-
}
|
|
1357
|
+
return () => dfs(cur.right!) as Thunk<BinaryTreeNode<K, V>>;
|
|
1358
|
+
};
|
|
1360
1359
|
|
|
1361
|
-
return callback(dfs(startNode));
|
|
1360
|
+
return callback(trampoline(() => dfs(startNode)));
|
|
1362
1361
|
}
|
|
1363
1362
|
}
|
|
1364
1363
|
|
package/src/types/utils/utils.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export type Thunk<R = any> = ToThunkFn<R> & { __THUNK__?: symbol };
|
|
3
|
-
export type TrlFn<A extends any[] = any[], R = any> = (...args: A) => R;
|
|
4
|
-
export type TrlAsyncFn = (...args: any[]) => any;
|
|
5
|
-
|
|
6
|
-
export type SpecifyOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
1
|
+
export type Thunk<T> = () => T | Thunk<T>;
|
|
7
2
|
|
|
8
3
|
export type Any = string | number | bigint | boolean | symbol | undefined | object;
|
|
9
4
|
|
package/src/utils/utils.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
-
import type { Comparable, ComparablePrimitive, Thunk
|
|
8
|
+
import type { Comparable, ComparablePrimitive, Thunk } from '../types';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* The function generates a random UUID (Universally Unique Identifier) in TypeScript.
|
|
@@ -47,90 +47,18 @@ export const arrayRemove = function <T>(array: T[], predicate: (item: T, index:
|
|
|
47
47
|
return result;
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
export const THUNK_SYMBOL = Symbol('thunk');
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
* function or a value that you want to check if it is a thunk. Thunks are functions that are wrapped
|
|
56
|
-
* around a value or computation for lazy evaluation. The function checks if the `fnOrValue` is
|
|
57
|
-
* @returns The function `isThunk` is checking if the input `fnOrValue` is a function and if it has a
|
|
58
|
-
* property `__THUNK__` equal to `THUNK_SYMBOL`. The return value will be `true` if both conditions are
|
|
59
|
-
* met, otherwise it will be `false`.
|
|
60
|
-
*/
|
|
61
|
-
export const isThunk = (fnOrValue: any) => {
|
|
62
|
-
return typeof fnOrValue === 'function' && fnOrValue.__THUNK__ === THUNK_SYMBOL;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* The `toThunk` function in TypeScript converts a function into a thunk by wrapping it in a closure.
|
|
67
|
-
* @param {ToThunkFn} fn - `fn` is a function that will be converted into a thunk.
|
|
68
|
-
* @returns A thunk function is being returned. Thunk functions are functions that delay the evaluation
|
|
69
|
-
* of an expression or operation until it is explicitly called or invoked. In this case, the `toThunk`
|
|
70
|
-
* function takes a function `fn` as an argument and returns a thunk function that, when called, will
|
|
71
|
-
* execute the `fn` function provided as an argument.
|
|
72
|
-
*/
|
|
73
|
-
export const toThunk = (fn: ToThunkFn): Thunk => {
|
|
74
|
-
const thunk = () => fn();
|
|
75
|
-
thunk.__THUNK__ = THUNK_SYMBOL;
|
|
76
|
-
return thunk;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* The `trampoline` function in TypeScript enables tail call optimization by using thunks to avoid
|
|
81
|
-
* stack overflow.
|
|
82
|
-
* @param {TrlFn} fn - The `fn` parameter in the `trampoline` function is a function that takes any
|
|
83
|
-
* number of arguments and returns a value.
|
|
84
|
-
* @returns The `trampoline` function returns an object with two properties:
|
|
85
|
-
* 1. A function that executes the provided function `fn` and continues to execute any thunks returned
|
|
86
|
-
* by `fn` until a non-thunk value is returned.
|
|
87
|
-
* 2. A `cont` property that is a function which creates a thunk for the provided function `fn`.
|
|
88
|
-
*/
|
|
89
|
-
export const trampoline = (fn: TrlFn) => {
|
|
90
|
-
const cont = (...args: [...Parameters<TrlFn>]): ReturnType<TrlFn> => toThunk(() => fn(...args));
|
|
91
|
-
|
|
92
|
-
return Object.assign(
|
|
93
|
-
(...args: [...Parameters<TrlFn>]) => {
|
|
94
|
-
let result = fn(...args);
|
|
95
|
-
|
|
96
|
-
while (isThunk(result) && typeof result === 'function') {
|
|
97
|
-
result = result();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return result;
|
|
101
|
-
},
|
|
102
|
-
{ cont }
|
|
103
|
-
);
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* The `trampolineAsync` function in TypeScript allows for asynchronous trampolining of a given
|
|
108
|
-
* function.
|
|
109
|
-
* @param {TrlAsyncFn} fn - The `fn` parameter in the `trampolineAsync` function is expected to be a
|
|
110
|
-
* function that returns a Promise. This function will be called recursively until a non-thunk value is
|
|
111
|
-
* returned.
|
|
112
|
-
* @returns The `trampolineAsync` function returns an object with two properties:
|
|
113
|
-
* 1. An async function that executes the provided `TrlAsyncFn` function and continues to execute any
|
|
114
|
-
* thunks returned by the function until a non-thunk value is returned.
|
|
115
|
-
* 2. A `cont` property that is a function which wraps the provided `TrlAsyncFn` function in a thunk
|
|
116
|
-
* and returns it.
|
|
117
|
-
*/
|
|
118
|
-
export const trampolineAsync = (fn: TrlAsyncFn) => {
|
|
119
|
-
const cont = (...args: [...Parameters<TrlAsyncFn>]): ReturnType<TrlAsyncFn> => toThunk(() => fn(...args));
|
|
120
|
-
|
|
121
|
-
return Object.assign(
|
|
122
|
-
async (...args: [...Parameters<TrlAsyncFn>]) => {
|
|
123
|
-
let result = await fn(...args);
|
|
124
|
-
|
|
125
|
-
while (isThunk(result) && typeof result === 'function') {
|
|
126
|
-
result = await result();
|
|
127
|
-
}
|
|
51
|
+
export function isThunk<T>(result: T | Thunk<T>): result is Thunk<T> {
|
|
52
|
+
return typeof result === 'function';
|
|
53
|
+
}
|
|
128
54
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
55
|
+
export function trampoline<T>(thunk: Thunk<T>): T {
|
|
56
|
+
let result: T | Thunk<T> = thunk;
|
|
57
|
+
while (isThunk(result)) {
|
|
58
|
+
result = result();
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
134
62
|
|
|
135
63
|
/**
|
|
136
64
|
* The function `getMSB` returns the most significant bit of a given number.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { isComparable, trampoline } from '../../../src';
|
|
2
|
+
|
|
1
3
|
describe('isNaN', () => {
|
|
2
4
|
it('should isNaN', function () {
|
|
3
5
|
expect(isNaN('string' as unknown as number)).toBe(true);
|
|
4
6
|
});
|
|
5
7
|
});
|
|
6
8
|
|
|
7
|
-
import { isComparable } from '../../../src';
|
|
8
|
-
|
|
9
9
|
describe('isComparable', () => {
|
|
10
10
|
describe('primitive types', () => {
|
|
11
11
|
it('numbers should be comparable', () => {
|
|
@@ -172,3 +172,36 @@ describe('isComparable', () => {
|
|
|
172
172
|
});
|
|
173
173
|
});
|
|
174
174
|
});
|
|
175
|
+
|
|
176
|
+
describe('Factorial Performance Tests', () => {
|
|
177
|
+
const depth = 5000;
|
|
178
|
+
let arr: number[];
|
|
179
|
+
|
|
180
|
+
const recurseTrampoline = (n: number, arr: number[], acc = 1): (() => any) | number => {
|
|
181
|
+
if (n === 0) return acc;
|
|
182
|
+
arr.unshift(1);
|
|
183
|
+
return () => recurseTrampoline(n - 1, arr, acc);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const recurse = (n: number, arr: number[], acc = 1): number => {
|
|
187
|
+
if (n === 0) return acc;
|
|
188
|
+
arr.unshift(1);
|
|
189
|
+
return recurse(n - 1, arr, acc);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
beforeEach(() => {
|
|
193
|
+
arr = new Array(depth).fill(0);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should calculate recursive function using trampoline without stack overflow', () => {
|
|
197
|
+
const result = trampoline(() => recurseTrampoline(depth, arr));
|
|
198
|
+
expect(result).toBe(1);
|
|
199
|
+
expect(arr.length).toBe(depth + depth);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should calculate recursive directly and possibly stack overflow', () => {
|
|
203
|
+
const result = recurse(depth, arr);
|
|
204
|
+
expect(result).toBe(1);
|
|
205
|
+
expect(arr.length).toBe(depth + depth);
|
|
206
|
+
});
|
|
207
|
+
});
|