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
|
@@ -6,6 +6,7 @@ import { Mapping } from './abc.js';
|
|
|
6
6
|
export declare class LRUCache<K = any, V = any> extends Mapping<K, V> {
|
|
7
7
|
protected items: Map<K, V>;
|
|
8
8
|
protected maxSize: number;
|
|
9
|
+
private eviction;
|
|
9
10
|
/**
|
|
10
11
|
* Creates a new instance of fixed size.
|
|
11
12
|
* @param {number} capacity
|
|
@@ -18,6 +19,8 @@ export declare class LRUCache<K = any, V = any> extends Mapping<K, V> {
|
|
|
18
19
|
* @returns {this}
|
|
19
20
|
*/
|
|
20
21
|
set(key: K, value: V): this;
|
|
22
|
+
/** An idle Map iterator pins every hash table the Map has outgrown, so it cannot live forever. */
|
|
23
|
+
private wrote;
|
|
21
24
|
/**
|
|
22
25
|
* This is just an alias of {@link LRUCache.set}.
|
|
23
26
|
* @param {K} key The key to add (note value will be `undefined`)
|
|
@@ -62,17 +65,17 @@ export declare class LRUCache<K = any, V = any> extends Mapping<K, V> {
|
|
|
62
65
|
*/
|
|
63
66
|
get capacity(): number;
|
|
64
67
|
/**
|
|
65
|
-
* Returns an iterable of all the keys in the cache,
|
|
68
|
+
* Returns an iterable of all the keys in the cache, from least to most recently used.
|
|
66
69
|
* @returns {IterableIterator<K>}
|
|
67
70
|
*/
|
|
68
71
|
keys(): IterableIterator<K>;
|
|
69
72
|
/**
|
|
70
|
-
* Returns an iterable of all the values in the cache,
|
|
73
|
+
* Returns an iterable of all the values in the cache, from least to most recently used.
|
|
71
74
|
* @returns {IterableIterator<V>}
|
|
72
75
|
*/
|
|
73
76
|
values(): IterableIterator<V>;
|
|
74
77
|
/**
|
|
75
|
-
* Returns an iterable of all the [key, value] pairs in the cache,
|
|
78
|
+
* Returns an iterable of all the [key, value] pairs in the cache, from least to most recently used.
|
|
76
79
|
* @returns {IterableIterator<[K, V]>}
|
|
77
80
|
*/
|
|
78
81
|
entries(): IterableIterator<[K, V]>;
|
|
@@ -13,6 +13,8 @@ export class LRUCache extends Mapping {
|
|
|
13
13
|
constructor(capacity = 1024) {
|
|
14
14
|
super();
|
|
15
15
|
this.maxSize = capacity;
|
|
16
|
+
// Not enumerable, so two caches compare by their items
|
|
17
|
+
Object.defineProperty(this, 'eviction', { value: { keys: this.items.keys(), writes: 0 } });
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
20
|
* Adds a new element with a specified `key` and `value` to the cache. If an element with the same key already exists, the element will be updated.
|
|
@@ -21,16 +23,25 @@ export class LRUCache extends Mapping {
|
|
|
21
23
|
* @returns {this}
|
|
22
24
|
*/
|
|
23
25
|
set(key, value) {
|
|
24
|
-
if (this.items.size === this.maxSize) {
|
|
25
|
-
// Because ES6 maps remember insertion order, we can evict the first key
|
|
26
|
-
const lastKey = this.items.keys().next().value;
|
|
27
|
-
this.items.delete(lastKey);
|
|
28
|
-
}
|
|
29
26
|
// Delete the previous key to update the new insertion order
|
|
30
27
|
this.items.delete(key);
|
|
31
28
|
this.items.set(key, value);
|
|
29
|
+
this.wrote();
|
|
30
|
+
if (this.items.size > this.maxSize) {
|
|
31
|
+
// Because ES6 maps remember insertion order, we can evict the first key
|
|
32
|
+
const lastKey = this.eviction.keys.next().value;
|
|
33
|
+
this.items.delete(lastKey);
|
|
34
|
+
}
|
|
32
35
|
return this;
|
|
33
36
|
}
|
|
37
|
+
/** An idle Map iterator pins every hash table the Map has outgrown, so it cannot live forever. */
|
|
38
|
+
wrote() {
|
|
39
|
+
const { eviction } = this;
|
|
40
|
+
if (++eviction.writes >= this.items.size) {
|
|
41
|
+
eviction.writes = 0;
|
|
42
|
+
eviction.keys = this.items.keys();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
34
45
|
/**
|
|
35
46
|
* This is just an alias of {@link LRUCache.set}.
|
|
36
47
|
* @param {K} key The key to add (note value will be `undefined`)
|
|
@@ -58,6 +69,7 @@ export class LRUCache extends Mapping {
|
|
|
58
69
|
// Delete the previous key to update the new insertion order
|
|
59
70
|
this.items.delete(key);
|
|
60
71
|
this.items.set(key, value);
|
|
72
|
+
this.wrote();
|
|
61
73
|
return value;
|
|
62
74
|
}
|
|
63
75
|
}
|
|
@@ -100,25 +112,26 @@ export class LRUCache extends Mapping {
|
|
|
100
112
|
return this.maxSize;
|
|
101
113
|
}
|
|
102
114
|
/**
|
|
103
|
-
* Returns an iterable of all the keys in the cache,
|
|
115
|
+
* Returns an iterable of all the keys in the cache, from least to most recently used.
|
|
104
116
|
* @returns {IterableIterator<K>}
|
|
105
117
|
*/
|
|
106
118
|
keys() {
|
|
107
|
-
|
|
119
|
+
// A snapshot: get and set re-insert keys, so a live Map iterator would never reach the end
|
|
120
|
+
return [...this.items.keys()].values();
|
|
108
121
|
}
|
|
109
122
|
/**
|
|
110
|
-
* Returns an iterable of all the values in the cache,
|
|
123
|
+
* Returns an iterable of all the values in the cache, from least to most recently used.
|
|
111
124
|
* @returns {IterableIterator<V>}
|
|
112
125
|
*/
|
|
113
126
|
values() {
|
|
114
|
-
return this.items.values();
|
|
127
|
+
return [...this.items.values()].values();
|
|
115
128
|
}
|
|
116
129
|
/**
|
|
117
|
-
* Returns an iterable of all the [key, value] pairs in the cache,
|
|
130
|
+
* Returns an iterable of all the [key, value] pairs in the cache, from least to most recently used.
|
|
118
131
|
* @returns {IterableIterator<[K, V]>}
|
|
119
132
|
*/
|
|
120
133
|
entries() {
|
|
121
|
-
return this.items.entries();
|
|
134
|
+
return [...this.items.entries()].values();
|
|
122
135
|
}
|
|
123
136
|
[Symbol.iterator]() {
|
|
124
137
|
return this.entries();
|
|
@@ -28,7 +28,7 @@ export class SortedMap extends Mapping {
|
|
|
28
28
|
* @returns {this} Returns the Map object.
|
|
29
29
|
*/
|
|
30
30
|
add(key) {
|
|
31
|
-
this.store.
|
|
31
|
+
this.store.add(key);
|
|
32
32
|
return this;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
@@ -69,7 +69,7 @@ export class SortedMap extends Mapping {
|
|
|
69
69
|
* @returns {boolean} `true` if key was removed, otherwise `false`.
|
|
70
70
|
*/
|
|
71
71
|
delete(item) {
|
|
72
|
-
return this.store.
|
|
72
|
+
return this.store.delete(item);
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* Removes all key/value pairs in the tree.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Comparer } from '../operators/index.js';
|
|
1
|
+
import type { Comparer } from '../operators/index.js';
|
|
2
2
|
import { Mapping } from './abc.js';
|
|
3
3
|
/**
|
|
4
4
|
* A `SortedTree` is a map that holds key value pairs ordered by keys. Any primitive value (and objects that implement {@link Comparable} or {@link Ordered} interfaces) can be used as keys or values.
|
|
@@ -15,7 +15,7 @@ export declare class SortedTree<K, V> extends Mapping<K, V> {
|
|
|
15
15
|
*/
|
|
16
16
|
constructor(iterable?: Iterable<[K, V]>, compareFn?: Comparer);
|
|
17
17
|
/**
|
|
18
|
-
* Adds a new `key` with a `null` value.
|
|
18
|
+
* Adds a new `key` with a `null` value, if the `key` doesn't exist.
|
|
19
19
|
* @param {K} key
|
|
20
20
|
* @returns {this} Returns the Tree object.
|
|
21
21
|
*/
|
|
@@ -18,12 +18,13 @@ export class SortedTree extends Mapping {
|
|
|
18
18
|
this.store = new BTree(iterable, compareFn);
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Adds a new `key` with a `null` value.
|
|
21
|
+
* Adds a new `key` with a `null` value, if the `key` doesn't exist.
|
|
22
22
|
* @param {K} key
|
|
23
23
|
* @returns {this} Returns the Tree object.
|
|
24
24
|
*/
|
|
25
25
|
add(key) {
|
|
26
|
-
this.store.
|
|
26
|
+
if (!this.store.contains(key))
|
|
27
|
+
this.store.set(key, null);
|
|
27
28
|
return this;
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Comparer } from '../operators/index.js';
|
|
1
|
+
import { type Comparer } from '../operators/index.js';
|
|
2
2
|
import { Mapping } from './abc.js';
|
|
3
3
|
/**
|
|
4
4
|
* Base SplayTree node class.
|
|
@@ -41,13 +41,15 @@ export declare class SplayTree<K, V = any> extends Mapping<K, V> {
|
|
|
41
41
|
* @returns {?V} The value for the key or `undefined`.
|
|
42
42
|
*/
|
|
43
43
|
get(key: K): V | undefined;
|
|
44
|
+
private findNode;
|
|
44
45
|
/**
|
|
45
|
-
* Inserts the `key` and `value` in the tree if the `key`
|
|
46
|
+
* Inserts the `key` and `value` in the tree, or updates the value if the `key` exists.
|
|
46
47
|
* @param {K} key A key which can be any comparable value
|
|
47
48
|
* @param {V} value A value associated with the key
|
|
48
49
|
* @returns
|
|
49
50
|
*/
|
|
50
51
|
set(key: K, value: V): void;
|
|
52
|
+
private insert;
|
|
51
53
|
/**
|
|
52
54
|
* Removes a specified key if it exists in the tree. The removed value is returned or `undefined` if not found.
|
|
53
55
|
* @param {K} key The key to remove.
|
|
@@ -83,7 +85,7 @@ export declare class SplayTree<K, V = any> extends Mapping<K, V> {
|
|
|
83
85
|
* @returns `true` if found.
|
|
84
86
|
*/
|
|
85
87
|
contains(key: K): boolean;
|
|
86
|
-
/** Alias of remove but
|
|
88
|
+
/** Alias of remove but returns `true` if the key was found instead of the deleted value. */
|
|
87
89
|
delete(key: K): boolean;
|
|
88
90
|
clear(): void;
|
|
89
91
|
/**
|
|
@@ -97,8 +99,8 @@ export declare class SplayTree<K, V = any> extends Mapping<K, V> {
|
|
|
97
99
|
*/
|
|
98
100
|
entries(): Iterable<[K, V]>;
|
|
99
101
|
/**
|
|
100
|
-
* Returns an ordered iterable of all the
|
|
101
|
-
* @returns {Iterable<V>}
|
|
102
|
+
* Returns an ordered iterable of all the values in the tree.
|
|
103
|
+
* @returns {Iterable<V>} An iterable of values sorted by key.
|
|
102
104
|
*/
|
|
103
105
|
values(): Iterable<V>;
|
|
104
106
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compare
|
|
1
|
+
import { compare } from '../operators/index.js';
|
|
2
2
|
import { Mapping } from './abc.js';
|
|
3
3
|
/**
|
|
4
4
|
* Base SplayTree node class.
|
|
@@ -14,22 +14,29 @@ class Node {
|
|
|
14
14
|
this.value = value;
|
|
15
15
|
}
|
|
16
16
|
get height() {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return
|
|
17
|
+
let height = -1;
|
|
18
|
+
let level = [this];
|
|
19
|
+
while (level.length) {
|
|
20
|
+
height += 1;
|
|
21
|
+
level = level.flatMap((node) => [node.left, node.right].filter(Boolean));
|
|
22
|
+
}
|
|
23
|
+
return height;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
// In-order
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
// In-order snapshot of a tree: reads splay it, so a live walk would lose its place
|
|
27
|
+
function traverse(node) {
|
|
28
|
+
const nodes = [];
|
|
29
|
+
const stack = [];
|
|
30
|
+
while (node || stack.length) {
|
|
31
|
+
while (node) {
|
|
32
|
+
stack.push(node);
|
|
33
|
+
node = node.left;
|
|
34
|
+
}
|
|
35
|
+
node = stack.pop();
|
|
36
|
+
nodes.push(node);
|
|
31
37
|
node = node.right;
|
|
32
38
|
}
|
|
39
|
+
return nodes;
|
|
33
40
|
}
|
|
34
41
|
/**
|
|
35
42
|
* A splay tree is a *self-balancing binary* search tree with the additional property that recently accessed elements are quick to access again.
|
|
@@ -75,6 +82,9 @@ export class SplayTree extends Mapping {
|
|
|
75
82
|
* @returns {?V} The value for the key or `undefined`.
|
|
76
83
|
*/
|
|
77
84
|
get(key) {
|
|
85
|
+
return this.findNode(key)?.value;
|
|
86
|
+
}
|
|
87
|
+
findNode(key) {
|
|
78
88
|
if (!this.root)
|
|
79
89
|
return;
|
|
80
90
|
// Note: deterministic splaying (always moves key to front):
|
|
@@ -86,7 +96,7 @@ export class SplayTree extends Mapping {
|
|
|
86
96
|
if (Math.random() <= this.randSplay) {
|
|
87
97
|
this.splay(key);
|
|
88
98
|
if (this.cmp(key, this.root.key) === 0)
|
|
89
|
-
return this.root
|
|
99
|
+
return this.root;
|
|
90
100
|
else
|
|
91
101
|
return undefined;
|
|
92
102
|
}
|
|
@@ -95,7 +105,7 @@ export class SplayTree extends Mapping {
|
|
|
95
105
|
while (current) {
|
|
96
106
|
const rank = this.cmp(key, current.key);
|
|
97
107
|
if (rank === 0)
|
|
98
|
-
return current
|
|
108
|
+
return current;
|
|
99
109
|
if (rank < 0)
|
|
100
110
|
current = current.left;
|
|
101
111
|
else
|
|
@@ -103,12 +113,15 @@ export class SplayTree extends Mapping {
|
|
|
103
113
|
}
|
|
104
114
|
}
|
|
105
115
|
/**
|
|
106
|
-
* Inserts the `key` and `value` in the tree if the `key`
|
|
116
|
+
* Inserts the `key` and `value` in the tree, or updates the value if the `key` exists.
|
|
107
117
|
* @param {K} key A key which can be any comparable value
|
|
108
118
|
* @param {V} value A value associated with the key
|
|
109
119
|
* @returns
|
|
110
120
|
*/
|
|
111
121
|
set(key, value) {
|
|
122
|
+
this.insert(key, value, true);
|
|
123
|
+
}
|
|
124
|
+
insert(key, value, overwrite) {
|
|
112
125
|
if (!this.root) {
|
|
113
126
|
this.root = new Node(key, value);
|
|
114
127
|
this.count += 1;
|
|
@@ -120,7 +133,8 @@ export class SplayTree extends Mapping {
|
|
|
120
133
|
const rank = this.cmp(key, this.root.key);
|
|
121
134
|
if (rank === 0) {
|
|
122
135
|
// Update the value
|
|
123
|
-
|
|
136
|
+
if (overwrite)
|
|
137
|
+
this.root.value = value;
|
|
124
138
|
return;
|
|
125
139
|
}
|
|
126
140
|
const node = new Node(key, value);
|
|
@@ -147,7 +161,7 @@ export class SplayTree extends Mapping {
|
|
|
147
161
|
return;
|
|
148
162
|
}
|
|
149
163
|
this.splay(key);
|
|
150
|
-
if (
|
|
164
|
+
if (this.cmp(key, this.root.key) !== 0) {
|
|
151
165
|
return;
|
|
152
166
|
}
|
|
153
167
|
const removed = this.root;
|
|
@@ -229,7 +243,6 @@ export class SplayTree extends Mapping {
|
|
|
229
243
|
if (!this.root)
|
|
230
244
|
return;
|
|
231
245
|
let stub, left, right;
|
|
232
|
-
// eslint-disable-next-line
|
|
233
246
|
stub = left = right = new Node(null, null);
|
|
234
247
|
let root = this.root;
|
|
235
248
|
while (true) {
|
|
@@ -284,7 +297,7 @@ export class SplayTree extends Mapping {
|
|
|
284
297
|
this.root = root;
|
|
285
298
|
}
|
|
286
299
|
add(key) {
|
|
287
|
-
|
|
300
|
+
this.insert(key, null, false);
|
|
288
301
|
}
|
|
289
302
|
/**
|
|
290
303
|
* Returns `true` if the given key is in the tree.
|
|
@@ -292,13 +305,13 @@ export class SplayTree extends Mapping {
|
|
|
292
305
|
* @returns `true` if found.
|
|
293
306
|
*/
|
|
294
307
|
contains(key) {
|
|
295
|
-
return this.
|
|
308
|
+
return this.findNode(key) !== undefined;
|
|
296
309
|
}
|
|
297
|
-
/** Alias of remove but
|
|
310
|
+
/** Alias of remove but returns `true` if the key was found instead of the deleted value. */
|
|
298
311
|
delete(key) {
|
|
299
|
-
|
|
312
|
+
const size = this.count;
|
|
300
313
|
this.remove(key);
|
|
301
|
-
return
|
|
314
|
+
return this.count < size;
|
|
302
315
|
}
|
|
303
316
|
clear() {
|
|
304
317
|
if (!this.root)
|
|
@@ -327,8 +340,8 @@ export class SplayTree extends Mapping {
|
|
|
327
340
|
}
|
|
328
341
|
}
|
|
329
342
|
/**
|
|
330
|
-
* Returns an ordered iterable of all the
|
|
331
|
-
* @returns {Iterable<V>}
|
|
343
|
+
* Returns an ordered iterable of all the values in the tree.
|
|
344
|
+
* @returns {Iterable<V>} An iterable of values sorted by key.
|
|
332
345
|
*/
|
|
333
346
|
*values() {
|
|
334
347
|
for (const node of traverse(this.root)) {
|
|
@@ -23,7 +23,7 @@ export declare class Trie extends Collection {
|
|
|
23
23
|
/**
|
|
24
24
|
* Generates all results that start with the given string.
|
|
25
25
|
* @param word A prefix string
|
|
26
|
-
* @param {number} [limit
|
|
26
|
+
* @param {number} [limit] The number of results to return. Defaults to every result.
|
|
27
27
|
*/
|
|
28
28
|
matches: (word: string, limit?: number) => Generator<string>;
|
|
29
29
|
/**
|
package/dist/collections/Trie.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { itake } from '../itertools/index.js';
|
|
1
2
|
import { Collection } from './abc.js';
|
|
2
|
-
function* traverse(
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
function* traverse(root, prefix) {
|
|
4
|
+
const stack = [[root, prefix]];
|
|
5
|
+
while (stack.length) {
|
|
6
|
+
const [node, path] = stack.pop();
|
|
7
|
+
if (node.isWord)
|
|
8
|
+
yield path;
|
|
9
|
+
for (const key of Object.keys(node).reverse()) {
|
|
10
|
+
stack.push([node[key], path + key]);
|
|
11
|
+
}
|
|
9
12
|
}
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
@@ -14,7 +17,7 @@ function* traverse(node, path, total = 20, count = 0) {
|
|
|
14
17
|
* @see {@link https://en.wikipedia.org/wiki/Trie Trie}
|
|
15
18
|
*/
|
|
16
19
|
export class Trie extends Collection {
|
|
17
|
-
root =
|
|
20
|
+
root = Object.create(null);
|
|
18
21
|
count = 0;
|
|
19
22
|
constructor(words) {
|
|
20
23
|
super();
|
|
@@ -33,16 +36,17 @@ export class Trie extends Collection {
|
|
|
33
36
|
for (let i = 0; i < word.length; i++) {
|
|
34
37
|
const c = word[i];
|
|
35
38
|
if (!current[c])
|
|
36
|
-
current[c] =
|
|
39
|
+
current[c] = Object.create(null);
|
|
37
40
|
current = current[c];
|
|
38
41
|
}
|
|
42
|
+
if (!current.isWord)
|
|
43
|
+
this.count++;
|
|
39
44
|
// Set as end of the word
|
|
40
45
|
Object.defineProperty(current, 'isWord', {
|
|
41
46
|
value: true,
|
|
42
47
|
enumerable: false,
|
|
43
48
|
writable: true
|
|
44
49
|
});
|
|
45
|
-
this.count++;
|
|
46
50
|
return this;
|
|
47
51
|
}
|
|
48
52
|
/**
|
|
@@ -51,15 +55,12 @@ export class Trie extends Collection {
|
|
|
51
55
|
* @returns {boolean} Returns `true` if the string was found and removed.
|
|
52
56
|
*/
|
|
53
57
|
remove(word) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return false;
|
|
58
|
+
const node = this.findNode(word);
|
|
59
|
+
if (!node?.isWord)
|
|
60
|
+
return false;
|
|
61
|
+
node.isWord = false;
|
|
62
|
+
this.count--;
|
|
63
|
+
return true;
|
|
63
64
|
}
|
|
64
65
|
findNode(word) {
|
|
65
66
|
let node = this.root;
|
|
@@ -72,13 +73,12 @@ export class Trie extends Collection {
|
|
|
72
73
|
/**
|
|
73
74
|
* Generates all results that start with the given string.
|
|
74
75
|
* @param word A prefix string
|
|
75
|
-
* @param {number} [limit
|
|
76
|
+
* @param {number} [limit] The number of results to return. Defaults to every result.
|
|
76
77
|
*/
|
|
77
|
-
matches = function* (word, limit
|
|
78
|
+
matches = function* (word, limit) {
|
|
78
79
|
const node = this.findNode(word);
|
|
79
|
-
if (node)
|
|
80
|
-
yield* traverse(node, word
|
|
81
|
-
}
|
|
80
|
+
if (node)
|
|
81
|
+
yield* itake(limit ?? Infinity, traverse(node, word));
|
|
82
82
|
};
|
|
83
83
|
/**
|
|
84
84
|
* Returns `true` if the given string is found in the tree.
|
|
@@ -86,13 +86,13 @@ export class Trie extends Collection {
|
|
|
86
86
|
*/
|
|
87
87
|
contains(word) {
|
|
88
88
|
const node = this.findNode(word);
|
|
89
|
-
return node?.isWord;
|
|
89
|
+
return !!node?.isWord;
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
92
|
* Removes all strings from the tree.
|
|
93
93
|
*/
|
|
94
94
|
clear() {
|
|
95
|
-
this.root =
|
|
95
|
+
this.root = Object.create(null);
|
|
96
96
|
this.count = 0;
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { KeyError, ValueError } from '../globals/index.js';
|
|
2
|
-
import { IterableIterator } from '../itertools/index.js';
|
|
3
2
|
import { eq } from '../operators/index.js';
|
|
4
3
|
import { Sequence } from './abc.js';
|
|
4
|
+
function IterableIterator(next) {
|
|
5
|
+
return {
|
|
6
|
+
next,
|
|
7
|
+
[Symbol.iterator]() {
|
|
8
|
+
return this;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
}
|
|
5
12
|
/**
|
|
6
13
|
* Fixed capacity double-ended queue implemented as ring deque.
|
|
7
14
|
* @template T
|
|
@@ -23,7 +30,9 @@ export class Deque extends Sequence {
|
|
|
23
30
|
throw new ValueError(`Deque capacity should be a positive integer.`);
|
|
24
31
|
this.ArrayConstructor = arrType.constructor;
|
|
25
32
|
this.capacity = capacity;
|
|
26
|
-
|
|
33
|
+
// A typed array cannot grow, so it takes the whole capacity up front
|
|
34
|
+
const length = ArrayBuffer.isView(arrType) ? capacity : arrType.length || capacity;
|
|
35
|
+
this.items = new this.ArrayConstructor(length);
|
|
27
36
|
this.clear();
|
|
28
37
|
if (arrType.length) {
|
|
29
38
|
for (const item of arrType) {
|
|
@@ -125,14 +134,11 @@ export class Deque extends Sequence {
|
|
|
125
134
|
* @returns {?T} The element if exists
|
|
126
135
|
*/
|
|
127
136
|
get(index) {
|
|
128
|
-
if (this.count === 0)
|
|
129
|
-
return;
|
|
130
|
-
index = this.start + index;
|
|
131
137
|
if (index < 0)
|
|
132
138
|
index += this.count;
|
|
133
|
-
if (index
|
|
134
|
-
|
|
135
|
-
return this.items[index];
|
|
139
|
+
if (index < 0 || index >= this.count)
|
|
140
|
+
return;
|
|
141
|
+
return this.items[(this.start + index) % this.capacity];
|
|
136
142
|
}
|
|
137
143
|
/**
|
|
138
144
|
* Update the element at a given `index`.
|
|
@@ -141,9 +147,10 @@ export class Deque extends Sequence {
|
|
|
141
147
|
set(index, value) {
|
|
142
148
|
if (index < 0)
|
|
143
149
|
index += this.count;
|
|
144
|
-
if (index
|
|
150
|
+
if (index < 0 || index >= this.count) {
|
|
145
151
|
throw new KeyError(`Invalid index: ${index} not in Deque.`);
|
|
146
|
-
|
|
152
|
+
}
|
|
153
|
+
this.items[(this.start + index) % this.capacity] = value;
|
|
147
154
|
}
|
|
148
155
|
/**
|
|
149
156
|
* Check if a given element is in the deque.
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export class FrozenSet extends Set {
|
|
10
10
|
constructor(iterable) {
|
|
11
|
-
super(
|
|
11
|
+
super();
|
|
12
|
+
// The Set constructor would call the no-op add below and drop every item
|
|
13
|
+
for (const item of iterable ?? [])
|
|
14
|
+
super.add(item);
|
|
12
15
|
return this.freeze();
|
|
13
16
|
}
|
|
14
17
|
/** @private */
|