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.
Files changed (216) hide show
  1. package/README.md +397 -91
  2. package/dist/array/index.d.ts +9 -0
  3. package/dist/array/index.js +9 -0
  4. package/dist/array/list.d.ts +99 -0
  5. package/dist/array/list.js +133 -0
  6. package/dist/array/sets.d.ts +130 -0
  7. package/dist/array/sets.js +213 -0
  8. package/dist/async/index.d.ts +6 -0
  9. package/dist/async/index.js +6 -0
  10. package/dist/async/retry.d.ts +38 -0
  11. package/dist/async/retry.js +56 -0
  12. package/dist/async/sleep.d.ts +42 -0
  13. package/dist/async/sleep.js +76 -0
  14. package/dist/collections/bisect.d.ts +103 -0
  15. package/dist/collections/bisect.js +157 -0
  16. package/dist/collections/deque.d.ts +67 -97
  17. package/dist/collections/deque.js +197 -256
  18. package/dist/collections/entries.d.ts +89 -0
  19. package/dist/collections/entries.js +131 -0
  20. package/dist/collections/frozen-set.d.ts +42 -0
  21. package/dist/collections/frozen-set.js +64 -0
  22. package/dist/collections/group.d.ts +141 -0
  23. package/dist/collections/group.js +241 -0
  24. package/dist/collections/heap.d.ts +64 -0
  25. package/dist/collections/heap.js +205 -0
  26. package/dist/collections/index.d.ts +15 -623
  27. package/dist/collections/index.js +14 -844
  28. package/dist/collections/internal/arrayKeys.d.ts +19 -0
  29. package/dist/collections/internal/arrayKeys.js +83 -0
  30. package/dist/collections/internal/invariants.d.ts +4 -0
  31. package/dist/collections/internal/invariants.js +12 -0
  32. package/dist/collections/internal/iterable.d.ts +25 -0
  33. package/dist/collections/internal/iterable.js +62 -0
  34. package/dist/collections/iterate.d.ts +162 -0
  35. package/dist/collections/iterate.js +188 -0
  36. package/dist/collections/lru-cache.d.ts +58 -0
  37. package/dist/collections/lru-cache.js +164 -0
  38. package/dist/collections/order.d.ts +19 -0
  39. package/dist/collections/order.js +38 -0
  40. package/dist/collections/shape.d.ts +32 -0
  41. package/dist/collections/shape.js +86 -0
  42. package/dist/collections/sorted-map.d.ts +171 -0
  43. package/dist/collections/sorted-map.js +845 -0
  44. package/dist/collections/sorted-set.d.ts +103 -0
  45. package/dist/collections/sorted-set.js +147 -0
  46. package/dist/collections/splay-tree.d.ts +82 -0
  47. package/dist/collections/splay-tree.js +354 -0
  48. package/dist/collections/trie.d.ts +58 -0
  49. package/dist/collections/trie.js +196 -0
  50. package/dist/decimal/currency.d.ts +211 -0
  51. package/dist/decimal/currency.js +321 -0
  52. package/dist/decimal/decimal.d.ts +299 -0
  53. package/dist/decimal/decimal.js +660 -0
  54. package/dist/decimal/index.d.ts +11 -148
  55. package/dist/decimal/index.js +10 -410
  56. package/dist/decimal/internal/bits.d.ts +2 -0
  57. package/dist/decimal/internal/bits.js +7 -0
  58. package/dist/decimal/internal/echo.d.ts +4 -0
  59. package/dist/decimal/internal/echo.js +6 -0
  60. package/dist/decimal/internal/isqrt.d.ts +9 -0
  61. package/dist/decimal/internal/isqrt.js +34 -0
  62. package/dist/decimal/internal/locale.d.ts +7 -0
  63. package/dist/decimal/internal/locale.js +24 -0
  64. package/dist/decimal/internal/minor-units.d.ts +2 -0
  65. package/dist/decimal/internal/minor-units.js +33 -0
  66. package/dist/decimal/internal/pow10.d.ts +24 -0
  67. package/dist/decimal/internal/pow10.js +96 -0
  68. package/dist/encoding/base64.d.ts +39 -0
  69. package/dist/encoding/base64.js +53 -0
  70. package/dist/encoding/hex.d.ts +23 -0
  71. package/dist/encoding/hex.js +34 -0
  72. package/dist/encoding/index.d.ts +6 -0
  73. package/dist/encoding/index.js +6 -0
  74. package/dist/function/debounce.d.ts +68 -0
  75. package/dist/function/debounce.js +203 -0
  76. package/dist/function/index.d.ts +6 -0
  77. package/dist/function/index.js +6 -0
  78. package/dist/function/shared.d.ts +2 -0
  79. package/dist/function/shared.js +5 -0
  80. package/dist/function/wrap.d.ts +130 -0
  81. package/dist/function/wrap.js +113 -0
  82. package/dist/hash/digest.d.ts +18 -0
  83. package/dist/hash/digest.js +26 -0
  84. package/dist/hash/hash.d.ts +22 -0
  85. package/dist/hash/hash.js +252 -0
  86. package/dist/hash/hashString.d.ts +13 -0
  87. package/dist/hash/hashString.js +53 -0
  88. package/dist/hash/index.d.ts +8 -0
  89. package/dist/hash/index.js +8 -0
  90. package/dist/hash/stableStringify.d.ts +19 -0
  91. package/dist/hash/stableStringify.js +102 -0
  92. package/dist/id/index.d.ts +7 -0
  93. package/dist/id/index.js +7 -0
  94. package/dist/id/nanoid.d.ts +16 -0
  95. package/dist/id/nanoid.js +65 -0
  96. package/dist/id/uniqueId.d.ts +14 -0
  97. package/dist/id/uniqueId.js +20 -0
  98. package/dist/id/uuid.d.ts +25 -0
  99. package/dist/id/uuid.js +64 -0
  100. package/dist/index.d.ts +15 -8
  101. package/dist/index.js +15 -8
  102. package/dist/internal/bytes.d.ts +11 -0
  103. package/dist/internal/bytes.js +33 -0
  104. package/dist/internal/codec.d.ts +11 -0
  105. package/dist/internal/codec.js +84 -0
  106. package/dist/internal/compare.d.ts +10 -0
  107. package/dist/internal/compare.js +26 -0
  108. package/dist/internal/crypto.d.ts +5 -0
  109. package/dist/internal/crypto.js +11 -0
  110. package/dist/internal/keys.d.ts +12 -0
  111. package/dist/internal/keys.js +23 -0
  112. package/dist/internal/kind.d.ts +44 -0
  113. package/dist/internal/kind.js +139 -0
  114. package/dist/internal/sparse.d.ts +51 -0
  115. package/dist/internal/sparse.js +104 -0
  116. package/dist/internal/text.d.ts +7 -0
  117. package/dist/internal/text.js +15 -0
  118. package/dist/internal/timer.d.ts +10 -0
  119. package/dist/internal/timer.js +17 -0
  120. package/dist/internal/truncate.d.ts +10 -0
  121. package/dist/internal/truncate.js +22 -0
  122. package/dist/internal/walk.d.ts +47 -0
  123. package/dist/internal/walk.js +100 -0
  124. package/dist/is/index.d.ts +8 -0
  125. package/dist/is/index.js +8 -0
  126. package/dist/is/isArrayLike.d.ts +18 -0
  127. package/dist/is/isArrayLike.js +25 -0
  128. package/dist/is/isError.d.ts +13 -0
  129. package/dist/is/isError.js +18 -0
  130. package/dist/is/isNil.d.ts +12 -0
  131. package/dist/is/isNil.js +14 -0
  132. package/dist/is/isPlainObject.d.ts +15 -0
  133. package/dist/is/isPlainObject.js +34 -0
  134. package/dist/number/index.d.ts +7 -0
  135. package/dist/number/index.js +7 -0
  136. package/dist/number/round.d.ts +86 -0
  137. package/dist/number/round.js +130 -0
  138. package/dist/number/stats.d.ts +52 -0
  139. package/dist/number/stats.js +115 -0
  140. package/dist/object/cloneDeep.d.ts +28 -0
  141. package/dist/object/cloneDeep.js +200 -0
  142. package/dist/object/index.d.ts +14 -0
  143. package/dist/object/index.js +13 -0
  144. package/dist/object/isEqual.d.ts +64 -0
  145. package/dist/object/isEqual.js +289 -0
  146. package/dist/object/matches.d.ts +40 -0
  147. package/dist/object/matches.js +284 -0
  148. package/dist/object/merge.d.ts +66 -0
  149. package/dist/object/merge.js +272 -0
  150. package/dist/object/parsePath.d.ts +22 -0
  151. package/dist/object/parsePath.js +111 -0
  152. package/dist/object/path.d.ts +85 -0
  153. package/dist/object/path.js +208 -0
  154. package/dist/object/pick.d.ts +91 -0
  155. package/dist/object/pick.js +180 -0
  156. package/dist/object/reshape.d.ts +73 -0
  157. package/dist/object/reshape.js +144 -0
  158. package/dist/random/index.d.ts +96 -32
  159. package/dist/random/index.js +215 -53
  160. package/dist/string/case.d.ts +71 -0
  161. package/dist/string/case.js +152 -0
  162. package/dist/string/fold.d.ts +35 -0
  163. package/dist/string/fold.js +100 -0
  164. package/dist/string/index.d.ts +6 -187
  165. package/dist/string/index.js +6 -224
  166. package/dist/string/truncate.d.ts +25 -0
  167. package/dist/string/truncate.js +44 -0
  168. package/dist/string/words.d.ts +27 -0
  169. package/dist/string/words.js +241 -0
  170. package/package.json +99 -51
  171. package/dist/collections/BTree.d.ts +0 -230
  172. package/dist/collections/BTree.js +0 -1143
  173. package/dist/collections/Heap.d.ts +0 -69
  174. package/dist/collections/Heap.js +0 -181
  175. package/dist/collections/LRUCache.d.ts +0 -83
  176. package/dist/collections/LRUCache.js +0 -139
  177. package/dist/collections/SortedMap.d.ts +0 -92
  178. package/dist/collections/SortedMap.js +0 -131
  179. package/dist/collections/SortedSet.d.ts +0 -69
  180. package/dist/collections/SortedSet.js +0 -99
  181. package/dist/collections/SortedTree.d.ts +0 -103
  182. package/dist/collections/SortedTree.js +0 -142
  183. package/dist/collections/SplayTree.d.ts +0 -107
  184. package/dist/collections/SplayTree.js +0 -351
  185. package/dist/collections/Trie.d.ts +0 -42
  186. package/dist/collections/Trie.js +0 -104
  187. package/dist/collections/abc.d.ts +0 -152
  188. package/dist/collections/abc.js +0 -39
  189. package/dist/collections/frozenset.d.ts +0 -19
  190. package/dist/collections/frozenset.js +0 -33
  191. package/dist/functools/index.d.ts +0 -106
  192. package/dist/functools/index.js +0 -203
  193. package/dist/globals/index.d.ts +0 -268
  194. package/dist/globals/index.js +0 -447
  195. package/dist/i18n/currency.d.ts +0 -27
  196. package/dist/i18n/currency.js +0 -100
  197. package/dist/i18n/date/index.d.ts +0 -210
  198. package/dist/i18n/date/index.js +0 -552
  199. package/dist/i18n/date/utils.d.ts +0 -64
  200. package/dist/i18n/date/utils.js +0 -192
  201. package/dist/i18n/duration.d.ts +0 -113
  202. package/dist/i18n/duration.js +0 -398
  203. package/dist/i18n/format.d.ts +0 -34
  204. package/dist/i18n/format.js +0 -378
  205. package/dist/i18n/index.d.ts +0 -9
  206. package/dist/i18n/index.js +0 -8
  207. package/dist/itertools/index.d.ts +0 -251
  208. package/dist/itertools/index.js +0 -434
  209. package/dist/math/index.d.ts +0 -79
  210. package/dist/math/index.js +0 -81
  211. package/dist/mod.d.ts +0 -1
  212. package/dist/mod.js +0 -1
  213. package/dist/operators/index.d.ts +0 -148
  214. package/dist/operators/index.js +0 -325
  215. package/dist/types.d.ts +0 -19
  216. 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
+ }