atomic-fns 1.2.0 → 2.0.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/README.md +397 -91
- package/dist/array/index.d.ts +9 -0
- package/dist/array/index.js +9 -0
- package/dist/array/list.d.ts +99 -0
- package/dist/array/list.js +133 -0
- package/dist/array/sets.d.ts +130 -0
- package/dist/array/sets.js +213 -0
- package/dist/async/index.d.ts +6 -0
- package/dist/async/index.js +6 -0
- package/dist/async/retry.d.ts +38 -0
- package/dist/async/retry.js +56 -0
- package/dist/async/sleep.d.ts +42 -0
- package/dist/async/sleep.js +76 -0
- package/dist/collections/bisect.d.ts +103 -0
- package/dist/collections/bisect.js +157 -0
- package/dist/collections/deque.d.ts +67 -97
- package/dist/collections/deque.js +197 -256
- package/dist/collections/entries.d.ts +89 -0
- package/dist/collections/entries.js +131 -0
- package/dist/collections/frozen-set.d.ts +42 -0
- package/dist/collections/frozen-set.js +64 -0
- package/dist/collections/group.d.ts +141 -0
- package/dist/collections/group.js +241 -0
- package/dist/collections/heap.d.ts +64 -0
- package/dist/collections/heap.js +205 -0
- package/dist/collections/index.d.ts +15 -623
- package/dist/collections/index.js +14 -844
- package/dist/collections/internal/arrayKeys.d.ts +19 -0
- package/dist/collections/internal/arrayKeys.js +83 -0
- package/dist/collections/internal/invariants.d.ts +4 -0
- package/dist/collections/internal/invariants.js +12 -0
- package/dist/collections/internal/iterable.d.ts +25 -0
- package/dist/collections/internal/iterable.js +62 -0
- package/dist/collections/iterate.d.ts +162 -0
- package/dist/collections/iterate.js +188 -0
- package/dist/collections/lru-cache.d.ts +58 -0
- package/dist/collections/lru-cache.js +164 -0
- package/dist/collections/order.d.ts +19 -0
- package/dist/collections/order.js +38 -0
- package/dist/collections/shape.d.ts +32 -0
- package/dist/collections/shape.js +86 -0
- package/dist/collections/sorted-map.d.ts +171 -0
- package/dist/collections/sorted-map.js +845 -0
- package/dist/collections/sorted-set.d.ts +103 -0
- package/dist/collections/sorted-set.js +147 -0
- package/dist/collections/splay-tree.d.ts +82 -0
- package/dist/collections/splay-tree.js +354 -0
- package/dist/collections/trie.d.ts +58 -0
- package/dist/collections/trie.js +196 -0
- package/dist/decimal/currency.d.ts +211 -0
- package/dist/decimal/currency.js +321 -0
- package/dist/decimal/decimal.d.ts +299 -0
- package/dist/decimal/decimal.js +660 -0
- package/dist/decimal/index.d.ts +11 -148
- package/dist/decimal/index.js +10 -410
- package/dist/decimal/internal/bits.d.ts +2 -0
- package/dist/decimal/internal/bits.js +7 -0
- package/dist/decimal/internal/echo.d.ts +4 -0
- package/dist/decimal/internal/echo.js +6 -0
- package/dist/decimal/internal/isqrt.d.ts +9 -0
- package/dist/decimal/internal/isqrt.js +34 -0
- package/dist/decimal/internal/locale.d.ts +7 -0
- package/dist/decimal/internal/locale.js +24 -0
- package/dist/decimal/internal/minor-units.d.ts +2 -0
- package/dist/decimal/internal/minor-units.js +33 -0
- package/dist/decimal/internal/pow10.d.ts +24 -0
- package/dist/decimal/internal/pow10.js +96 -0
- package/dist/encoding/base64.d.ts +39 -0
- package/dist/encoding/base64.js +53 -0
- package/dist/encoding/hex.d.ts +23 -0
- package/dist/encoding/hex.js +34 -0
- package/dist/encoding/index.d.ts +6 -0
- package/dist/encoding/index.js +6 -0
- package/dist/function/debounce.d.ts +68 -0
- package/dist/function/debounce.js +203 -0
- package/dist/function/index.d.ts +6 -0
- package/dist/function/index.js +6 -0
- package/dist/function/shared.d.ts +2 -0
- package/dist/function/shared.js +5 -0
- package/dist/function/wrap.d.ts +130 -0
- package/dist/function/wrap.js +113 -0
- package/dist/hash/digest.d.ts +18 -0
- package/dist/hash/digest.js +26 -0
- package/dist/hash/hash.d.ts +22 -0
- package/dist/hash/hash.js +252 -0
- package/dist/hash/hashString.d.ts +13 -0
- package/dist/hash/hashString.js +53 -0
- package/dist/hash/index.d.ts +8 -0
- package/dist/hash/index.js +8 -0
- package/dist/hash/stableStringify.d.ts +19 -0
- package/dist/hash/stableStringify.js +102 -0
- package/dist/id/index.d.ts +7 -0
- package/dist/id/index.js +7 -0
- package/dist/id/nanoid.d.ts +16 -0
- package/dist/id/nanoid.js +65 -0
- package/dist/id/uniqueId.d.ts +14 -0
- package/dist/id/uniqueId.js +20 -0
- package/dist/id/uuid.d.ts +25 -0
- package/dist/id/uuid.js +64 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +15 -8
- package/dist/internal/bytes.d.ts +11 -0
- package/dist/internal/bytes.js +33 -0
- package/dist/internal/codec.d.ts +11 -0
- package/dist/internal/codec.js +84 -0
- package/dist/internal/compare.d.ts +10 -0
- package/dist/internal/compare.js +26 -0
- package/dist/internal/crypto.d.ts +5 -0
- package/dist/internal/crypto.js +11 -0
- package/dist/internal/keys.d.ts +12 -0
- package/dist/internal/keys.js +23 -0
- package/dist/internal/kind.d.ts +44 -0
- package/dist/internal/kind.js +139 -0
- package/dist/internal/sparse.d.ts +51 -0
- package/dist/internal/sparse.js +104 -0
- package/dist/internal/text.d.ts +7 -0
- package/dist/internal/text.js +15 -0
- package/dist/internal/timer.d.ts +10 -0
- package/dist/internal/timer.js +17 -0
- package/dist/internal/truncate.d.ts +10 -0
- package/dist/internal/truncate.js +22 -0
- package/dist/internal/walk.d.ts +47 -0
- package/dist/internal/walk.js +100 -0
- package/dist/is/index.d.ts +8 -0
- package/dist/is/index.js +8 -0
- package/dist/is/isArrayLike.d.ts +18 -0
- package/dist/is/isArrayLike.js +25 -0
- package/dist/is/isError.d.ts +13 -0
- package/dist/is/isError.js +18 -0
- package/dist/is/isNil.d.ts +12 -0
- package/dist/is/isNil.js +14 -0
- package/dist/is/isPlainObject.d.ts +15 -0
- package/dist/is/isPlainObject.js +34 -0
- package/dist/number/index.d.ts +7 -0
- package/dist/number/index.js +7 -0
- package/dist/number/round.d.ts +86 -0
- package/dist/number/round.js +130 -0
- package/dist/number/stats.d.ts +52 -0
- package/dist/number/stats.js +115 -0
- package/dist/object/cloneDeep.d.ts +28 -0
- package/dist/object/cloneDeep.js +200 -0
- package/dist/object/index.d.ts +14 -0
- package/dist/object/index.js +13 -0
- package/dist/object/isEqual.d.ts +64 -0
- package/dist/object/isEqual.js +289 -0
- package/dist/object/matches.d.ts +40 -0
- package/dist/object/matches.js +284 -0
- package/dist/object/merge.d.ts +66 -0
- package/dist/object/merge.js +272 -0
- package/dist/object/parsePath.d.ts +22 -0
- package/dist/object/parsePath.js +111 -0
- package/dist/object/path.d.ts +85 -0
- package/dist/object/path.js +208 -0
- package/dist/object/pick.d.ts +91 -0
- package/dist/object/pick.js +180 -0
- package/dist/object/reshape.d.ts +73 -0
- package/dist/object/reshape.js +144 -0
- package/dist/random/index.d.ts +96 -32
- package/dist/random/index.js +215 -53
- package/dist/string/case.d.ts +71 -0
- package/dist/string/case.js +152 -0
- package/dist/string/fold.d.ts +35 -0
- package/dist/string/fold.js +100 -0
- package/dist/string/index.d.ts +6 -187
- package/dist/string/index.js +6 -224
- package/dist/string/truncate.d.ts +25 -0
- package/dist/string/truncate.js +44 -0
- package/dist/string/words.d.ts +27 -0
- package/dist/string/words.js +241 -0
- package/package.json +99 -51
- package/dist/collections/BTree.d.ts +0 -230
- package/dist/collections/BTree.js +0 -1143
- package/dist/collections/Heap.d.ts +0 -69
- package/dist/collections/Heap.js +0 -181
- package/dist/collections/LRUCache.d.ts +0 -83
- package/dist/collections/LRUCache.js +0 -139
- package/dist/collections/SortedMap.d.ts +0 -92
- package/dist/collections/SortedMap.js +0 -131
- package/dist/collections/SortedSet.d.ts +0 -69
- package/dist/collections/SortedSet.js +0 -99
- package/dist/collections/SortedTree.d.ts +0 -103
- package/dist/collections/SortedTree.js +0 -142
- package/dist/collections/SplayTree.d.ts +0 -107
- package/dist/collections/SplayTree.js +0 -351
- package/dist/collections/Trie.d.ts +0 -42
- package/dist/collections/Trie.js +0 -104
- package/dist/collections/abc.d.ts +0 -152
- package/dist/collections/abc.js +0 -39
- package/dist/collections/frozenset.d.ts +0 -19
- package/dist/collections/frozenset.js +0 -33
- package/dist/functools/index.d.ts +0 -106
- package/dist/functools/index.js +0 -203
- package/dist/globals/index.d.ts +0 -268
- package/dist/globals/index.js +0 -447
- package/dist/i18n/currency.d.ts +0 -27
- package/dist/i18n/currency.js +0 -100
- package/dist/i18n/date/index.d.ts +0 -210
- package/dist/i18n/date/index.js +0 -552
- package/dist/i18n/date/utils.d.ts +0 -64
- package/dist/i18n/date/utils.js +0 -192
- package/dist/i18n/duration.d.ts +0 -113
- package/dist/i18n/duration.js +0 -398
- package/dist/i18n/format.d.ts +0 -34
- package/dist/i18n/format.js +0 -378
- package/dist/i18n/index.d.ts +0 -9
- package/dist/i18n/index.js +0 -8
- package/dist/itertools/index.d.ts +0 -251
- package/dist/itertools/index.js +0 -434
- package/dist/math/index.d.ts +0 -79
- package/dist/math/index.js +0 -81
- package/dist/mod.d.ts +0 -1
- package/dist/mod.js +0 -1
- package/dist/operators/index.d.ts +0 -148
- package/dist/operators/index.js +0 -325
- package/dist/types.d.ts +0 -19
- package/dist/types.js +0 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A set whose values stay sorted, on the same B+ tree as {@link SortedMap}. It has `Set`'s core
|
|
3
|
+
* method names (`has`, `add`, `delete`, `keys`, ...), so it can be the argument of `Set`'s ES2025
|
|
4
|
+
* set algebra (`union`, `intersection`, ...) but has none of those methods itself. It iterates in
|
|
5
|
+
* order, and adds `first`, `last`, `lower`, `higher`, `floor`, `ceiling`, `at`, `rank` and range
|
|
6
|
+
* queries in O(log n). Values the comparator calls equal are the same value: `add` of one keeps the
|
|
7
|
+
* value already there. A `-0` is stored as `+0`, as `Set` does. With the default comparator, values
|
|
8
|
+
* are numbers, bigints or strings: `NaN` throws `RangeError`, and `null`, `undefined` and other
|
|
9
|
+
* values throw `TypeError`; pass a comparator to order them.
|
|
10
|
+
*
|
|
11
|
+
* Every lookup runs the comparator, so `has` of a value it cannot order throws instead of returning
|
|
12
|
+
* `false`. The same goes for `Set` methods that call `has` on a `SortedSet` argument: with the
|
|
13
|
+
* default comparator, `new Set(['x']).isSubsetOf(new SortedSet([1]))` throws `TypeError`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const ids = new SortedSet([30, 10, 20, 10])
|
|
18
|
+
* ;[...ids] // [10, 20, 30]
|
|
19
|
+
* ids.higher(10) // 20
|
|
20
|
+
* ids.rank(25) // 2
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare class SortedSet<T = unknown> {
|
|
24
|
+
#private;
|
|
25
|
+
/**
|
|
26
|
+
* Create a set holding `values`; when values repeat, the first one seen is kept.
|
|
27
|
+
* @param values Initial values. `null` means none, as for `Set`.
|
|
28
|
+
* @param compareFn Comparator. Defaults to the primitive order (numbers, bigints and strings).
|
|
29
|
+
* @throws {TypeError} when `values` is not iterable or the comparator cannot order a value.
|
|
30
|
+
* @throws {RangeError} when `values` is a huge sparse array, or holds `NaN` under the default
|
|
31
|
+
* comparator.
|
|
32
|
+
*/
|
|
33
|
+
constructor(values?: Iterable<T> | null, compareFn?: ((a: T, b: T) => number) | null);
|
|
34
|
+
/** The number of values. */
|
|
35
|
+
get size(): number;
|
|
36
|
+
/** `'SortedSet'`, for `Object.prototype.toString`. */
|
|
37
|
+
get [Symbol.toStringTag](): string;
|
|
38
|
+
/**
|
|
39
|
+
* Insert `value` unless an equal value is present. O(log n).
|
|
40
|
+
* @returns `this`
|
|
41
|
+
* @throws {TypeError} when the comparator cannot order `value`; the set is unchanged.
|
|
42
|
+
*/
|
|
43
|
+
add(value: T): this;
|
|
44
|
+
/** Whether a value equal to `value` is present. O(log n). */
|
|
45
|
+
has(value: T): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Remove the value equal to `value`. O(log n).
|
|
48
|
+
* @returns Whether it was present.
|
|
49
|
+
*/
|
|
50
|
+
delete(value: T): boolean;
|
|
51
|
+
/** Remove every value. */
|
|
52
|
+
clear(): void;
|
|
53
|
+
/** The smallest value, or `undefined` when empty. */
|
|
54
|
+
first(): T | undefined;
|
|
55
|
+
/** The largest value, or `undefined` when empty. */
|
|
56
|
+
last(): T | undefined;
|
|
57
|
+
/** The greatest value below `value`, or `undefined`. */
|
|
58
|
+
lower(value: T): T | undefined;
|
|
59
|
+
/** The least value above `value`, or `undefined`. */
|
|
60
|
+
higher(value: T): T | undefined;
|
|
61
|
+
/** The greatest value at or below `value`, or `undefined`. */
|
|
62
|
+
floor(value: T): T | undefined;
|
|
63
|
+
/** The least value at or above `value`, or `undefined`. */
|
|
64
|
+
ceiling(value: T): T | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* The value at `index` in order, with `Array.prototype.at` rules, or `undefined` out of range.
|
|
67
|
+
* O(log n).
|
|
68
|
+
*/
|
|
69
|
+
at(index: number): T | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* How many values sort before `value`: its index when present, else where it would go. O(log n).
|
|
72
|
+
* @throws {TypeError} when the comparator cannot order `value`.
|
|
73
|
+
*/
|
|
74
|
+
rank(value: T): number;
|
|
75
|
+
/**
|
|
76
|
+
* The values in `[from, to)`, or `[from, to]` with `inclusiveEnd`, in order.
|
|
77
|
+
* @param options `inclusiveEnd` includes `to` (default false); `limit` caps how many values are
|
|
78
|
+
* collected (a non-negative integer or `Infinity`, the default).
|
|
79
|
+
* @throws {TypeError} when `options` is neither `undefined` nor an object, `limit` is not a
|
|
80
|
+
* number, or the comparator cannot order `from` or `to`.
|
|
81
|
+
* @throws {RangeError} when `limit` is a number but not a non-negative integer or `Infinity`.
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* new SortedSet([1, 2, 3, 4]).valuesBetween(2, 4) // [2, 3]
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
valuesBetween(from: T, to: T, options?: {
|
|
88
|
+
inclusiveEnd?: boolean;
|
|
89
|
+
limit?: number;
|
|
90
|
+
}): T[];
|
|
91
|
+
/** The values, largest first. */
|
|
92
|
+
valuesDescending(): IteratorObject<T>;
|
|
93
|
+
/** The values, in order. */
|
|
94
|
+
values(): IteratorObject<T>;
|
|
95
|
+
/** The values, in order, as `Set.prototype.keys` gives them. */
|
|
96
|
+
keys(): IteratorObject<T>;
|
|
97
|
+
/** `[value, value]` pairs, in order, as `Set.prototype.entries` gives them. */
|
|
98
|
+
entries(): IteratorObject<[T, T]>;
|
|
99
|
+
/** Call `callback(value, value, set)` for each value, in order. */
|
|
100
|
+
forEach(callback: (value: T, key: T, set: this) => void, thisArg?: unknown): void;
|
|
101
|
+
/** The values, in order. */
|
|
102
|
+
[Symbol.iterator](): IteratorObject<T>;
|
|
103
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { createSetMap, insertIfAbsent } from './sorted-map.js';
|
|
2
|
+
/**
|
|
3
|
+
* A set whose values stay sorted, on the same B+ tree as {@link SortedMap}. It has `Set`'s core
|
|
4
|
+
* method names (`has`, `add`, `delete`, `keys`, ...), so it can be the argument of `Set`'s ES2025
|
|
5
|
+
* set algebra (`union`, `intersection`, ...) but has none of those methods itself. It iterates in
|
|
6
|
+
* order, and adds `first`, `last`, `lower`, `higher`, `floor`, `ceiling`, `at`, `rank` and range
|
|
7
|
+
* queries in O(log n). Values the comparator calls equal are the same value: `add` of one keeps the
|
|
8
|
+
* value already there. A `-0` is stored as `+0`, as `Set` does. With the default comparator, values
|
|
9
|
+
* are numbers, bigints or strings: `NaN` throws `RangeError`, and `null`, `undefined` and other
|
|
10
|
+
* values throw `TypeError`; pass a comparator to order them.
|
|
11
|
+
*
|
|
12
|
+
* Every lookup runs the comparator, so `has` of a value it cannot order throws instead of returning
|
|
13
|
+
* `false`. The same goes for `Set` methods that call `has` on a `SortedSet` argument: with the
|
|
14
|
+
* default comparator, `new Set(['x']).isSubsetOf(new SortedSet([1]))` throws `TypeError`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const ids = new SortedSet([30, 10, 20, 10])
|
|
19
|
+
* ;[...ids] // [10, 20, 30]
|
|
20
|
+
* ids.higher(10) // 20
|
|
21
|
+
* ids.rank(25) // 2
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export class SortedSet {
|
|
25
|
+
#map;
|
|
26
|
+
/**
|
|
27
|
+
* Create a set holding `values`; when values repeat, the first one seen is kept.
|
|
28
|
+
* @param values Initial values. `null` means none, as for `Set`.
|
|
29
|
+
* @param compareFn Comparator. Defaults to the primitive order (numbers, bigints and strings).
|
|
30
|
+
* @throws {TypeError} when `values` is not iterable or the comparator cannot order a value.
|
|
31
|
+
* @throws {RangeError} when `values` is a huge sparse array, or holds `NaN` under the default
|
|
32
|
+
* comparator.
|
|
33
|
+
*/
|
|
34
|
+
constructor(values, compareFn) {
|
|
35
|
+
this.#map = createSetMap(values, compareFn);
|
|
36
|
+
}
|
|
37
|
+
/** The number of values. */
|
|
38
|
+
get size() {
|
|
39
|
+
return this.#map.size;
|
|
40
|
+
}
|
|
41
|
+
/** `'SortedSet'`, for `Object.prototype.toString`. */
|
|
42
|
+
get [Symbol.toStringTag]() {
|
|
43
|
+
return 'SortedSet';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Insert `value` unless an equal value is present. O(log n).
|
|
47
|
+
* @returns `this`
|
|
48
|
+
* @throws {TypeError} when the comparator cannot order `value`; the set is unchanged.
|
|
49
|
+
*/
|
|
50
|
+
add(value) {
|
|
51
|
+
insertIfAbsent(this.#map, value, true);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
/** Whether a value equal to `value` is present. O(log n). */
|
|
55
|
+
has(value) {
|
|
56
|
+
return this.#map.has(value);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Remove the value equal to `value`. O(log n).
|
|
60
|
+
* @returns Whether it was present.
|
|
61
|
+
*/
|
|
62
|
+
delete(value) {
|
|
63
|
+
return this.#map.delete(value);
|
|
64
|
+
}
|
|
65
|
+
/** Remove every value. */
|
|
66
|
+
clear() {
|
|
67
|
+
this.#map.clear();
|
|
68
|
+
}
|
|
69
|
+
/** The smallest value, or `undefined` when empty. */
|
|
70
|
+
first() {
|
|
71
|
+
return this.#map.firstKey();
|
|
72
|
+
}
|
|
73
|
+
/** The largest value, or `undefined` when empty. */
|
|
74
|
+
last() {
|
|
75
|
+
return this.#map.lastKey();
|
|
76
|
+
}
|
|
77
|
+
/** The greatest value below `value`, or `undefined`. */
|
|
78
|
+
lower(value) {
|
|
79
|
+
return this.#map.lower(value)?.[0];
|
|
80
|
+
}
|
|
81
|
+
/** The least value above `value`, or `undefined`. */
|
|
82
|
+
higher(value) {
|
|
83
|
+
return this.#map.higher(value)?.[0];
|
|
84
|
+
}
|
|
85
|
+
/** The greatest value at or below `value`, or `undefined`. */
|
|
86
|
+
floor(value) {
|
|
87
|
+
return this.#map.floor(value)?.[0];
|
|
88
|
+
}
|
|
89
|
+
/** The least value at or above `value`, or `undefined`. */
|
|
90
|
+
ceiling(value) {
|
|
91
|
+
return this.#map.ceiling(value)?.[0];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The value at `index` in order, with `Array.prototype.at` rules, or `undefined` out of range.
|
|
95
|
+
* O(log n).
|
|
96
|
+
*/
|
|
97
|
+
at(index) {
|
|
98
|
+
return this.#map.at(index)?.[0];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* How many values sort before `value`: its index when present, else where it would go. O(log n).
|
|
102
|
+
* @throws {TypeError} when the comparator cannot order `value`.
|
|
103
|
+
*/
|
|
104
|
+
rank(value) {
|
|
105
|
+
return this.#map.rank(value);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The values in `[from, to)`, or `[from, to]` with `inclusiveEnd`, in order.
|
|
109
|
+
* @param options `inclusiveEnd` includes `to` (default false); `limit` caps how many values are
|
|
110
|
+
* collected (a non-negative integer or `Infinity`, the default).
|
|
111
|
+
* @throws {TypeError} when `options` is neither `undefined` nor an object, `limit` is not a
|
|
112
|
+
* number, or the comparator cannot order `from` or `to`.
|
|
113
|
+
* @throws {RangeError} when `limit` is a number but not a non-negative integer or `Infinity`.
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* new SortedSet([1, 2, 3, 4]).valuesBetween(2, 4) // [2, 3]
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
valuesBetween(from, to, options) {
|
|
120
|
+
return this.#map.entriesBetween(from, to, options).map(([v]) => v);
|
|
121
|
+
}
|
|
122
|
+
/** The values, largest first. */
|
|
123
|
+
valuesDescending() {
|
|
124
|
+
return this.#map.entriesDescending().map(([v]) => v);
|
|
125
|
+
}
|
|
126
|
+
/** The values, in order. */
|
|
127
|
+
values() {
|
|
128
|
+
return this.#map.keys();
|
|
129
|
+
}
|
|
130
|
+
/** The values, in order, as `Set.prototype.keys` gives them. */
|
|
131
|
+
keys() {
|
|
132
|
+
return this.#map.keys();
|
|
133
|
+
}
|
|
134
|
+
/** `[value, value]` pairs, in order, as `Set.prototype.entries` gives them. */
|
|
135
|
+
entries() {
|
|
136
|
+
return this.#map.keys().map((v) => [v, v]);
|
|
137
|
+
}
|
|
138
|
+
/** Call `callback(value, value, set)` for each value, in order. */
|
|
139
|
+
forEach(callback, thisArg) {
|
|
140
|
+
for (const v of this.values())
|
|
141
|
+
Reflect.apply(callback, thisArg, [v, v, this]);
|
|
142
|
+
}
|
|
143
|
+
/** The values, in order. */
|
|
144
|
+
[Symbol.iterator]() {
|
|
145
|
+
return this.values();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An ordered map on a splay tree, a self-adjusting binary search tree that moves what you read to
|
|
3
|
+
* the root, so recently used keys are quick to reach again. Insertion, lookup and removal take
|
|
4
|
+
* O(log n) amortized time. It has `Map`'s method names, iterates in key order, and treats keys the
|
|
5
|
+
* comparator calls equal as the same key. `get` and `has` splay with probability 0.5 (a randomized
|
|
6
|
+
* splay tree); `firstKey`, `lastKey`, `lower`, `higher` and iterator re-seeks always splay. With
|
|
7
|
+
* the default comparator, keys are numbers, bigints or strings: `NaN` throws `RangeError`, and
|
|
8
|
+
* `null`, `undefined` and other values throw `TypeError`; pass a comparator to order them. A
|
|
9
|
+
* comparator that returns anything but a finite number throws `TypeError`, and a comparator that
|
|
10
|
+
* throws leaves every entry in place.
|
|
11
|
+
*
|
|
12
|
+
* Iterators capture a structural version; splaying bumps it. A stale iterator re-seeks by splaying
|
|
13
|
+
* its last yielded key's successor (O(log n) amortized), and an iterator left open holds nothing
|
|
14
|
+
* that later reads or writes wait on.
|
|
15
|
+
*
|
|
16
|
+
* @see {@link https://en.wikipedia.org/wiki/Splay_tree Splay tree}
|
|
17
|
+
* @see {@link https://web.archive.org/web/20220930173835/http://www14.in.tum.de/personen/albers/papers/ipl02.pdf Randomized Splay Trees}
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const tree = new SplayTree([
|
|
21
|
+
* [3, 'c'],
|
|
22
|
+
* [1, 'a']
|
|
23
|
+
* ])
|
|
24
|
+
* tree.set(2, 'b')
|
|
25
|
+
* ;[...tree.keys()] // [1, 2, 3]
|
|
26
|
+
* tree.lower(2) // [1, 'a']
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class SplayTree<K, V = unknown> {
|
|
30
|
+
#private;
|
|
31
|
+
/**
|
|
32
|
+
* Create a tree holding `entries`, inserted in order.
|
|
33
|
+
* @param entries Initial `[key, value]` pairs. `null` means none, as for `Map`.
|
|
34
|
+
* @param compareFn Key comparator. Defaults to the primitive order (numbers, bigints and strings).
|
|
35
|
+
* @throws {TypeError} when `entries` is not iterable or holds something that is not an entry.
|
|
36
|
+
*/
|
|
37
|
+
constructor(entries?: Iterable<readonly [K, V]> | null, compareFn?: ((a: K, b: K) => number) | null);
|
|
38
|
+
/** The number of entries. */
|
|
39
|
+
get size(): number;
|
|
40
|
+
/** `'SplayTree'`, for `Object.prototype.toString`. */
|
|
41
|
+
get [Symbol.toStringTag](): string;
|
|
42
|
+
/** The value for `key`, or `undefined`. May splay the key to the root. */
|
|
43
|
+
get(key: K): V | undefined;
|
|
44
|
+
/** Whether `key` is present. May splay the key to the root. */
|
|
45
|
+
has(key: K): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Insert or replace `key`, splaying it to the root.
|
|
48
|
+
* @returns `this`
|
|
49
|
+
*/
|
|
50
|
+
set(key: K, value: V): this;
|
|
51
|
+
/**
|
|
52
|
+
* Remove `key`.
|
|
53
|
+
* @returns Whether it was present.
|
|
54
|
+
*/
|
|
55
|
+
delete(key: K): boolean;
|
|
56
|
+
/** Remove every entry. */
|
|
57
|
+
clear(): void;
|
|
58
|
+
/** The smallest key, or `undefined` when empty. Splays it to the root. */
|
|
59
|
+
firstKey(): K | undefined;
|
|
60
|
+
/** The largest key, or `undefined` when empty. Splays it to the root. */
|
|
61
|
+
lastKey(): K | undefined;
|
|
62
|
+
/** The entry with the greatest key below `key`, or `undefined`. Splays it to the root. */
|
|
63
|
+
lower(key: K): [K, V] | undefined;
|
|
64
|
+
/** The entry with the least key above `key`, or `undefined`. Splays it to the root. */
|
|
65
|
+
higher(key: K): [K, V] | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Top-down splay of `key` (Sleator and Tarjan). Bumps the structural version so open
|
|
68
|
+
* iterators re-seek from their last key. A comparator that throws leaves every entry in place.
|
|
69
|
+
* @see {@link https://doi.org/10.1145%2F3828.3835 Self-Adjusting Binary Search Trees}
|
|
70
|
+
*/
|
|
71
|
+
splay(key: K): void;
|
|
72
|
+
/** The keys, in order. */
|
|
73
|
+
keys(): IteratorObject<K>;
|
|
74
|
+
/** The values, in key order. */
|
|
75
|
+
values(): IteratorObject<V>;
|
|
76
|
+
/** `[key, value]` pairs, in key order. */
|
|
77
|
+
entries(): IteratorObject<[K, V]>;
|
|
78
|
+
/** Call `callback(value, key, tree)` for each entry, in key order. */
|
|
79
|
+
forEach(callback: (value: V, key: K, tree: this) => void, thisArg?: unknown): void;
|
|
80
|
+
/** `[key, value]` pairs, in key order. */
|
|
81
|
+
[Symbol.iterator](): IteratorObject<[K, V]>;
|
|
82
|
+
}
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { defaultCompare } from '../internal/compare.js';
|
|
2
|
+
import { requireIterable } from './internal/iterable.js';
|
|
3
|
+
class Node {
|
|
4
|
+
key;
|
|
5
|
+
value;
|
|
6
|
+
left;
|
|
7
|
+
right;
|
|
8
|
+
constructor(key, value) {
|
|
9
|
+
this.key = key;
|
|
10
|
+
this.value = value;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* An ordered map on a splay tree, a self-adjusting binary search tree that moves what you read to
|
|
15
|
+
* the root, so recently used keys are quick to reach again. Insertion, lookup and removal take
|
|
16
|
+
* O(log n) amortized time. It has `Map`'s method names, iterates in key order, and treats keys the
|
|
17
|
+
* comparator calls equal as the same key. `get` and `has` splay with probability 0.5 (a randomized
|
|
18
|
+
* splay tree); `firstKey`, `lastKey`, `lower`, `higher` and iterator re-seeks always splay. With
|
|
19
|
+
* the default comparator, keys are numbers, bigints or strings: `NaN` throws `RangeError`, and
|
|
20
|
+
* `null`, `undefined` and other values throw `TypeError`; pass a comparator to order them. A
|
|
21
|
+
* comparator that returns anything but a finite number throws `TypeError`, and a comparator that
|
|
22
|
+
* throws leaves every entry in place.
|
|
23
|
+
*
|
|
24
|
+
* Iterators capture a structural version; splaying bumps it. A stale iterator re-seeks by splaying
|
|
25
|
+
* its last yielded key's successor (O(log n) amortized), and an iterator left open holds nothing
|
|
26
|
+
* that later reads or writes wait on.
|
|
27
|
+
*
|
|
28
|
+
* @see {@link https://en.wikipedia.org/wiki/Splay_tree Splay tree}
|
|
29
|
+
* @see {@link https://web.archive.org/web/20220930173835/http://www14.in.tum.de/personen/albers/papers/ipl02.pdf Randomized Splay Trees}
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const tree = new SplayTree([
|
|
33
|
+
* [3, 'c'],
|
|
34
|
+
* [1, 'a']
|
|
35
|
+
* ])
|
|
36
|
+
* tree.set(2, 'b')
|
|
37
|
+
* ;[...tree.keys()] // [1, 2, 3]
|
|
38
|
+
* tree.lower(2) // [1, 'a']
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class SplayTree {
|
|
42
|
+
#root;
|
|
43
|
+
#compareFn;
|
|
44
|
+
#size = 0;
|
|
45
|
+
#version = 0;
|
|
46
|
+
/**
|
|
47
|
+
* Create a tree holding `entries`, inserted in order.
|
|
48
|
+
* @param entries Initial `[key, value]` pairs. `null` means none, as for `Map`.
|
|
49
|
+
* @param compareFn Key comparator. Defaults to the primitive order (numbers, bigints and strings).
|
|
50
|
+
* @throws {TypeError} when `entries` is not iterable or holds something that is not an entry.
|
|
51
|
+
*/
|
|
52
|
+
constructor(entries, compareFn) {
|
|
53
|
+
this.#compareFn = compareFn ?? defaultCompare;
|
|
54
|
+
if (entries == null)
|
|
55
|
+
return;
|
|
56
|
+
for (const entry of requireIterable(entries)) {
|
|
57
|
+
if (Object(entry) !== entry)
|
|
58
|
+
throw new TypeError('entries must be [key, value] pairs');
|
|
59
|
+
this.set(entry[0], entry[1]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** The number of entries. */
|
|
63
|
+
get size() {
|
|
64
|
+
return this.#size;
|
|
65
|
+
}
|
|
66
|
+
/** `'SplayTree'`, for `Object.prototype.toString`. */
|
|
67
|
+
get [Symbol.toStringTag]() {
|
|
68
|
+
return 'SplayTree';
|
|
69
|
+
}
|
|
70
|
+
/** The value for `key`, or `undefined`. May splay the key to the root. */
|
|
71
|
+
get(key) {
|
|
72
|
+
return this.#lookup(key)?.value;
|
|
73
|
+
}
|
|
74
|
+
/** Whether `key` is present. May splay the key to the root. */
|
|
75
|
+
has(key) {
|
|
76
|
+
return this.#lookup(key) !== undefined;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Insert or replace `key`, splaying it to the root.
|
|
80
|
+
* @returns `this`
|
|
81
|
+
*/
|
|
82
|
+
set(key, value) {
|
|
83
|
+
if (!this.#root) {
|
|
84
|
+
this.#cmp(key, key);
|
|
85
|
+
this.#root = new Node(key, value);
|
|
86
|
+
this.#size = 1;
|
|
87
|
+
this.#version++;
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
this.splay(key);
|
|
91
|
+
const rank = this.#cmp(key, this.#root.key);
|
|
92
|
+
if (rank === 0) {
|
|
93
|
+
this.#root.value = value;
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
const node = new Node(key, value);
|
|
97
|
+
if (rank > 0) {
|
|
98
|
+
node.left = this.#root;
|
|
99
|
+
node.right = this.#root.right;
|
|
100
|
+
this.#root.right = undefined;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
node.right = this.#root;
|
|
104
|
+
node.left = this.#root.left;
|
|
105
|
+
this.#root.left = undefined;
|
|
106
|
+
}
|
|
107
|
+
this.#root = node;
|
|
108
|
+
this.#size++;
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Remove `key`.
|
|
113
|
+
* @returns Whether it was present.
|
|
114
|
+
*/
|
|
115
|
+
delete(key) {
|
|
116
|
+
if (!this.#root)
|
|
117
|
+
return false;
|
|
118
|
+
this.splay(key);
|
|
119
|
+
if (this.#cmp(key, this.#root.key) !== 0)
|
|
120
|
+
return false;
|
|
121
|
+
if (!this.#root.left) {
|
|
122
|
+
this.#root = this.#root.right;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const max = this.#splayMax(this.#root.left);
|
|
126
|
+
max.right = this.#root.right;
|
|
127
|
+
this.#root = max;
|
|
128
|
+
}
|
|
129
|
+
this.#size--;
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
/** Remove every entry. */
|
|
133
|
+
clear() {
|
|
134
|
+
this.#root = undefined;
|
|
135
|
+
this.#size = 0;
|
|
136
|
+
this.#version++;
|
|
137
|
+
}
|
|
138
|
+
/** The smallest key, or `undefined` when empty. Splays it to the root. */
|
|
139
|
+
firstKey() {
|
|
140
|
+
if (!this.#root)
|
|
141
|
+
return undefined;
|
|
142
|
+
let n = this.#root;
|
|
143
|
+
while (n.left)
|
|
144
|
+
n = n.left;
|
|
145
|
+
const key = n.key;
|
|
146
|
+
this.splay(key);
|
|
147
|
+
return key;
|
|
148
|
+
}
|
|
149
|
+
/** The largest key, or `undefined` when empty. Splays it to the root. */
|
|
150
|
+
lastKey() {
|
|
151
|
+
if (!this.#root)
|
|
152
|
+
return undefined;
|
|
153
|
+
let n = this.#root;
|
|
154
|
+
while (n.right)
|
|
155
|
+
n = n.right;
|
|
156
|
+
const key = n.key;
|
|
157
|
+
this.splay(key);
|
|
158
|
+
return key;
|
|
159
|
+
}
|
|
160
|
+
/** The entry with the greatest key below `key`, or `undefined`. Splays it to the root. */
|
|
161
|
+
lower(key) {
|
|
162
|
+
if (!this.#root)
|
|
163
|
+
return undefined;
|
|
164
|
+
this.splay(key);
|
|
165
|
+
if (this.#cmp(this.#root.key, key) < 0)
|
|
166
|
+
return [this.#root.key, this.#root.value];
|
|
167
|
+
let n = this.#root.left;
|
|
168
|
+
if (!n)
|
|
169
|
+
return undefined;
|
|
170
|
+
while (n.right)
|
|
171
|
+
n = n.right;
|
|
172
|
+
this.splay(n.key);
|
|
173
|
+
return [n.key, n.value];
|
|
174
|
+
}
|
|
175
|
+
/** The entry with the least key above `key`, or `undefined`. Splays it to the root. */
|
|
176
|
+
higher(key) {
|
|
177
|
+
if (!this.#root)
|
|
178
|
+
return undefined;
|
|
179
|
+
this.splay(key);
|
|
180
|
+
if (this.#cmp(this.#root.key, key) > 0)
|
|
181
|
+
return [this.#root.key, this.#root.value];
|
|
182
|
+
let n = this.#root.right;
|
|
183
|
+
if (!n)
|
|
184
|
+
return undefined;
|
|
185
|
+
while (n.left)
|
|
186
|
+
n = n.left;
|
|
187
|
+
this.splay(n.key);
|
|
188
|
+
return [n.key, n.value];
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Top-down splay of `key` (Sleator and Tarjan). Bumps the structural version so open
|
|
192
|
+
* iterators re-seek from their last key. A comparator that throws leaves every entry in place.
|
|
193
|
+
* @see {@link https://doi.org/10.1145%2F3828.3835 Self-Adjusting Binary Search Trees}
|
|
194
|
+
*/
|
|
195
|
+
splay(key) {
|
|
196
|
+
if (!this.#root)
|
|
197
|
+
return;
|
|
198
|
+
const stub = {};
|
|
199
|
+
let left = stub;
|
|
200
|
+
let right = stub;
|
|
201
|
+
let root = this.#root;
|
|
202
|
+
try {
|
|
203
|
+
for (;;) {
|
|
204
|
+
const rank = this.#cmp(key, root.key);
|
|
205
|
+
if (rank < 0) {
|
|
206
|
+
if (!root.left)
|
|
207
|
+
break;
|
|
208
|
+
if (this.#cmp(key, root.left.key) < 0) {
|
|
209
|
+
const tmp = root.left;
|
|
210
|
+
root.left = tmp.right;
|
|
211
|
+
tmp.right = root;
|
|
212
|
+
root = tmp;
|
|
213
|
+
if (!root.left)
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
right.left = root;
|
|
217
|
+
right = root;
|
|
218
|
+
root = root.left;
|
|
219
|
+
}
|
|
220
|
+
else if (rank > 0) {
|
|
221
|
+
if (!root.right)
|
|
222
|
+
break;
|
|
223
|
+
if (this.#cmp(key, root.right.key) > 0) {
|
|
224
|
+
const tmp = root.right;
|
|
225
|
+
root.right = tmp.left;
|
|
226
|
+
tmp.left = root;
|
|
227
|
+
root = tmp;
|
|
228
|
+
if (!root.right)
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
left.right = root;
|
|
232
|
+
left = root;
|
|
233
|
+
root = root.right;
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
left.right = root.left;
|
|
242
|
+
right.left = root.right;
|
|
243
|
+
root.left = stub.right;
|
|
244
|
+
root.right = stub.left;
|
|
245
|
+
this.#root = root;
|
|
246
|
+
this.#version++;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** The keys, in order. */
|
|
250
|
+
keys() {
|
|
251
|
+
return this.#inorder().map((n) => n.key);
|
|
252
|
+
}
|
|
253
|
+
/** The values, in key order. */
|
|
254
|
+
values() {
|
|
255
|
+
return this.#inorder().map((n) => n.value);
|
|
256
|
+
}
|
|
257
|
+
/** `[key, value]` pairs, in key order. */
|
|
258
|
+
entries() {
|
|
259
|
+
return this.#inorder().map((n) => [n.key, n.value]);
|
|
260
|
+
}
|
|
261
|
+
/** Call `callback(value, key, tree)` for each entry, in key order. */
|
|
262
|
+
forEach(callback, thisArg) {
|
|
263
|
+
for (const [k, v] of this.entries())
|
|
264
|
+
Reflect.apply(callback, thisArg, [v, k, this]);
|
|
265
|
+
}
|
|
266
|
+
/** `[key, value]` pairs, in key order. */
|
|
267
|
+
[Symbol.iterator]() {
|
|
268
|
+
return this.entries();
|
|
269
|
+
}
|
|
270
|
+
*#inorder() {
|
|
271
|
+
let version = this.#version;
|
|
272
|
+
let lastKey;
|
|
273
|
+
let haveLast = false;
|
|
274
|
+
const stack = [];
|
|
275
|
+
let n = this.#root;
|
|
276
|
+
// Splaying or mutating restructures the tree, so the stack is stale. Splay the successor of
|
|
277
|
+
// the last yielded key to the root: a plain descent would pay O(height) at every step.
|
|
278
|
+
const reseek = () => {
|
|
279
|
+
stack.length = 0;
|
|
280
|
+
n = haveLast ? undefined : this.#root;
|
|
281
|
+
if (haveLast) {
|
|
282
|
+
this.higher(lastKey);
|
|
283
|
+
const root = this.#root;
|
|
284
|
+
if (root && this.#cmp(root.key, lastKey) > 0)
|
|
285
|
+
stack.push(root);
|
|
286
|
+
}
|
|
287
|
+
version = this.#version;
|
|
288
|
+
};
|
|
289
|
+
for (;;) {
|
|
290
|
+
if (version !== this.#version)
|
|
291
|
+
reseek();
|
|
292
|
+
while (n) {
|
|
293
|
+
stack.push(n);
|
|
294
|
+
n = n.left;
|
|
295
|
+
}
|
|
296
|
+
const current = stack.pop();
|
|
297
|
+
if (current === undefined)
|
|
298
|
+
return;
|
|
299
|
+
lastKey = current.key;
|
|
300
|
+
haveLast = true;
|
|
301
|
+
n = current.right;
|
|
302
|
+
yield current;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Top-down splay of the largest key in the subtree at `root`, returning the new subtree root,
|
|
307
|
+
* which has no right child. It follows right links only and never calls the comparator, so it
|
|
308
|
+
* cannot throw while `delete` holds a detached subtree.
|
|
309
|
+
*/
|
|
310
|
+
#splayMax(root) {
|
|
311
|
+
const stub = {};
|
|
312
|
+
let left = stub;
|
|
313
|
+
while (root.right) {
|
|
314
|
+
const tmp = root.right;
|
|
315
|
+
root.right = tmp.left;
|
|
316
|
+
tmp.left = root;
|
|
317
|
+
root = tmp;
|
|
318
|
+
if (!root.right)
|
|
319
|
+
break;
|
|
320
|
+
left.right = root;
|
|
321
|
+
left = root;
|
|
322
|
+
root = root.right;
|
|
323
|
+
}
|
|
324
|
+
left.right = root.left;
|
|
325
|
+
root.left = stub.right;
|
|
326
|
+
return root;
|
|
327
|
+
}
|
|
328
|
+
#lookup(key) {
|
|
329
|
+
if (!this.#root)
|
|
330
|
+
return undefined;
|
|
331
|
+
if (Math.random() < 0.5) {
|
|
332
|
+
this.splay(key);
|
|
333
|
+
return this.#cmp(key, this.#root.key) === 0 ? this.#root : undefined;
|
|
334
|
+
}
|
|
335
|
+
return this.#find(key);
|
|
336
|
+
}
|
|
337
|
+
#cmp(a, b) {
|
|
338
|
+
const rank = this.#compareFn(a, b);
|
|
339
|
+
if (typeof rank !== 'number' || !Number.isFinite(rank)) {
|
|
340
|
+
throw new TypeError('comparator must return a finite number');
|
|
341
|
+
}
|
|
342
|
+
return rank;
|
|
343
|
+
}
|
|
344
|
+
#find(key) {
|
|
345
|
+
let n = this.#root;
|
|
346
|
+
while (n) {
|
|
347
|
+
const c = this.#cmp(key, n.key);
|
|
348
|
+
if (c === 0)
|
|
349
|
+
return n;
|
|
350
|
+
n = c < 0 ? n.left : n.right;
|
|
351
|
+
}
|
|
352
|
+
return undefined;
|
|
353
|
+
}
|
|
354
|
+
}
|