linked-list-typed 2.0.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +14 -14
  2. package/dist/data-structures/base/iterable-element-base.d.ts +186 -83
  3. package/dist/data-structures/base/iterable-element-base.js +149 -107
  4. package/dist/data-structures/base/iterable-entry-base.d.ts +95 -119
  5. package/dist/data-structures/base/iterable-entry-base.js +59 -116
  6. package/dist/data-structures/base/linear-base.d.ts +250 -192
  7. package/dist/data-structures/base/linear-base.js +137 -274
  8. package/dist/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
  9. package/dist/data-structures/binary-tree/avl-tree-counter.js +171 -205
  10. package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
  11. package/dist/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
  12. package/dist/data-structures/binary-tree/avl-tree.d.ts +138 -149
  13. package/dist/data-structures/binary-tree/avl-tree.js +208 -195
  14. package/dist/data-structures/binary-tree/binary-tree.d.ts +476 -632
  15. package/dist/data-structures/binary-tree/binary-tree.js +612 -879
  16. package/dist/data-structures/binary-tree/bst.d.ts +258 -306
  17. package/dist/data-structures/binary-tree/bst.js +505 -481
  18. package/dist/data-structures/binary-tree/red-black-tree.d.ts +107 -179
  19. package/dist/data-structures/binary-tree/red-black-tree.js +114 -209
  20. package/dist/data-structures/binary-tree/tree-counter.d.ts +132 -154
  21. package/dist/data-structures/binary-tree/tree-counter.js +172 -203
  22. package/dist/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
  23. package/dist/data-structures/binary-tree/tree-multi-map.js +105 -85
  24. package/dist/data-structures/graph/abstract-graph.d.ts +238 -233
  25. package/dist/data-structures/graph/abstract-graph.js +267 -237
  26. package/dist/data-structures/graph/directed-graph.d.ts +108 -224
  27. package/dist/data-structures/graph/directed-graph.js +146 -233
  28. package/dist/data-structures/graph/map-graph.d.ts +49 -55
  29. package/dist/data-structures/graph/map-graph.js +56 -59
  30. package/dist/data-structures/graph/undirected-graph.d.ts +103 -146
  31. package/dist/data-structures/graph/undirected-graph.js +129 -149
  32. package/dist/data-structures/hash/hash-map.d.ts +164 -338
  33. package/dist/data-structures/hash/hash-map.js +270 -457
  34. package/dist/data-structures/heap/heap.d.ts +214 -289
  35. package/dist/data-structures/heap/heap.js +340 -349
  36. package/dist/data-structures/heap/max-heap.d.ts +11 -47
  37. package/dist/data-structures/heap/max-heap.js +11 -66
  38. package/dist/data-structures/heap/min-heap.d.ts +12 -47
  39. package/dist/data-structures/heap/min-heap.js +11 -66
  40. package/dist/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
  41. package/dist/data-structures/linked-list/doubly-linked-list.js +368 -494
  42. package/dist/data-structures/linked-list/singly-linked-list.d.ts +261 -310
  43. package/dist/data-structures/linked-list/singly-linked-list.js +447 -466
  44. package/dist/data-structures/linked-list/skip-linked-list.d.ts +0 -107
  45. package/dist/data-structures/linked-list/skip-linked-list.js +0 -100
  46. package/dist/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
  47. package/dist/data-structures/priority-queue/max-priority-queue.js +11 -78
  48. package/dist/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
  49. package/dist/data-structures/priority-queue/min-priority-queue.js +10 -79
  50. package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -61
  51. package/dist/data-structures/priority-queue/priority-queue.js +8 -83
  52. package/dist/data-structures/queue/deque.d.ts +227 -254
  53. package/dist/data-structures/queue/deque.js +309 -348
  54. package/dist/data-structures/queue/queue.d.ts +180 -201
  55. package/dist/data-structures/queue/queue.js +265 -248
  56. package/dist/data-structures/stack/stack.d.ts +124 -102
  57. package/dist/data-structures/stack/stack.js +181 -125
  58. package/dist/data-structures/trie/trie.d.ts +164 -165
  59. package/dist/data-structures/trie/trie.js +189 -172
  60. package/dist/interfaces/binary-tree.d.ts +56 -6
  61. package/dist/interfaces/graph.d.ts +16 -0
  62. package/dist/types/data-structures/base/base.d.ts +1 -1
  63. package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -0
  64. package/dist/types/utils/utils.d.ts +6 -6
  65. package/dist/utils/utils.d.ts +110 -49
  66. package/dist/utils/utils.js +148 -73
  67. package/package.json +2 -2
  68. package/src/data-structures/base/iterable-element-base.ts +238 -115
  69. package/src/data-structures/base/iterable-entry-base.ts +96 -120
  70. package/src/data-structures/base/linear-base.ts +271 -277
  71. package/src/data-structures/binary-tree/avl-tree-counter.ts +198 -216
  72. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +192 -101
  73. package/src/data-structures/binary-tree/avl-tree.ts +239 -206
  74. package/src/data-structures/binary-tree/binary-tree.ts +681 -905
  75. package/src/data-structures/binary-tree/bst.ts +568 -570
  76. package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
  77. package/src/data-structures/binary-tree/tree-counter.ts +199 -218
  78. package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
  79. package/src/data-structures/graph/abstract-graph.ts +339 -264
  80. package/src/data-structures/graph/directed-graph.ts +146 -236
  81. package/src/data-structures/graph/map-graph.ts +63 -60
  82. package/src/data-structures/graph/undirected-graph.ts +129 -152
  83. package/src/data-structures/hash/hash-map.ts +274 -496
  84. package/src/data-structures/heap/heap.ts +389 -402
  85. package/src/data-structures/heap/max-heap.ts +12 -76
  86. package/src/data-structures/heap/min-heap.ts +13 -76
  87. package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
  88. package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
  89. package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
  90. package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
  91. package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
  92. package/src/data-structures/priority-queue/priority-queue.ts +3 -92
  93. package/src/data-structures/queue/deque.ts +381 -357
  94. package/src/data-structures/queue/queue.ts +310 -264
  95. package/src/data-structures/stack/stack.ts +217 -131
  96. package/src/data-structures/trie/trie.ts +240 -175
  97. package/src/interfaces/binary-tree.ts +240 -6
  98. package/src/interfaces/graph.ts +37 -0
  99. package/src/types/data-structures/base/base.ts +5 -5
  100. package/src/types/data-structures/graph/abstract-graph.ts +5 -0
  101. package/src/types/utils/utils.ts +9 -5
  102. package/src/utils/utils.ts +152 -86
@@ -3,7 +3,7 @@ import { LinearBase } from '../../../data-structures/base/linear-base';
3
3
  export type EntryCallback<K, V, R> = (key: K, value: V, index: number, original: IterableEntryBase<K, V>) => R;
4
4
  export type ElementCallback<E, R, RT> = (element: E, index: number, original: IterableElementBase<E, R>) => RT;
5
5
  export type ReduceEntryCallback<K, V, R> = (accumulator: R, value: V, key: K, index: number, original: IterableEntryBase<K, V>) => R;
6
- export type ReduceElementCallback<E, R, RT = E> = (accumulator: RT, element: E, index: number, original: IterableElementBase<E, R>) => RT;
6
+ export type ReduceElementCallback<E, R, U = E> = (accumulator: U, value: E, index: number, self: IterableElementBase<E, R>) => U;
7
7
  export type ReduceLinearCallback<E, RT = E> = (accumulator: RT, element: E, index: number, original: LinearBase<E>) => RT;
8
8
  export type IterableElementBaseOptions<E, R> = {
9
9
  toElementFn?: (rawElement: R) => E;
@@ -8,3 +8,7 @@ export type DijkstraResult<V> = {
8
8
  minDist: number;
9
9
  minPath: V[];
10
10
  } | undefined;
11
+ export type GraphOptions<V = any> = {
12
+ vertexValueInitializer?: (key: VertexKey) => V;
13
+ defaultEdgeWeight?: number;
14
+ };
@@ -1,12 +1,7 @@
1
- export type ToThunkFn<R = any> = () => R;
2
- export type Thunk<R = any> = ToThunkFn<R> & {
3
- __THUNK__?: symbol;
4
- };
5
- export type TrlFn<A extends any[] = any[], R = any> = (...args: A) => R;
6
- export type TrlAsyncFn = (...args: any[]) => any;
7
1
  export type SpecifyOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
8
2
  export type Any = string | number | bigint | boolean | symbol | undefined | object;
9
3
  export type Arithmetic = number | bigint;
4
+ export type ElemOf<T> = T extends (infer U)[] ? U : never;
10
5
  export type ComparablePrimitive = number | bigint | string | boolean;
11
6
  export interface BaseComparableObject {
12
7
  [key: string]: unknown;
@@ -20,3 +15,8 @@ export interface StringComparableObject extends BaseComparableObject {
20
15
  }
21
16
  export type ComparableObject = ValueComparableObject | StringComparableObject;
22
17
  export type Comparable = ComparablePrimitive | Date | ComparableObject;
18
+ export type TrampolineThunk<T> = {
19
+ readonly isThunk: true;
20
+ readonly fn: () => Trampoline<T>;
21
+ };
22
+ export type Trampoline<T> = T | TrampolineThunk<T>;
@@ -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, Thunk, ToThunkFn, TrlAsyncFn, TrlFn } from '../types';
8
+ import type { Comparable, Trampoline, TrampolineThunk } from '../types';
9
9
  /**
10
10
  * The function generates a random UUID (Universally Unique Identifier) in TypeScript.
11
11
  * @returns A randomly generated UUID (Universally Unique Identifier) in the format
@@ -23,54 +23,6 @@ export declare const uuidV4: () => string;
23
23
  * `predicate` function.
24
24
  */
25
25
  export declare const arrayRemove: <T>(array: T[], predicate: (item: T, index: number, array: T[]) => boolean) => T[];
26
- export declare const THUNK_SYMBOL: unique symbol;
27
- /**
28
- * The function `isThunk` checks if a given value is a function with a specific symbol property.
29
- * @param {any} fnOrValue - The `fnOrValue` parameter in the `isThunk` function can be either a
30
- * function or a value that you want to check if it is a thunk. Thunks are functions that are wrapped
31
- * around a value or computation for lazy evaluation. The function checks if the `fnOrValue` is
32
- * @returns The function `isThunk` is checking if the input `fnOrValue` is a function and if it has a
33
- * property `__THUNK__` equal to `THUNK_SYMBOL`. The return value will be `true` if both conditions are
34
- * met, otherwise it will be `false`.
35
- */
36
- export declare const isThunk: (fnOrValue: any) => boolean;
37
- /**
38
- * The `toThunk` function in TypeScript converts a function into a thunk by wrapping it in a closure.
39
- * @param {ToThunkFn} fn - `fn` is a function that will be converted into a thunk.
40
- * @returns A thunk function is being returned. Thunk functions are functions that delay the evaluation
41
- * of an expression or operation until it is explicitly called or invoked. In this case, the `toThunk`
42
- * function takes a function `fn` as an argument and returns a thunk function that, when called, will
43
- * execute the `fn` function provided as an argument.
44
- */
45
- export declare const toThunk: (fn: ToThunkFn) => Thunk;
46
- /**
47
- * The `trampoline` function in TypeScript enables tail call optimization by using thunks to avoid
48
- * stack overflow.
49
- * @param {TrlFn} fn - The `fn` parameter in the `trampoline` function is a function that takes any
50
- * number of arguments and returns a value.
51
- * @returns The `trampoline` function returns an object with two properties:
52
- * 1. A function that executes the provided function `fn` and continues to execute any thunks returned
53
- * by `fn` until a non-thunk value is returned.
54
- * 2. A `cont` property that is a function which creates a thunk for the provided function `fn`.
55
- */
56
- export declare const trampoline: (fn: TrlFn) => ((...args: [...Parameters<TrlFn>]) => any) & {
57
- cont: (...args: [...Parameters<TrlFn>]) => ReturnType<TrlFn>;
58
- };
59
- /**
60
- * The `trampolineAsync` function in TypeScript allows for asynchronous trampolining of a given
61
- * function.
62
- * @param {TrlAsyncFn} fn - The `fn` parameter in the `trampolineAsync` function is expected to be a
63
- * function that returns a Promise. This function will be called recursively until a non-thunk value is
64
- * returned.
65
- * @returns The `trampolineAsync` function returns an object with two properties:
66
- * 1. An async function that executes the provided `TrlAsyncFn` function and continues to execute any
67
- * thunks returned by the function until a non-thunk value is returned.
68
- * 2. A `cont` property that is a function which wraps the provided `TrlAsyncFn` function in a thunk
69
- * and returns it.
70
- */
71
- export declare const trampolineAsync: (fn: TrlAsyncFn) => ((...args: [...Parameters<TrlAsyncFn>]) => Promise<any>) & {
72
- cont: (...args: [...Parameters<TrlAsyncFn>]) => ReturnType<TrlAsyncFn>;
73
- };
74
26
  /**
75
27
  * The function `getMSB` returns the most significant bit of a given number.
76
28
  * @param {number} value - The `value` parameter is a number for which we want to find the position of
@@ -146,3 +98,112 @@ export declare const roundFixed: (num: number, digit?: number) => number;
146
98
  * considered comparable or not.
147
99
  */
148
100
  export declare function isComparable(value: unknown, isForceObjectComparable?: boolean): value is Comparable;
101
+ /**
102
+ * Creates a trampoline thunk object.
103
+ *
104
+ * A "thunk" is a deferred computation — instead of performing a recursive call immediately,
105
+ * it wraps the next step of the computation in a function. This allows recursive processes
106
+ * to be executed iteratively, preventing stack overflows.
107
+ *
108
+ * @template T - The type of the final computation result.
109
+ * @param computation - A function that, when executed, returns the next trampoline step.
110
+ * @returns A TrampolineThunk object containing the deferred computation.
111
+ */
112
+ export declare const makeTrampolineThunk: <T>(computation: () => Trampoline<T>) => TrampolineThunk<T>;
113
+ /**
114
+ * Type guard to check whether a given value is a TrampolineThunk.
115
+ *
116
+ * This function is used to distinguish between a final computation result (value)
117
+ * and a deferred computation (thunk).
118
+ *
119
+ * @template T - The type of the value being checked.
120
+ * @param value - The value to test.
121
+ * @returns True if the value is a valid TrampolineThunk, false otherwise.
122
+ */
123
+ export declare const isTrampolineThunk: <T>(value: Trampoline<T>) => value is TrampolineThunk<T>;
124
+ /**
125
+ * Executes a trampoline computation until a final (non-thunk) result is obtained.
126
+ *
127
+ * The trampoline function repeatedly invokes the deferred computations (thunks)
128
+ * in an iterative loop. This avoids deep recursive calls and prevents stack overflow,
129
+ * which is particularly useful for implementing recursion in a stack-safe manner.
130
+ *
131
+ * @template T - The type of the final result.
132
+ * @param initial - The initial Trampoline value or thunk to start execution from.
133
+ * @returns The final result of the computation (a non-thunk value).
134
+ */
135
+ export declare function trampoline<T>(initial: Trampoline<T>): T;
136
+ /**
137
+ * Wraps a recursive function inside a trampoline executor.
138
+ *
139
+ * This function transforms a potentially recursive function (that returns a Trampoline<Result>)
140
+ * into a *stack-safe* function that executes iteratively using the `trampoline` runner.
141
+ *
142
+ * In other words, it allows you to write functions that look recursive,
143
+ * but actually run in constant stack space.
144
+ *
145
+ * @template Args - The tuple type representing the argument list of the original function.
146
+ * @template Result - The final return type after all trampoline steps are resolved.
147
+ *
148
+ * @param fn - A function that performs a single step of computation
149
+ * and returns a Trampoline (either a final value or a deferred thunk).
150
+ *
151
+ * @returns A new function with the same arguments, but which automatically
152
+ * runs the trampoline process and returns the *final result* instead
153
+ * of a Trampoline.
154
+ *
155
+ * @example
156
+ * // Example: Computing factorial in a stack-safe way
157
+ * const factorial = makeTrampoline(function fact(n: number, acc: number = 1): Trampoline<number> {
158
+ * return n === 0
159
+ * ? acc
160
+ * : makeTrampolineThunk(() => fact(n - 1, acc * n));
161
+ * });
162
+ *
163
+ * console.log(factorial(100000)); // Works without stack overflow
164
+ */
165
+ export declare function makeTrampoline<Args extends any[], Result>(fn: (...args: Args) => Trampoline<Result>): (...args: Args) => Result;
166
+ /**
167
+ * Executes an asynchronous trampoline computation until a final (non-thunk) result is obtained.
168
+ *
169
+ * This function repeatedly invokes asynchronous deferred computations (thunks)
170
+ * in an iterative loop. Each thunk may return either a Trampoline<T> or a Promise<Trampoline<T>>.
171
+ *
172
+ * It ensures that asynchronous recursive functions can run without growing the call stack,
173
+ * making it suitable for stack-safe async recursion.
174
+ *
175
+ * @template T - The type of the final result.
176
+ * @param initial - The initial Trampoline or Promise of Trampoline to start execution from.
177
+ * @returns A Promise that resolves to the final result (a non-thunk value).
178
+ */
179
+ export declare function asyncTrampoline<T>(initial: Trampoline<T> | Promise<Trampoline<T>>): Promise<T>;
180
+ /**
181
+ * Wraps an asynchronous recursive function inside an async trampoline executor.
182
+ *
183
+ * This helper transforms a recursive async function that returns a Trampoline<Result>
184
+ * (or Promise<Trampoline<Result>>) into a *stack-safe* async function that executes
185
+ * iteratively via the `asyncTrampoline` runner.
186
+ *
187
+ * @template Args - The tuple type representing the argument list of the original function.
188
+ * @template Result - The final return type after all async trampoline steps are resolved.
189
+ *
190
+ * @param fn - An async or sync function that performs a single step of computation
191
+ * and returns a Trampoline (either a final value or a deferred thunk).
192
+ *
193
+ * @returns An async function with the same arguments, but which automatically
194
+ * runs the trampoline process and resolves to the *final result*.
195
+ *
196
+ * @example
197
+ * // Example: Async factorial using trampoline
198
+ * const asyncFactorial = makeAsyncTrampoline(async function fact(
199
+ * n: number,
200
+ * acc: number = 1
201
+ * ): Promise<Trampoline<number>> {
202
+ * return n === 0
203
+ * ? acc
204
+ * : makeTrampolineThunk(() => fact(n - 1, acc * n));
205
+ * });
206
+ *
207
+ * asyncFactorial(100000).then(console.log); // Works without stack overflow
208
+ */
209
+ export declare function makeAsyncTrampoline<Args extends any[], Result>(fn: (...args: Args) => Trampoline<Result> | Promise<Trampoline<Result>>): (...args: Args) => Promise<Result>;
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.isComparable = exports.roundFixed = exports.calcMinUnitsRequired = exports.isWeakKey = exports.throwRangeError = exports.rangeCheck = exports.getMSB = exports.trampolineAsync = exports.trampoline = exports.toThunk = exports.isThunk = exports.THUNK_SYMBOL = exports.arrayRemove = exports.uuidV4 = void 0;
12
+ exports.makeAsyncTrampoline = exports.asyncTrampoline = exports.makeTrampoline = exports.trampoline = exports.isTrampolineThunk = exports.makeTrampolineThunk = exports.isComparable = exports.roundFixed = exports.calcMinUnitsRequired = exports.isWeakKey = exports.throwRangeError = exports.rangeCheck = exports.getMSB = exports.arrayRemove = exports.uuidV4 = void 0;
13
13
  /**
14
14
  * The function generates a random UUID (Universally Unique Identifier) in TypeScript.
15
15
  * @returns A randomly generated UUID (Universally Unique Identifier) in the format
@@ -46,78 +46,6 @@ const arrayRemove = function (array, predicate) {
46
46
  return result;
47
47
  };
48
48
  exports.arrayRemove = arrayRemove;
49
- exports.THUNK_SYMBOL = Symbol('thunk');
50
- /**
51
- * The function `isThunk` checks if a given value is a function with a specific symbol property.
52
- * @param {any} fnOrValue - The `fnOrValue` parameter in the `isThunk` function can be either a
53
- * function or a value that you want to check if it is a thunk. Thunks are functions that are wrapped
54
- * around a value or computation for lazy evaluation. The function checks if the `fnOrValue` is
55
- * @returns The function `isThunk` is checking if the input `fnOrValue` is a function and if it has a
56
- * property `__THUNK__` equal to `THUNK_SYMBOL`. The return value will be `true` if both conditions are
57
- * met, otherwise it will be `false`.
58
- */
59
- const isThunk = (fnOrValue) => {
60
- return typeof fnOrValue === 'function' && fnOrValue.__THUNK__ === exports.THUNK_SYMBOL;
61
- };
62
- exports.isThunk = isThunk;
63
- /**
64
- * The `toThunk` function in TypeScript converts a function into a thunk by wrapping it in a closure.
65
- * @param {ToThunkFn} fn - `fn` is a function that will be converted into a thunk.
66
- * @returns A thunk function is being returned. Thunk functions are functions that delay the evaluation
67
- * of an expression or operation until it is explicitly called or invoked. In this case, the `toThunk`
68
- * function takes a function `fn` as an argument and returns a thunk function that, when called, will
69
- * execute the `fn` function provided as an argument.
70
- */
71
- const toThunk = (fn) => {
72
- const thunk = () => fn();
73
- thunk.__THUNK__ = exports.THUNK_SYMBOL;
74
- return thunk;
75
- };
76
- exports.toThunk = toThunk;
77
- /**
78
- * The `trampoline` function in TypeScript enables tail call optimization by using thunks to avoid
79
- * stack overflow.
80
- * @param {TrlFn} fn - The `fn` parameter in the `trampoline` function is a function that takes any
81
- * number of arguments and returns a value.
82
- * @returns The `trampoline` function returns an object with two properties:
83
- * 1. A function that executes the provided function `fn` and continues to execute any thunks returned
84
- * by `fn` until a non-thunk value is returned.
85
- * 2. A `cont` property that is a function which creates a thunk for the provided function `fn`.
86
- */
87
- const trampoline = (fn) => {
88
- const cont = (...args) => (0, exports.toThunk)(() => fn(...args));
89
- return Object.assign((...args) => {
90
- let result = fn(...args);
91
- while ((0, exports.isThunk)(result) && typeof result === 'function') {
92
- result = result();
93
- }
94
- return result;
95
- }, { cont });
96
- };
97
- exports.trampoline = trampoline;
98
- /**
99
- * The `trampolineAsync` function in TypeScript allows for asynchronous trampolining of a given
100
- * function.
101
- * @param {TrlAsyncFn} fn - The `fn` parameter in the `trampolineAsync` function is expected to be a
102
- * function that returns a Promise. This function will be called recursively until a non-thunk value is
103
- * returned.
104
- * @returns The `trampolineAsync` function returns an object with two properties:
105
- * 1. An async function that executes the provided `TrlAsyncFn` function and continues to execute any
106
- * thunks returned by the function until a non-thunk value is returned.
107
- * 2. A `cont` property that is a function which wraps the provided `TrlAsyncFn` function in a thunk
108
- * and returns it.
109
- */
110
- const trampolineAsync = (fn) => {
111
- const cont = (...args) => (0, exports.toThunk)(() => fn(...args));
112
- return Object.assign((...args) => __awaiter(void 0, void 0, void 0, function* () {
113
- let result = yield fn(...args);
114
- while ((0, exports.isThunk)(result) && typeof result === 'function') {
115
- result = yield result();
116
- }
117
- return result;
118
- }), { cont });
119
- };
120
- exports.trampolineAsync = trampolineAsync;
121
49
  /**
122
50
  * The function `getMSB` returns the most significant bit of a given number.
123
51
  * @param {number} value - The `value` parameter is a number for which we want to find the position of
@@ -276,3 +204,150 @@ function isComparable(value, isForceObjectComparable = false) {
276
204
  return isPrimitiveComparable(comparableValue);
277
205
  }
278
206
  exports.isComparable = isComparable;
207
+ /**
208
+ * Creates a trampoline thunk object.
209
+ *
210
+ * A "thunk" is a deferred computation — instead of performing a recursive call immediately,
211
+ * it wraps the next step of the computation in a function. This allows recursive processes
212
+ * to be executed iteratively, preventing stack overflows.
213
+ *
214
+ * @template T - The type of the final computation result.
215
+ * @param computation - A function that, when executed, returns the next trampoline step.
216
+ * @returns A TrampolineThunk object containing the deferred computation.
217
+ */
218
+ const makeTrampolineThunk = (computation) => ({
219
+ isThunk: true,
220
+ fn: computation // The deferred computation function
221
+ });
222
+ exports.makeTrampolineThunk = makeTrampolineThunk;
223
+ /**
224
+ * Type guard to check whether a given value is a TrampolineThunk.
225
+ *
226
+ * This function is used to distinguish between a final computation result (value)
227
+ * and a deferred computation (thunk).
228
+ *
229
+ * @template T - The type of the value being checked.
230
+ * @param value - The value to test.
231
+ * @returns True if the value is a valid TrampolineThunk, false otherwise.
232
+ */
233
+ const isTrampolineThunk = (value) => typeof value === 'object' && // Must be an object
234
+ value !== null && // Must not be null
235
+ 'isThunk' in value && // Must have the 'isThunk' property
236
+ value.isThunk; // The flag must be true
237
+ exports.isTrampolineThunk = isTrampolineThunk;
238
+ /**
239
+ * Executes a trampoline computation until a final (non-thunk) result is obtained.
240
+ *
241
+ * The trampoline function repeatedly invokes the deferred computations (thunks)
242
+ * in an iterative loop. This avoids deep recursive calls and prevents stack overflow,
243
+ * which is particularly useful for implementing recursion in a stack-safe manner.
244
+ *
245
+ * @template T - The type of the final result.
246
+ * @param initial - The initial Trampoline value or thunk to start execution from.
247
+ * @returns The final result of the computation (a non-thunk value).
248
+ */
249
+ function trampoline(initial) {
250
+ let current = initial; // Start with the initial trampoline value
251
+ while ((0, exports.isTrampolineThunk)(current)) {
252
+ // Keep unwrapping while we have thunks
253
+ current = current.fn(); // Execute the deferred function to get the next step
254
+ }
255
+ return current; // Once no thunks remain, return the final result
256
+ }
257
+ exports.trampoline = trampoline;
258
+ /**
259
+ * Wraps a recursive function inside a trampoline executor.
260
+ *
261
+ * This function transforms a potentially recursive function (that returns a Trampoline<Result>)
262
+ * into a *stack-safe* function that executes iteratively using the `trampoline` runner.
263
+ *
264
+ * In other words, it allows you to write functions that look recursive,
265
+ * but actually run in constant stack space.
266
+ *
267
+ * @template Args - The tuple type representing the argument list of the original function.
268
+ * @template Result - The final return type after all trampoline steps are resolved.
269
+ *
270
+ * @param fn - A function that performs a single step of computation
271
+ * and returns a Trampoline (either a final value or a deferred thunk).
272
+ *
273
+ * @returns A new function with the same arguments, but which automatically
274
+ * runs the trampoline process and returns the *final result* instead
275
+ * of a Trampoline.
276
+ *
277
+ * @example
278
+ * // Example: Computing factorial in a stack-safe way
279
+ * const factorial = makeTrampoline(function fact(n: number, acc: number = 1): Trampoline<number> {
280
+ * return n === 0
281
+ * ? acc
282
+ * : makeTrampolineThunk(() => fact(n - 1, acc * n));
283
+ * });
284
+ *
285
+ * console.log(factorial(100000)); // Works without stack overflow
286
+ */
287
+ function makeTrampoline(fn // A function that returns a trampoline step
288
+ ) {
289
+ // Return a wrapped function that automatically runs the trampoline execution loop
290
+ return (...args) => trampoline(fn(...args));
291
+ }
292
+ exports.makeTrampoline = makeTrampoline;
293
+ /**
294
+ * Executes an asynchronous trampoline computation until a final (non-thunk) result is obtained.
295
+ *
296
+ * This function repeatedly invokes asynchronous deferred computations (thunks)
297
+ * in an iterative loop. Each thunk may return either a Trampoline<T> or a Promise<Trampoline<T>>.
298
+ *
299
+ * It ensures that asynchronous recursive functions can run without growing the call stack,
300
+ * making it suitable for stack-safe async recursion.
301
+ *
302
+ * @template T - The type of the final result.
303
+ * @param initial - The initial Trampoline or Promise of Trampoline to start execution from.
304
+ * @returns A Promise that resolves to the final result (a non-thunk value).
305
+ */
306
+ function asyncTrampoline(initial) {
307
+ return __awaiter(this, void 0, void 0, function* () {
308
+ let current = yield initial; // Wait for the initial step to resolve if it's a Promise
309
+ // Keep executing thunks until we reach a non-thunk (final) value
310
+ while ((0, exports.isTrampolineThunk)(current)) {
311
+ current = yield current.fn(); // Execute the thunk function (may be async)
312
+ }
313
+ // Once the final value is reached, return it
314
+ return current;
315
+ });
316
+ }
317
+ exports.asyncTrampoline = asyncTrampoline;
318
+ /**
319
+ * Wraps an asynchronous recursive function inside an async trampoline executor.
320
+ *
321
+ * This helper transforms a recursive async function that returns a Trampoline<Result>
322
+ * (or Promise<Trampoline<Result>>) into a *stack-safe* async function that executes
323
+ * iteratively via the `asyncTrampoline` runner.
324
+ *
325
+ * @template Args - The tuple type representing the argument list of the original function.
326
+ * @template Result - The final return type after all async trampoline steps are resolved.
327
+ *
328
+ * @param fn - An async or sync function that performs a single step of computation
329
+ * and returns a Trampoline (either a final value or a deferred thunk).
330
+ *
331
+ * @returns An async function with the same arguments, but which automatically
332
+ * runs the trampoline process and resolves to the *final result*.
333
+ *
334
+ * @example
335
+ * // Example: Async factorial using trampoline
336
+ * const asyncFactorial = makeAsyncTrampoline(async function fact(
337
+ * n: number,
338
+ * acc: number = 1
339
+ * ): Promise<Trampoline<number>> {
340
+ * return n === 0
341
+ * ? acc
342
+ * : makeTrampolineThunk(() => fact(n - 1, acc * n));
343
+ * });
344
+ *
345
+ * asyncFactorial(100000).then(console.log); // Works without stack overflow
346
+ */
347
+ function makeAsyncTrampoline(fn) {
348
+ // Return a wrapped async function that runs through the async trampoline loop
349
+ return (...args) => __awaiter(this, void 0, void 0, function* () {
350
+ return asyncTrampoline(fn(...args));
351
+ });
352
+ }
353
+ exports.makeAsyncTrampoline = makeAsyncTrampoline;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linked-list-typed",
3
- "version": "2.0.4",
3
+ "version": "2.1.0",
4
4
  "description": "Linked List",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -66,6 +66,6 @@
66
66
  "typescript": "^4.9.5"
67
67
  },
68
68
  "dependencies": {
69
- "data-structure-typed": "^2.0.4"
69
+ "data-structure-typed": "^2.1.0"
70
70
  }
71
71
  }