atomic-fns 1.1.7 → 1.2.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 +51 -12
- package/dist/collections/BTree.d.ts +11 -10
- package/dist/collections/BTree.js +58 -80
- package/dist/collections/Heap.js +1 -1
- package/dist/collections/LRUCache.d.ts +6 -3
- package/dist/collections/LRUCache.js +24 -11
- package/dist/collections/SortedMap.js +2 -2
- package/dist/collections/SortedTree.d.ts +2 -2
- package/dist/collections/SortedTree.js +3 -2
- package/dist/collections/SplayTree.d.ts +7 -5
- package/dist/collections/SplayTree.js +39 -26
- package/dist/collections/Trie.d.ts +1 -1
- package/dist/collections/Trie.js +26 -26
- package/dist/collections/deque.d.ts +1 -1
- package/dist/collections/deque.js +17 -10
- package/dist/collections/frozenset.js +4 -1
- package/dist/collections/index.d.ts +13 -32
- package/dist/collections/index.js +210 -82
- package/dist/decimal/index.d.ts +5 -2
- package/dist/decimal/index.js +63 -27
- package/dist/functools/index.d.ts +6 -30
- package/dist/functools/index.js +24 -56
- package/dist/globals/index.d.ts +3 -20
- package/dist/globals/index.js +23 -39
- package/dist/i18n/currency.d.ts +3 -0
- package/dist/i18n/currency.js +22 -7
- package/dist/i18n/date/index.d.ts +17 -10
- package/dist/i18n/date/index.js +79 -58
- package/dist/i18n/date/utils.d.ts +4 -5
- package/dist/i18n/date/utils.js +15 -113
- package/dist/i18n/duration.d.ts +11 -10
- package/dist/i18n/duration.js +38 -32
- package/dist/i18n/format.d.ts +5 -2
- package/dist/i18n/format.js +81 -209
- package/dist/i18n/index.d.ts +2 -1
- package/dist/itertools/index.d.ts +9 -13
- package/dist/itertools/index.js +38 -41
- package/dist/math/index.d.ts +10 -27
- package/dist/math/index.js +16 -33
- package/dist/operators/index.d.ts +1 -5
- package/dist/operators/index.js +60 -40
- package/dist/random/index.js +9 -6
- package/dist/string/index.d.ts +1 -1
- package/dist/string/index.js +2 -4
- package/dist/types.d.ts +3 -3
- package/package.json +16 -21
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# atomic-fns
|
|
2
2
|
|
|
3
|
-
[Read the Docs](https://atomic-stack
|
|
3
|
+
[Read the Docs](https://jsr.io/@atomic-stack/atomic-fns/doc)
|
|
4
4
|
|
|
5
5
|
## Like Lodash, but in TypeScript and for ESNext.
|
|
6
6
|
|
|
@@ -17,7 +17,7 @@ You may prefer this library because:
|
|
|
17
17
|
|
|
18
18
|
## Docs
|
|
19
19
|
|
|
20
|
-
📖 Available at [atomic-fns](https://atomic-stack
|
|
20
|
+
📖 Available at [atomic-fns](https://jsr.io/@atomic-stack/atomic-fns/doc)
|
|
21
21
|
|
|
22
22
|
## Get Started
|
|
23
23
|
|
|
@@ -29,6 +29,12 @@ To install the package you need to have [npm](https://www.npmjs.com/get-npm) (or
|
|
|
29
29
|
npm install atomic-fns
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
It is also on [JSR](https://jsr.io/@atomic-stack/atomic-fns), for Deno and other runtimes that read TypeScript directly:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx jsr add @atomic-stack/atomic-fns
|
|
36
|
+
```
|
|
37
|
+
|
|
32
38
|
## How to use
|
|
33
39
|
|
|
34
40
|
Just import any function or class you need.
|
|
@@ -36,7 +42,7 @@ Just import any function or class you need.
|
|
|
36
42
|
```js
|
|
37
43
|
import { sorted, times, uniqueId } from 'atomic-fns'
|
|
38
44
|
|
|
39
|
-
times(5, (i) => i)
|
|
45
|
+
[...times(5, (i) => i)]
|
|
40
46
|
// -> [0, 1, 2, 3, 4]
|
|
41
47
|
|
|
42
48
|
sorted([4, 3, 2, 1])
|
|
@@ -47,7 +53,7 @@ uniqueId('user_')
|
|
|
47
53
|
...
|
|
48
54
|
```
|
|
49
55
|
|
|
50
|
-
See the full list of [modules](https://atomic-stack
|
|
56
|
+
See the full list of [modules](https://jsr.io/@atomic-stack/atomic-fns/doc).
|
|
51
57
|
|
|
52
58
|
## Data model
|
|
53
59
|
This library features a data model similar to [Python](https://docs.python.org/3/reference/datamodel.html#special-method-names) but not always. Only the missing parts have been implemented, while respecting the JS standards.
|
|
@@ -67,7 +73,7 @@ When working with objects, functions in this library use these custom operators
|
|
|
67
73
|
|
|
68
74
|
## New Types
|
|
69
75
|
|
|
70
|
-
[`Decimal`](https://atomic-stack
|
|
76
|
+
[`Decimal`](https://jsr.io/@atomic-stack/atomic-fns/doc/decimal/~/Decimal) provides support for correct rounded floating point arithmetic, with arbitrary precision.
|
|
71
77
|
|
|
72
78
|
This fixes precision issues with float arithmetic, for example:
|
|
73
79
|
```
|
|
@@ -81,15 +87,48 @@ decimal('0.1').add('0.1').add('0.1').toNumber()
|
|
|
81
87
|
Some common base interfaces and typing patterns you may have seen like `Optional`, `Result`, `Comparable`, `Iterator`, and others.
|
|
82
88
|
|
|
83
89
|
### Sorted Containers
|
|
84
|
-
- [SortedSet](https://atomic-stack
|
|
85
|
-
- [SortedMap](https://atomic-stack
|
|
86
|
-
- [SortedTree](https://atomic-stack
|
|
90
|
+
- [SortedSet](https://jsr.io/@atomic-stack/atomic-fns/doc/collections/~/SortedSet)
|
|
91
|
+
- [SortedMap](https://jsr.io/@atomic-stack/atomic-fns/doc/collections/~/SortedMap)
|
|
92
|
+
- [SortedTree](https://jsr.io/@atomic-stack/atomic-fns/doc/collections/~/SortedTree)
|
|
87
93
|
|
|
88
94
|
### Other Containers
|
|
89
|
-
- [Deque](https://atomic-stack
|
|
90
|
-
- [FrozenSet](https://atomic-stack
|
|
91
|
-
- [LRUCache](https://atomic-stack
|
|
92
|
-
|
|
95
|
+
- [Deque](https://jsr.io/@atomic-stack/atomic-fns/doc/collections/~/Deque)
|
|
96
|
+
- [FrozenSet](https://jsr.io/@atomic-stack/atomic-fns/doc/collections/~/FrozenSet)
|
|
97
|
+
- [LRUCache](https://jsr.io/@atomic-stack/atomic-fns/doc/collections/~/LRUCache)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
## Upgrading to 1.2
|
|
101
|
+
|
|
102
|
+
1.2 removes the exports that only repeated a native function, along with the deprecated `id` and the experimental `cache` decorator.
|
|
103
|
+
|
|
104
|
+
| Removed | Use instead |
|
|
105
|
+
| ------------------------------- | -------------------------------------- |
|
|
106
|
+
| `isArray` | `Array.isArray` |
|
|
107
|
+
| `isInteger` | `Number.isInteger` |
|
|
108
|
+
| `keys`, `values` | `Object.keys`, `Object.values` |
|
|
109
|
+
| `bind` | `Function.prototype.bind` |
|
|
110
|
+
| `callAsync` | `new Promise` |
|
|
111
|
+
| `floor`, `ceil`, `log2` | `Math.floor`, `Math.ceil`, `Math.log2` |
|
|
112
|
+
| `cloneArray`, `cloneTypedArray` | `clone`, `structuredClone`, `slice` |
|
|
113
|
+
| `IterableIterator` | `Iterator.from` |
|
|
114
|
+
| `id` | `identity` |
|
|
115
|
+
| `cache` | `memoize` |
|
|
116
|
+
|
|
117
|
+
The rest of 1.2 fixes bugs. These fixes change results that code may have worked around:
|
|
118
|
+
|
|
119
|
+
- `eq`, `lt`, `lte`, `gt` and `gte` now ask an object's own method first and honor a `false` answer, so comparing two `Decimal` values gives the right answer. `eq(0, -0)` is `true`.
|
|
120
|
+
- `deepEqual` and `shallowEqual` tell kinds apart, and compare Dates, RegExps and typed arrays by value.
|
|
121
|
+
- `merge` copies plain objects from its sources and skips `__proto__`, so it no longer changes a source or `Object.prototype`.
|
|
122
|
+
- `difference` removes the values of the other arrays, where it returned a symmetric difference.
|
|
123
|
+
- `uniq` with an iteratee returns the original elements, not the computed keys, and `sortedUniq` sorts them by that key.
|
|
124
|
+
- `memoize` caches an `undefined` result.
|
|
125
|
+
- `divmod` follows Python, so the quotient and remainder add back up to the input.
|
|
126
|
+
- `bisect` and `insort` find the right position in every case.
|
|
127
|
+
- `Deque.set` throws `KeyError` past the end, where the value was lost.
|
|
128
|
+
- A frozen `BTree` refuses `remove`, as it does `set`.
|
|
129
|
+
- `IntlDate` adds months with a clamp to the last day of the month, keeps the wall clock across DST for calendar units, and `diff` counts calendar months, quarters and years. `exact` keeps the averaged result.
|
|
130
|
+
- `addDuration` and `subDuration` read a date-only string as local time, as `IntlDate` does.
|
|
131
|
+
- `format('Z')` prints the numeric offset, such as `-05:00`.
|
|
93
132
|
|
|
94
133
|
## Contributing
|
|
95
134
|
If you want to contribute to the project and make it better, your help is very welcome. Contributing is also a great way to learn more about social coding on Github, new technologies and and their ecosystems and how to make constructive, helpful bug reports, feature requests and the noblest of all contributions: a good, clean pull request. You will be listed as a **Champion** on the official site as well.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Comparer } from '../operators/index.js';
|
|
1
|
+
import { type Comparer } from '../operators/index.js';
|
|
2
2
|
import { Mapping } from './abc.js';
|
|
3
|
-
import { Iteratee } from '../types';
|
|
3
|
+
import type { Iteratee } from '../types.js';
|
|
4
4
|
export declare class BTree<K = any, V = any> extends Mapping<K, V> {
|
|
5
5
|
private root;
|
|
6
6
|
count: number;
|
|
@@ -14,8 +14,7 @@ export declare class BTree<K = any, V = any> extends Mapping<K, V> {
|
|
|
14
14
|
* Initializes an empty B+ tree.
|
|
15
15
|
* @param {?Iterable<[K, V]>} [entries] The initial key value pairs.
|
|
16
16
|
* @param compareFn Custom function to compare pairs of elements in the tree.
|
|
17
|
-
* If not specified,
|
|
18
|
-
* @param entries A set of key-value pairs to initialize the tree
|
|
17
|
+
* If not specified, {@link operators.compare} is used.
|
|
19
18
|
* @param {number} [maxNodeSize=64] Branching factor (maximum items or children per node)
|
|
20
19
|
* Must be in range 4..256. If undefined or <4 then default is used; if >256 then 256.
|
|
21
20
|
*/
|
|
@@ -64,6 +63,7 @@ export declare class BTree<K = any, V = any> extends Mapping<K, V> {
|
|
|
64
63
|
* starts at the next higher key (according to the comparator).
|
|
65
64
|
* @param reusedArray Optional array used repeatedly to store key-value
|
|
66
65
|
* pairs, to avoid creating a new array on every iteration.
|
|
66
|
+
* Note: changing the tree during iteration may skip or repeat keys.
|
|
67
67
|
*/
|
|
68
68
|
entries(lowestKey?: K, reusedArray?: Array<K | V>): IterableIterator<[K, V]>;
|
|
69
69
|
/** Returns an iterator that provides items in reversed order.
|
|
@@ -74,6 +74,7 @@ export declare class BTree<K = any, V = any> extends Mapping<K, V> {
|
|
|
74
74
|
* pairs, to avoid creating a new array on every iteration.
|
|
75
75
|
* @param skipHighest Iff this flag is true and the highestKey exists in the
|
|
76
76
|
* collection, the pair matching highestKey is skipped, not iterated.
|
|
77
|
+
* Note: changing the tree during iteration may skip or repeat keys.
|
|
77
78
|
*/
|
|
78
79
|
reversed(highestKey?: K, reusedArray?: Array<K | V>, skipHighest?: boolean): IterableIterator<[K, V]>;
|
|
79
80
|
private findPath;
|
|
@@ -128,8 +129,8 @@ export declare class BTree<K = any, V = any> extends Mapping<K, V> {
|
|
|
128
129
|
* */
|
|
129
130
|
floor(key: K, reusedArray?: [K, V]): [K, V] | undefined;
|
|
130
131
|
/** Returns the key-value pair associated with the supplied key if it exists
|
|
131
|
-
* or the
|
|
132
|
-
*
|
|
132
|
+
* or the next higher pair otherwise. If there is no next higher pair,
|
|
133
|
+
* undefined is returned.
|
|
133
134
|
* @param key The key to search for.
|
|
134
135
|
* @param reusedArray Optional array used repeatedly to store key-value pairs, to
|
|
135
136
|
* avoid creating a new array each time you call this method.
|
|
@@ -142,8 +143,9 @@ export declare class BTree<K = any, V = any> extends Mapping<K, V> {
|
|
|
142
143
|
* @param high This method returns when a key larger than this is reached.
|
|
143
144
|
* @param includeHigh If the `high` key is present, its pair will be included
|
|
144
145
|
* in the output if and only if this parameter is true. Note: if the
|
|
145
|
-
* `low` key is present, it is
|
|
146
|
-
*
|
|
146
|
+
* `low` key is present, it is included in the output unless `low`
|
|
147
|
+
* equals `high` and this parameter is false.
|
|
148
|
+
* @param maxLength Length limit. keysRange will stop scanning the tree when
|
|
147
149
|
* the array reaches this size.
|
|
148
150
|
* @description Computational complexity: O(result.length + log size)
|
|
149
151
|
*/
|
|
@@ -191,7 +193,7 @@ export declare class BTree<K = any, V = any> extends Mapping<K, V> {
|
|
|
191
193
|
* function can return `{value:v}` to change the value associated
|
|
192
194
|
* with the current key, `{delete:true}` to delete the current pair,
|
|
193
195
|
* `{done:R}` to stop early with result R, or it can return nothing
|
|
194
|
-
* (undefined or {}) to cause no effect and continue iterating.
|
|
196
|
+
* (undefined, null or {}) to cause no effect and continue iterating.
|
|
195
197
|
* `{done:R}` can be combined with one of the other two commands.
|
|
196
198
|
* The third argument `counter` is the number of items iterated
|
|
197
199
|
* previously; it equals 0 when `onFound` is called the first time.
|
|
@@ -219,7 +221,6 @@ export declare class BTree<K = any, V = any> extends Mapping<K, V> {
|
|
|
219
221
|
* BTree object and its leaf nodes (zero if there are no internal nodes). */
|
|
220
222
|
get height(): number;
|
|
221
223
|
/** Makes the object read-only to ensure it is not accidentally modified.
|
|
222
|
-
* Freezing does not have to be permanent; unfreeze() reverses the effect.
|
|
223
224
|
* This is accomplished by replacing mutator functions with a function
|
|
224
225
|
* that throws an Error. Compared to using a property (e.g. this.isFrozen)
|
|
225
226
|
* this implementation gives better performance in non-frozen BTrees.
|
|
@@ -43,7 +43,7 @@ class BNode {
|
|
|
43
43
|
/// ////////////////////////////////////////////////////////////////////////
|
|
44
44
|
// Shared methods /////////////////////////////////////////////////////////
|
|
45
45
|
maxKey() {
|
|
46
|
-
return this.keys
|
|
46
|
+
return this.keys.at(-1);
|
|
47
47
|
}
|
|
48
48
|
// If key not found, returns i^failXor where i is the insertion index.
|
|
49
49
|
// Callers that don't care whether there was a match will set failXor=0.
|
|
@@ -62,11 +62,9 @@ class BNode {
|
|
|
62
62
|
return mid;
|
|
63
63
|
else {
|
|
64
64
|
// c is NaN or otherwise invalid
|
|
65
|
-
// eslint-disable-next-line
|
|
66
65
|
if (key === key)
|
|
67
66
|
// at least the search key is not NaN
|
|
68
|
-
return keys.length;
|
|
69
|
-
// eslint-disable-next-line
|
|
67
|
+
return keys.length ^ failXor;
|
|
70
68
|
else
|
|
71
69
|
throw new KeyError(`Btree found an invalid key: ${key}`);
|
|
72
70
|
}
|
|
@@ -152,7 +150,6 @@ class BNode {
|
|
|
152
150
|
else {
|
|
153
151
|
// This leaf node is full and must split
|
|
154
152
|
const newRightSibling = this.splitOffRightSide();
|
|
155
|
-
// eslint-disable-next-line
|
|
156
153
|
let target = this;
|
|
157
154
|
if (i > this.keys.length) {
|
|
158
155
|
i -= this.keys.length;
|
|
@@ -205,10 +202,8 @@ class BNode {
|
|
|
205
202
|
}
|
|
206
203
|
else {
|
|
207
204
|
v = this.reifyValues();
|
|
208
|
-
// eslint-disable-next-line
|
|
209
205
|
v.push(rhs.values.shift());
|
|
210
206
|
}
|
|
211
|
-
// eslint-disable-next-line
|
|
212
207
|
this.keys.push(rhs.keys.shift());
|
|
213
208
|
}
|
|
214
209
|
takeFromLeft(lhs) {
|
|
@@ -222,10 +217,8 @@ class BNode {
|
|
|
222
217
|
}
|
|
223
218
|
else {
|
|
224
219
|
v = this.reifyValues();
|
|
225
|
-
// eslint-disable-next-line
|
|
226
220
|
v.unshift(lhs.values.pop());
|
|
227
221
|
}
|
|
228
|
-
// eslint-disable-next-line
|
|
229
222
|
this.keys.unshift(lhs.keys.pop());
|
|
230
223
|
}
|
|
231
224
|
splitOffRightSide() {
|
|
@@ -256,14 +249,13 @@ class BNode {
|
|
|
256
249
|
iHigh++;
|
|
257
250
|
}
|
|
258
251
|
const keys = this.keys;
|
|
259
|
-
const values = this.values;
|
|
260
252
|
if (onFound !== undefined) {
|
|
261
253
|
for (let i = iLow; i < iHigh; i++) {
|
|
262
254
|
const key = keys[i];
|
|
263
|
-
const result = onFound(key, values[i], count++);
|
|
264
|
-
if (result
|
|
255
|
+
const result = onFound(key, this.values[i], count++);
|
|
256
|
+
if (result != null) {
|
|
265
257
|
if (editMode) {
|
|
266
|
-
if (key
|
|
258
|
+
if (!Object.is(key, keys[i]) || this.isShared)
|
|
267
259
|
throw new Error('BTree illegally changed or cloned in editRange');
|
|
268
260
|
if (result.delete) {
|
|
269
261
|
this.keys.splice(i, 1);
|
|
@@ -273,8 +265,8 @@ class BNode {
|
|
|
273
265
|
i--;
|
|
274
266
|
iHigh--;
|
|
275
267
|
}
|
|
276
|
-
else if (result
|
|
277
|
-
|
|
268
|
+
else if ('value' in Object(result)) {
|
|
269
|
+
this.reifyValues()[i] = result.value;
|
|
278
270
|
}
|
|
279
271
|
}
|
|
280
272
|
if (result.done !== undefined)
|
|
@@ -283,7 +275,7 @@ class BNode {
|
|
|
283
275
|
}
|
|
284
276
|
}
|
|
285
277
|
else
|
|
286
|
-
count += iHigh - iLow;
|
|
278
|
+
count += Math.max(iHigh - iLow, 0);
|
|
287
279
|
return count;
|
|
288
280
|
}
|
|
289
281
|
/** Adds entire contents of right-hand sibling (rhs is left unchanged) */
|
|
@@ -292,7 +284,7 @@ class BNode {
|
|
|
292
284
|
if (this.values === undefVals) {
|
|
293
285
|
if (rhs.values === undefVals)
|
|
294
286
|
return;
|
|
295
|
-
this.values = this.values.slice(0, this.keys.length);
|
|
287
|
+
this.values = this.values.slice(0, this.keys.length - rhs.keys.length);
|
|
296
288
|
}
|
|
297
289
|
this.values.push.apply(this.values, rhs.reifyValues());
|
|
298
290
|
}
|
|
@@ -318,8 +310,7 @@ export class BTree extends Mapping {
|
|
|
318
310
|
* Initializes an empty B+ tree.
|
|
319
311
|
* @param {?Iterable<[K, V]>} [entries] The initial key value pairs.
|
|
320
312
|
* @param compareFn Custom function to compare pairs of elements in the tree.
|
|
321
|
-
* If not specified,
|
|
322
|
-
* @param entries A set of key-value pairs to initialize the tree
|
|
313
|
+
* If not specified, {@link operators.compare} is used.
|
|
323
314
|
* @param {number} [maxNodeSize=64] Branching factor (maximum items or children per node)
|
|
324
315
|
* Must be in range 4..256. If undefined or <4 then default is used; if >256 then 256.
|
|
325
316
|
*/
|
|
@@ -365,7 +356,7 @@ export class BTree extends Mapping {
|
|
|
365
356
|
// private forEachPair<R = number>(callback: Iteratee<K, V>, initialCounter?: number): R | number {
|
|
366
357
|
// const low = this.minKey()
|
|
367
358
|
// const high = this.maxKey()
|
|
368
|
-
//
|
|
359
|
+
//
|
|
369
360
|
// return this.rangeForEach(low!, high, true, callback, initialCounter)
|
|
370
361
|
// }
|
|
371
362
|
/**
|
|
@@ -399,7 +390,7 @@ export class BTree extends Mapping {
|
|
|
399
390
|
return true;
|
|
400
391
|
}
|
|
401
392
|
add(key) {
|
|
402
|
-
return this.set(key, null);
|
|
393
|
+
return this.set(key, this.get(key, null));
|
|
403
394
|
}
|
|
404
395
|
/**
|
|
405
396
|
* Returns true if the key exists in the B+ tree, false if not.
|
|
@@ -407,7 +398,7 @@ export class BTree extends Mapping {
|
|
|
407
398
|
* @description Computational complexity: O(log size)
|
|
408
399
|
*/
|
|
409
400
|
contains(key) {
|
|
410
|
-
return this.
|
|
401
|
+
return this.rangeForEach(key, key, true) !== 0;
|
|
411
402
|
}
|
|
412
403
|
/**
|
|
413
404
|
* Removes a single key-value pair from the B+ tree.
|
|
@@ -425,6 +416,7 @@ export class BTree extends Mapping {
|
|
|
425
416
|
* starts at the next higher key (according to the comparator).
|
|
426
417
|
* @param reusedArray Optional array used repeatedly to store key-value
|
|
427
418
|
* pairs, to avoid creating a new array on every iteration.
|
|
419
|
+
* Note: changing the tree during iteration may skip or repeat keys.
|
|
428
420
|
*/
|
|
429
421
|
entries(lowestKey, reusedArray) {
|
|
430
422
|
const info = this.findPath(lowestKey);
|
|
@@ -434,7 +426,6 @@ export class BTree extends Mapping {
|
|
|
434
426
|
let state = reusedArray !== undefined ? 1 : 0;
|
|
435
427
|
let i = lowestKey === undefined ? -1 : leaf.indexOf(lowestKey, 0, this._compare) - 1;
|
|
436
428
|
return iterator(() => {
|
|
437
|
-
// eslint-disable-next-line
|
|
438
429
|
jump: while (true) {
|
|
439
430
|
switch (state) {
|
|
440
431
|
case 0:
|
|
@@ -444,32 +435,29 @@ export class BTree extends Mapping {
|
|
|
444
435
|
continue;
|
|
445
436
|
case 1:
|
|
446
437
|
if (++i < leaf.keys.length) {
|
|
447
|
-
// eslint-disable-next-line
|
|
448
438
|
reusedArray[0] = leaf.keys[i];
|
|
449
|
-
// eslint-disable-next-line
|
|
450
439
|
reusedArray[1] = leaf.values[i];
|
|
451
440
|
return { done: false, value: reusedArray };
|
|
452
441
|
}
|
|
453
442
|
state = 2;
|
|
454
|
-
// eslint-disable-next-line
|
|
455
443
|
case 2:
|
|
456
444
|
// Advance to the next leaf node
|
|
457
|
-
// eslint-disable-next-line
|
|
458
445
|
let level = -1;
|
|
459
446
|
while (true) {
|
|
460
447
|
if (++level >= nodequeue.length) {
|
|
461
448
|
state = 3;
|
|
462
|
-
// eslint-disable-next-line
|
|
463
449
|
continue jump;
|
|
464
450
|
}
|
|
465
451
|
if (++nodeindex[level] < nodequeue[level].length)
|
|
466
452
|
break;
|
|
467
453
|
}
|
|
454
|
+
// Keys removed during iteration can leave this path empty.
|
|
468
455
|
for (; level > 0; level--) {
|
|
469
|
-
|
|
456
|
+
const parent = nodequeue[level][nodeindex[level]];
|
|
457
|
+
nodequeue[level - 1] = parent?.children ?? EmptyArray;
|
|
470
458
|
nodeindex[level - 1] = 0;
|
|
471
459
|
}
|
|
472
|
-
leaf = nodequeue[0][nodeindex[0]];
|
|
460
|
+
leaf = nodequeue[0][nodeindex[0]] ?? EmptyLeaf;
|
|
473
461
|
i = -1;
|
|
474
462
|
state = reusedArray !== undefined ? 1 : 0;
|
|
475
463
|
continue;
|
|
@@ -487,58 +475,53 @@ export class BTree extends Mapping {
|
|
|
487
475
|
* pairs, to avoid creating a new array on every iteration.
|
|
488
476
|
* @param skipHighest Iff this flag is true and the highestKey exists in the
|
|
489
477
|
* collection, the pair matching highestKey is skipped, not iterated.
|
|
478
|
+
* Note: changing the tree during iteration may skip or repeat keys.
|
|
490
479
|
*/
|
|
491
480
|
reversed(highestKey, reusedArray, skipHighest) {
|
|
492
|
-
|
|
493
|
-
highestKey = this.maxKey();
|
|
494
|
-
skipHighest = undefined;
|
|
495
|
-
if (highestKey === undefined)
|
|
496
|
-
return iterator(); // collection is empty
|
|
497
|
-
}
|
|
498
|
-
// eslint-disable-next-line
|
|
499
|
-
let { nodequeue, nodeindex, leaf } = this.findPath(highestKey) || this.findPath(this.maxKey());
|
|
481
|
+
let { nodequeue, nodeindex, leaf } = this.findPath(highestKey, true) || this.findPath(undefined, true);
|
|
500
482
|
assert(!nodequeue[0] || leaf === nodequeue[0][nodeindex[0]], 'wat!');
|
|
501
|
-
let i = leaf.
|
|
502
|
-
if (
|
|
503
|
-
i
|
|
483
|
+
let i = leaf.keys.length;
|
|
484
|
+
if (highestKey !== undefined) {
|
|
485
|
+
i = leaf.indexOf(highestKey, 0, this._compare);
|
|
486
|
+
if (!skipHighest && i < leaf.keys.length && this._compare(leaf.keys[i], highestKey) <= 0)
|
|
487
|
+
i++;
|
|
488
|
+
}
|
|
504
489
|
let state = reusedArray !== undefined ? 1 : 0;
|
|
505
490
|
return iterator(() => {
|
|
506
|
-
// eslint-disable-next-line
|
|
507
491
|
jump: while (true) {
|
|
508
492
|
switch (state) {
|
|
509
493
|
case 0:
|
|
510
|
-
|
|
494
|
+
i = Math.min(i, leaf.keys.length) - 1;
|
|
495
|
+
if (i >= 0)
|
|
511
496
|
return { done: false, value: [leaf.keys[i], leaf.values[i]] };
|
|
512
497
|
state = 2;
|
|
513
498
|
continue;
|
|
514
499
|
case 1:
|
|
515
|
-
|
|
516
|
-
|
|
500
|
+
i = Math.min(i, leaf.keys.length) - 1;
|
|
501
|
+
if (i >= 0) {
|
|
517
502
|
reusedArray[0] = leaf.keys[i];
|
|
518
|
-
// eslint-disable-next-line
|
|
519
503
|
reusedArray[1] = leaf.values[i];
|
|
520
504
|
return { done: false, value: reusedArray };
|
|
521
505
|
}
|
|
522
506
|
state = 2;
|
|
523
|
-
// eslint-disable-next-line
|
|
524
507
|
case 2:
|
|
525
508
|
// Advance to the next leaf node
|
|
526
|
-
// eslint-disable-next-line
|
|
527
509
|
let level = -1;
|
|
528
510
|
while (true) {
|
|
529
511
|
if (++level >= nodequeue.length) {
|
|
530
512
|
state = 3;
|
|
531
|
-
// eslint-disable-next-line
|
|
532
513
|
continue jump;
|
|
533
514
|
}
|
|
534
515
|
if (--nodeindex[level] >= 0)
|
|
535
516
|
break;
|
|
536
517
|
}
|
|
518
|
+
// Keys removed during iteration can leave this path empty.
|
|
537
519
|
for (; level > 0; level--) {
|
|
538
|
-
|
|
520
|
+
const parent = nodequeue[level][nodeindex[level]];
|
|
521
|
+
nodequeue[level - 1] = parent?.children ?? EmptyArray;
|
|
539
522
|
nodeindex[level - 1] = nodequeue[level - 1].length - 1;
|
|
540
523
|
}
|
|
541
|
-
leaf = nodequeue[0][nodeindex[0]];
|
|
524
|
+
leaf = nodequeue[0][nodeindex[0]] ?? EmptyLeaf;
|
|
542
525
|
i = leaf.keys.length;
|
|
543
526
|
state = reusedArray !== undefined ? 1 : 0;
|
|
544
527
|
continue;
|
|
@@ -548,7 +531,7 @@ export class BTree extends Mapping {
|
|
|
548
531
|
}
|
|
549
532
|
});
|
|
550
533
|
}
|
|
551
|
-
/* Used by entries() and
|
|
534
|
+
/* Used by entries() and reversed() to prepare to start iterating.
|
|
552
535
|
* It develops a "node queue" for each non-leaf level of the tree.
|
|
553
536
|
* Levels are numbered "bottom-up" so that level 0 is a list of leaf
|
|
554
537
|
* nodes from a low-level non-leaf node. The queue at a given level L
|
|
@@ -558,7 +541,7 @@ export class BTree extends Mapping {
|
|
|
558
541
|
* (However inside this function the order is reversed.)
|
|
559
542
|
* @private
|
|
560
543
|
*/
|
|
561
|
-
findPath(key) {
|
|
544
|
+
findPath(key, fromEnd = false) {
|
|
562
545
|
let nextnode = this.root;
|
|
563
546
|
let nodequeue, nodeindex;
|
|
564
547
|
if (nextnode.isLeaf) {
|
|
@@ -571,7 +554,10 @@ export class BTree extends Mapping {
|
|
|
571
554
|
nodeindex = [];
|
|
572
555
|
for (let d = 0; !nextnode.isLeaf; d++) {
|
|
573
556
|
nodequeue[d] = nextnode.children;
|
|
574
|
-
|
|
557
|
+
if (key !== undefined)
|
|
558
|
+
nodeindex[d] = nextnode.indexOf(key, 0, this._compare);
|
|
559
|
+
else
|
|
560
|
+
nodeindex[d] = fromEnd ? nodequeue[d].length - 1 : 0;
|
|
575
561
|
if (nodeindex[d] >= nodequeue[d].length)
|
|
576
562
|
return; // first key > maxKey()
|
|
577
563
|
nextnode = nodequeue[d][nodeindex[d]];
|
|
@@ -642,12 +628,7 @@ export class BTree extends Mapping {
|
|
|
642
628
|
}
|
|
643
629
|
/** Gets an array filled with the contents of the tree, sorted by key */
|
|
644
630
|
toArray() {
|
|
645
|
-
|
|
646
|
-
const max = this.maxKey();
|
|
647
|
-
const maxLength = 2147483647;
|
|
648
|
-
if (min !== undefined)
|
|
649
|
-
return this.keysRange(min, max, true, maxLength);
|
|
650
|
-
return [];
|
|
631
|
+
return [...this.entries()];
|
|
651
632
|
}
|
|
652
633
|
/** Gets a string representing the tree's data based on toArray(). */
|
|
653
634
|
toString() {
|
|
@@ -660,7 +641,7 @@ export class BTree extends Mapping {
|
|
|
660
641
|
* avoid creating a new array on every iteration.
|
|
661
642
|
*/
|
|
662
643
|
lowerBound(key, reusedArray) {
|
|
663
|
-
reusedArray
|
|
644
|
+
reusedArray ||= [];
|
|
664
645
|
if (key === undefined) {
|
|
665
646
|
return this.root.minPair(reusedArray);
|
|
666
647
|
}
|
|
@@ -680,7 +661,7 @@ export class BTree extends Mapping {
|
|
|
680
661
|
* avoid creating a new array each time you call this method.
|
|
681
662
|
*/
|
|
682
663
|
upperBound(key, reusedArray) {
|
|
683
|
-
reusedArray
|
|
664
|
+
reusedArray ||= [];
|
|
684
665
|
if (key === undefined) {
|
|
685
666
|
return this.root.maxPair(reusedArray);
|
|
686
667
|
}
|
|
@@ -704,8 +685,8 @@ export class BTree extends Mapping {
|
|
|
704
685
|
return this.root.getPairOrNextLower(key, this._compare, true, reusedArray || []);
|
|
705
686
|
}
|
|
706
687
|
/** Returns the key-value pair associated with the supplied key if it exists
|
|
707
|
-
* or the
|
|
708
|
-
*
|
|
688
|
+
* or the next higher pair otherwise. If there is no next higher pair,
|
|
689
|
+
* undefined is returned.
|
|
709
690
|
* @param key The key to search for.
|
|
710
691
|
* @param reusedArray Optional array used repeatedly to store key-value pairs, to
|
|
711
692
|
* avoid creating a new array each time you call this method.
|
|
@@ -720,16 +701,18 @@ export class BTree extends Mapping {
|
|
|
720
701
|
* @param high This method returns when a key larger than this is reached.
|
|
721
702
|
* @param includeHigh If the `high` key is present, its pair will be included
|
|
722
703
|
* in the output if and only if this parameter is true. Note: if the
|
|
723
|
-
* `low` key is present, it is
|
|
724
|
-
*
|
|
704
|
+
* `low` key is present, it is included in the output unless `low`
|
|
705
|
+
* equals `high` and this parameter is false.
|
|
706
|
+
* @param maxLength Length limit. keysRange will stop scanning the tree when
|
|
725
707
|
* the array reaches this size.
|
|
726
708
|
* @description Computational complexity: O(result.length + log size)
|
|
727
709
|
*/
|
|
728
710
|
keysRange(low, high, includeHigh, maxLength = 0x3ffffff) {
|
|
729
711
|
const results = [];
|
|
730
712
|
this.root.forRange(low, high, includeHigh, false, this, 0, (k, v) => {
|
|
713
|
+
if (results.length >= maxLength)
|
|
714
|
+
return Break;
|
|
731
715
|
results.push([k, v]);
|
|
732
|
-
return results.length > maxLength ? Break : undefined;
|
|
733
716
|
});
|
|
734
717
|
return results;
|
|
735
718
|
}
|
|
@@ -743,8 +726,8 @@ export class BTree extends Mapping {
|
|
|
743
726
|
extend(entries) {
|
|
744
727
|
let added = 0;
|
|
745
728
|
for (const pair of entries) {
|
|
746
|
-
this.set(pair[0], pair[1] ?? null)
|
|
747
|
-
|
|
729
|
+
if (this.set(pair[0], pair[1] ?? null))
|
|
730
|
+
added++;
|
|
748
731
|
}
|
|
749
732
|
return added;
|
|
750
733
|
}
|
|
@@ -786,7 +769,7 @@ export class BTree extends Mapping {
|
|
|
786
769
|
* function can return `{value:v}` to change the value associated
|
|
787
770
|
* with the current key, `{delete:true}` to delete the current pair,
|
|
788
771
|
* `{done:R}` to stop early with result R, or it can return nothing
|
|
789
|
-
* (undefined or {}) to cause no effect and continue iterating.
|
|
772
|
+
* (undefined, null or {}) to cause no effect and continue iterating.
|
|
790
773
|
* `{done:R}` can be combined with one of the other two commands.
|
|
791
774
|
* The third argument `counter` is the number of items iterated
|
|
792
775
|
* previously; it equals 0 when `onFound` is called the first time.
|
|
@@ -850,18 +833,17 @@ export class BTree extends Mapping {
|
|
|
850
833
|
return height;
|
|
851
834
|
}
|
|
852
835
|
/** Makes the object read-only to ensure it is not accidentally modified.
|
|
853
|
-
* Freezing does not have to be permanent; unfreeze() reverses the effect.
|
|
854
836
|
* This is accomplished by replacing mutator functions with a function
|
|
855
837
|
* that throws an Error. Compared to using a property (e.g. this.isFrozen)
|
|
856
838
|
* this implementation gives better performance in non-frozen BTrees.
|
|
857
839
|
*/
|
|
858
840
|
freeze() {
|
|
859
841
|
const t = this;
|
|
860
|
-
// Note: all other mutators ultimately call set() or
|
|
842
|
+
// Note: all other mutators ultimately call set() or rangeUpdate()
|
|
861
843
|
// so we don't need to override those others.
|
|
862
844
|
t.clear =
|
|
863
845
|
t.set =
|
|
864
|
-
t.
|
|
846
|
+
t.rangeUpdate =
|
|
865
847
|
() => {
|
|
866
848
|
throw TypeError('Attempted to modify a frozen BTree');
|
|
867
849
|
};
|
|
@@ -918,12 +900,12 @@ class BNodeInternal extends BNode {
|
|
|
918
900
|
return this.children[0].minPair(reusedArray);
|
|
919
901
|
}
|
|
920
902
|
maxPair(reusedArray) {
|
|
921
|
-
return this.children
|
|
903
|
+
return this.children.at(-1).maxPair(reusedArray);
|
|
922
904
|
}
|
|
923
905
|
get(key, defaultValue, tree) {
|
|
924
906
|
const i = this.indexOf(key, 0, tree._compare);
|
|
925
907
|
const children = this.children;
|
|
926
|
-
return i < children.length ? children[i].get(key, defaultValue, tree) :
|
|
908
|
+
return i < children.length ? children[i].get(key, defaultValue, tree) : defaultValue;
|
|
927
909
|
}
|
|
928
910
|
getPairOrNextLower(key, compare, inclusive, reusedArray) {
|
|
929
911
|
const i = this.indexOf(key, 0, compare);
|
|
@@ -1006,9 +988,9 @@ class BNodeInternal extends BNode {
|
|
|
1006
988
|
}
|
|
1007
989
|
}
|
|
1008
990
|
const result = child.set(key, value, overwrite, tree);
|
|
991
|
+
this.keys[i] = child.maxKey();
|
|
1009
992
|
if (result === false)
|
|
1010
993
|
return false;
|
|
1011
|
-
this.keys[i] = child.maxKey();
|
|
1012
994
|
if (result === true)
|
|
1013
995
|
return true;
|
|
1014
996
|
// The child has split and `result` is a new right child... does it fit?
|
|
@@ -1051,18 +1033,14 @@ class BNodeInternal extends BNode {
|
|
|
1051
1033
|
// Reminder: parent node must update its copy of key for this node
|
|
1052
1034
|
// assert: neither node is shared
|
|
1053
1035
|
// assert rhs.keys.length > (maxNodeSize/2 && this.keys.length<maxNodeSize)
|
|
1054
|
-
// eslint-disable-next-line
|
|
1055
1036
|
this.keys.push(rhs.keys.shift());
|
|
1056
|
-
// eslint-disable-next-line
|
|
1057
1037
|
this.children.push(rhs.children.shift());
|
|
1058
1038
|
}
|
|
1059
1039
|
takeFromLeft(lhs) {
|
|
1060
1040
|
// Reminder: parent node must update its copy of key for this node
|
|
1061
1041
|
// assert: neither node is shared
|
|
1062
1042
|
// assert rhs.keys.length > (maxNodeSize/2 && this.keys.length<maxNodeSize)
|
|
1063
|
-
// eslint-disable-next-line
|
|
1064
1043
|
this.keys.unshift(lhs.keys.pop());
|
|
1065
|
-
// eslint-disable-next-line
|
|
1066
1044
|
this.children.unshift(lhs.children.pop());
|
|
1067
1045
|
}
|
|
1068
1046
|
/// //////////////////////////////////////////////////////////////////////////
|
package/dist/collections/Heap.js
CHANGED
|
@@ -87,7 +87,7 @@ export class Heap extends Collection {
|
|
|
87
87
|
* @return `true` if the item was removed.
|
|
88
88
|
*/
|
|
89
89
|
remove(item) {
|
|
90
|
-
const index = this.heap.indexOf(item);
|
|
90
|
+
const index = Number.isNaN(item) ? this.heap.findIndex(Number.isNaN) : this.heap.indexOf(item);
|
|
91
91
|
if (index < 0)
|
|
92
92
|
return false;
|
|
93
93
|
if (index === 0) {
|