effect 2.0.3 → 2.0.5
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/FiberMap/package.json +6 -0
- package/FiberSet/package.json +6 -0
- package/Trie/package.json +6 -0
- package/dist/cjs/FiberMap.js +190 -0
- package/dist/cjs/FiberMap.js.map +1 -0
- package/dist/cjs/FiberSet.js +150 -0
- package/dist/cjs/FiberSet.js.map +1 -0
- package/dist/cjs/MutableHashMap.js +11 -1
- package/dist/cjs/MutableHashMap.js.map +1 -1
- package/dist/cjs/MutableHashSet.js +7 -1
- package/dist/cjs/MutableHashSet.js.map +1 -1
- package/dist/cjs/MutableList.js +8 -11
- package/dist/cjs/MutableList.js.map +1 -1
- package/dist/cjs/Schedule.js.map +1 -1
- package/dist/cjs/Struct.js +16 -1
- package/dist/cjs/Struct.js.map +1 -1
- package/dist/cjs/Trie.js +680 -0
- package/dist/cjs/Trie.js.map +1 -0
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/hashMap/node.js +2 -2
- package/dist/cjs/internal/hashMap/node.js.map +1 -1
- package/dist/cjs/internal/pubsub.js +11 -17
- package/dist/cjs/internal/pubsub.js.map +1 -1
- package/dist/cjs/internal/redBlackTree/node.js +35 -30
- package/dist/cjs/internal/redBlackTree/node.js.map +1 -1
- package/dist/cjs/internal/redBlackTree.js +69 -13
- package/dist/cjs/internal/redBlackTree.js.map +1 -1
- package/dist/cjs/internal/schedule.js +1 -1
- package/dist/cjs/internal/schedule.js.map +1 -1
- package/dist/cjs/internal/stack.js +6 -11
- package/dist/cjs/internal/stack.js.map +1 -1
- package/dist/cjs/internal/trie.js +588 -0
- package/dist/cjs/internal/trie.js.map +1 -0
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/FiberMap.d.ts +135 -0
- package/dist/dts/FiberMap.d.ts.map +1 -0
- package/dist/dts/FiberSet.d.ts +99 -0
- package/dist/dts/FiberSet.d.ts.map +1 -0
- package/dist/dts/MutableHashMap.d.ts +4 -0
- package/dist/dts/MutableHashMap.d.ts.map +1 -1
- package/dist/dts/MutableHashSet.d.ts +5 -0
- package/dist/dts/MutableHashSet.d.ts.map +1 -1
- package/dist/dts/MutableList.d.ts.map +1 -1
- package/dist/dts/Schedule.d.ts +2 -1
- package/dist/dts/Schedule.d.ts.map +1 -1
- package/dist/dts/Struct.d.ts +17 -3
- package/dist/dts/Struct.d.ts.map +1 -1
- package/dist/dts/Trie.d.ts +740 -0
- package/dist/dts/Trie.d.ts.map +1 -0
- package/dist/dts/Types.d.ts +4 -0
- package/dist/dts/Types.d.ts.map +1 -1
- package/dist/dts/index.d.ts +26 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/redBlackTree/node.d.ts +8 -0
- package/dist/dts/internal/redBlackTree/node.d.ts.map +1 -1
- package/dist/dts/internal/stack.d.ts +1 -1
- package/dist/dts/internal/stack.d.ts.map +1 -1
- package/dist/dts/internal/trie.d.ts +2 -0
- package/dist/dts/internal/trie.d.ts.map +1 -0
- package/dist/dts/internal/version.d.ts +1 -1
- package/dist/esm/FiberMap.js +154 -0
- package/dist/esm/FiberMap.js.map +1 -0
- package/dist/esm/FiberSet.js +114 -0
- package/dist/esm/FiberSet.js.map +1 -0
- package/dist/esm/MutableHashMap.js +9 -0
- package/dist/esm/MutableHashMap.js.map +1 -1
- package/dist/esm/MutableHashSet.js +5 -0
- package/dist/esm/MutableHashSet.js.map +1 -1
- package/dist/esm/MutableList.js +8 -11
- package/dist/esm/MutableList.js.map +1 -1
- package/dist/esm/Schedule.js.map +1 -1
- package/dist/esm/Struct.js +14 -0
- package/dist/esm/Struct.js.map +1 -1
- package/dist/esm/Trie.js +648 -0
- package/dist/esm/Trie.js.map +1 -0
- package/dist/esm/index.js +26 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/hashMap/node.js +2 -2
- package/dist/esm/internal/hashMap/node.js.map +1 -1
- package/dist/esm/internal/pubsub.js +11 -17
- package/dist/esm/internal/pubsub.js.map +1 -1
- package/dist/esm/internal/redBlackTree/node.js +31 -25
- package/dist/esm/internal/redBlackTree/node.js.map +1 -1
- package/dist/esm/internal/redBlackTree.js +69 -13
- package/dist/esm/internal/redBlackTree.js.map +1 -1
- package/dist/esm/internal/schedule.js +1 -1
- package/dist/esm/internal/schedule.js.map +1 -1
- package/dist/esm/internal/stack.js +4 -9
- package/dist/esm/internal/stack.js.map +1 -1
- package/dist/esm/internal/trie.js +547 -0
- package/dist/esm/internal/trie.js.map +1 -0
- package/dist/esm/internal/version.js +1 -1
- package/package.json +25 -1
- package/src/FiberMap.ts +296 -0
- package/src/FiberSet.ts +194 -0
- package/src/MutableHashMap.ts +10 -0
- package/src/MutableHashSet.ts +6 -0
- package/src/MutableList.ts +15 -7
- package/src/Schedule.ts +2 -1
- package/src/Struct.ts +24 -6
- package/src/Trie.ts +772 -0
- package/src/Types.ts +5 -0
- package/src/index.ts +29 -0
- package/src/internal/hashMap/node.ts +3 -3
- package/src/internal/pubsub.ts +15 -14
- package/src/internal/redBlackTree/node.ts +37 -17
- package/src/internal/redBlackTree.ts +73 -38
- package/src/internal/schedule.ts +2 -2
- package/src/internal/stack.ts +8 -2
- package/src/internal/trie.ts +721 -0
- package/src/internal/version.ts +1 -1
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
import * as Equal from "../Equal.js"
|
|
2
|
+
import { dual, identity, pipe } from "../Function.js"
|
|
3
|
+
import * as Hash from "../Hash.js"
|
|
4
|
+
import { format, NodeInspectSymbol, toJSON } from "../Inspectable.js"
|
|
5
|
+
import * as Option from "../Option.js"
|
|
6
|
+
import type * as Ordering from "../Ordering.js"
|
|
7
|
+
import { pipeArguments } from "../Pipeable.js"
|
|
8
|
+
import { hasProperty } from "../Predicate.js"
|
|
9
|
+
import type * as TR from "../Trie.js"
|
|
10
|
+
|
|
11
|
+
const TrieSymbolKey = "effect/Trie"
|
|
12
|
+
|
|
13
|
+
/** @internal */
|
|
14
|
+
export const TrieTypeId: TR.TypeId = Symbol.for(TrieSymbolKey) as TR.TypeId
|
|
15
|
+
|
|
16
|
+
type TraversalMap<K, V, A> = (k: K, v: V) => A
|
|
17
|
+
|
|
18
|
+
type TraversalFilter<K, V> = (k: K, v: V) => boolean
|
|
19
|
+
|
|
20
|
+
/** @internal */
|
|
21
|
+
export interface TrieImpl<in out V> extends TR.Trie<V> {
|
|
22
|
+
readonly _root: Node<V> | undefined
|
|
23
|
+
readonly _count: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const trieVariance = {
|
|
27
|
+
/* c8 ignore next */
|
|
28
|
+
_Value: (_: never) => _
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const TrieProto: TR.Trie<unknown> = {
|
|
32
|
+
[TrieTypeId]: trieVariance,
|
|
33
|
+
[Symbol.iterator]<V>(this: TrieImpl<V>): Iterator<[string, V]> {
|
|
34
|
+
return new TrieIterator(this, (k, v) => [k, v], () => true)
|
|
35
|
+
},
|
|
36
|
+
[Hash.symbol](): number {
|
|
37
|
+
let hash = Hash.hash(TrieSymbolKey)
|
|
38
|
+
for (const item of this) {
|
|
39
|
+
hash ^= pipe(Hash.hash(item[0]), Hash.combine(Hash.hash(item[1])))
|
|
40
|
+
}
|
|
41
|
+
return hash
|
|
42
|
+
},
|
|
43
|
+
[Equal.symbol]<V>(this: TrieImpl<V>, that: unknown): boolean {
|
|
44
|
+
if (isTrie(that)) {
|
|
45
|
+
const entries = Array.from(that)
|
|
46
|
+
return Array.from(this).every((itemSelf, i) => {
|
|
47
|
+
const itemThat = entries[i]
|
|
48
|
+
return Equal.equals(itemSelf[0], itemThat[0]) && Equal.equals(itemSelf[1], itemThat[1])
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
return false
|
|
52
|
+
},
|
|
53
|
+
toString() {
|
|
54
|
+
return format(this.toJSON())
|
|
55
|
+
},
|
|
56
|
+
toJSON() {
|
|
57
|
+
return {
|
|
58
|
+
_id: "Trie",
|
|
59
|
+
values: Array.from(this).map(toJSON)
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
[NodeInspectSymbol]() {
|
|
63
|
+
return this.toJSON()
|
|
64
|
+
},
|
|
65
|
+
pipe() {
|
|
66
|
+
return pipeArguments(this, arguments)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const makeImpl = <V>(root: Node<V> | undefined): TrieImpl<V> => {
|
|
71
|
+
const trie = Object.create(TrieProto)
|
|
72
|
+
trie._root = root
|
|
73
|
+
trie._count = root?.count ?? 0
|
|
74
|
+
return trie
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class TrieIterator<in out V, out T> implements IterableIterator<T> {
|
|
78
|
+
stack: Array<[Node<V>, string, boolean]> = []
|
|
79
|
+
|
|
80
|
+
constructor(
|
|
81
|
+
readonly trie: TrieImpl<V>,
|
|
82
|
+
readonly f: TraversalMap<string, V, T>,
|
|
83
|
+
readonly filter: TraversalFilter<string, V>
|
|
84
|
+
) {
|
|
85
|
+
const root = trie._root !== undefined ? trie._root : undefined
|
|
86
|
+
if (root !== undefined) {
|
|
87
|
+
this.stack.push([root, "", false])
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
next(): IteratorResult<T> {
|
|
92
|
+
while (this.stack.length > 0) {
|
|
93
|
+
const [node, keyString, isAdded] = this.stack.pop()!
|
|
94
|
+
|
|
95
|
+
if (isAdded) {
|
|
96
|
+
const value = node.value
|
|
97
|
+
if (value !== undefined) {
|
|
98
|
+
const key = keyString + node.key
|
|
99
|
+
if (this.filter(key, value)) {
|
|
100
|
+
return { done: false, value: this.f(key, value) }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
this.addToStack(node, keyString)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { done: true, value: undefined }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
addToStack(node: Node<V>, keyString: string) {
|
|
112
|
+
if (node.right !== undefined) {
|
|
113
|
+
this.stack.push([node.right, keyString, false])
|
|
114
|
+
}
|
|
115
|
+
if (node.mid !== undefined) {
|
|
116
|
+
this.stack.push([node.mid, keyString + node.key, false])
|
|
117
|
+
}
|
|
118
|
+
this.stack.push([node, keyString, true])
|
|
119
|
+
if (node.left !== undefined) {
|
|
120
|
+
this.stack.push([node.left, keyString, false])
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
[Symbol.iterator](): IterableIterator<T> {
|
|
125
|
+
return new TrieIterator(this.trie, this.f, this.filter)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** @internal */
|
|
130
|
+
export const isTrie: {
|
|
131
|
+
<V>(u: Iterable<readonly [string, V]>): u is TR.Trie<V>
|
|
132
|
+
(u: unknown): u is TR.Trie<unknown>
|
|
133
|
+
} = (u: unknown): u is TR.Trie<unknown> => hasProperty(u, TrieTypeId)
|
|
134
|
+
|
|
135
|
+
/** @internal */
|
|
136
|
+
export const empty = <V = never>(): TR.Trie<V> => makeImpl<V>(undefined)
|
|
137
|
+
|
|
138
|
+
/** @internal */
|
|
139
|
+
export const fromIterable = <V>(entries: Iterable<readonly [string, V]>) => {
|
|
140
|
+
let trie = empty<V>()
|
|
141
|
+
for (const [key, value] of entries) {
|
|
142
|
+
trie = insert(trie, key, value)
|
|
143
|
+
}
|
|
144
|
+
return trie
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** @internal */
|
|
148
|
+
export const make = <Entries extends Array<readonly [string, any]>>(...entries: Entries): TR.Trie<
|
|
149
|
+
Entries[number] extends readonly [any, infer V] ? V : never
|
|
150
|
+
> => {
|
|
151
|
+
return fromIterable(entries)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** @internal */
|
|
155
|
+
export const insert = dual<
|
|
156
|
+
<V>(key: string, value: V) => (self: TR.Trie<V>) => TR.Trie<V>,
|
|
157
|
+
<V>(self: TR.Trie<V>, key: string, value: V) => TR.Trie<V>
|
|
158
|
+
>(3, <V>(self: TR.Trie<V>, key: string, value: V) => {
|
|
159
|
+
if (key.length === 0) return self
|
|
160
|
+
|
|
161
|
+
// -1:left | 0:mid | 1:right
|
|
162
|
+
const dStack: Array<Ordering.Ordering> = []
|
|
163
|
+
const nStack: Array<Node<V>> = []
|
|
164
|
+
let n: Node<V> = (self as TrieImpl<V>)._root ?? {
|
|
165
|
+
key: key[0],
|
|
166
|
+
count: 0
|
|
167
|
+
}
|
|
168
|
+
const count = n.count + 1
|
|
169
|
+
let cIndex = 0
|
|
170
|
+
|
|
171
|
+
while (cIndex < key.length) {
|
|
172
|
+
const c = key[cIndex]
|
|
173
|
+
nStack.push(n)
|
|
174
|
+
if (c > n.key) {
|
|
175
|
+
dStack.push(1)
|
|
176
|
+
if (n.right === undefined) {
|
|
177
|
+
n = { key: c, count }
|
|
178
|
+
} else {
|
|
179
|
+
n = n.right
|
|
180
|
+
}
|
|
181
|
+
} else if (c < n.key) {
|
|
182
|
+
dStack.push(-1)
|
|
183
|
+
if (n.left === undefined) {
|
|
184
|
+
n = { key: c, count }
|
|
185
|
+
} else {
|
|
186
|
+
n = n.left
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
if (cIndex === key.length - 1) {
|
|
190
|
+
n.value = value
|
|
191
|
+
} else if (n.mid === undefined) {
|
|
192
|
+
dStack.push(0)
|
|
193
|
+
n = { key: key[cIndex + 1], count }
|
|
194
|
+
} else {
|
|
195
|
+
dStack.push(0)
|
|
196
|
+
n = n.mid
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
cIndex += 1
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Rebuild path to leaf node (Path-copying immutability)
|
|
204
|
+
for (let s = nStack.length - 2; s >= 0; --s) {
|
|
205
|
+
const n2 = nStack[s]
|
|
206
|
+
const d = dStack[s]
|
|
207
|
+
if (d === -1) {
|
|
208
|
+
// left
|
|
209
|
+
nStack[s] = {
|
|
210
|
+
key: n2.key,
|
|
211
|
+
count,
|
|
212
|
+
value: n2.value,
|
|
213
|
+
left: nStack[s + 1],
|
|
214
|
+
mid: n2.mid,
|
|
215
|
+
right: n2.right
|
|
216
|
+
}
|
|
217
|
+
} else if (d === 1) {
|
|
218
|
+
// right
|
|
219
|
+
nStack[s] = {
|
|
220
|
+
key: n2.key,
|
|
221
|
+
count,
|
|
222
|
+
value: n2.value,
|
|
223
|
+
left: n2.left,
|
|
224
|
+
mid: n2.mid,
|
|
225
|
+
right: nStack[s + 1]
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
// mid
|
|
229
|
+
nStack[s] = {
|
|
230
|
+
key: n2.key,
|
|
231
|
+
count,
|
|
232
|
+
value: n2.value,
|
|
233
|
+
left: n2.left,
|
|
234
|
+
mid: nStack[s + 1],
|
|
235
|
+
right: n2.right
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
nStack[0].count = count
|
|
241
|
+
return makeImpl(nStack[0])
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
/** @internal */
|
|
245
|
+
export const size = <V>(self: TR.Trie<V>): number => (self as TrieImpl<V>)._root?.count ?? 0
|
|
246
|
+
|
|
247
|
+
/** @internal */
|
|
248
|
+
export const isEmpty = <V>(self: TR.Trie<V>): boolean => size(self) === 0
|
|
249
|
+
|
|
250
|
+
/** @internal */
|
|
251
|
+
export const keys = <V>(self: TR.Trie<V>): IterableIterator<string> =>
|
|
252
|
+
new TrieIterator(self as TrieImpl<V>, (key) => key, () => true)
|
|
253
|
+
|
|
254
|
+
/** @internal */
|
|
255
|
+
export const values = <V>(self: TR.Trie<V>): IterableIterator<V> =>
|
|
256
|
+
new TrieIterator(self as TrieImpl<V>, (_, value) => value, () => true)
|
|
257
|
+
|
|
258
|
+
/** @internal */
|
|
259
|
+
export const entries = <V>(self: TR.Trie<V>): IterableIterator<[string, V]> =>
|
|
260
|
+
new TrieIterator(self as TrieImpl<V>, (key, value) => [key, value], () => true)
|
|
261
|
+
|
|
262
|
+
/** @internal */
|
|
263
|
+
export const reduce = dual<
|
|
264
|
+
<Z, V>(
|
|
265
|
+
zero: Z,
|
|
266
|
+
f: (accumulator: Z, value: V, key: string) => Z
|
|
267
|
+
) => (self: TR.Trie<V>) => Z,
|
|
268
|
+
<Z, V>(self: TR.Trie<V>, zero: Z, f: (accumulator: Z, value: V, key: string) => Z) => Z
|
|
269
|
+
>(3, (self, zero, f) => {
|
|
270
|
+
let accumulator = zero
|
|
271
|
+
for (const entry of self) {
|
|
272
|
+
accumulator = f(accumulator, entry[1], entry[0])
|
|
273
|
+
}
|
|
274
|
+
return accumulator
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
/** @internal */
|
|
278
|
+
export const map = dual<
|
|
279
|
+
<A, V>(f: (value: V, key: string) => A) => (self: TR.Trie<V>) => TR.Trie<A>,
|
|
280
|
+
<V, A>(self: TR.Trie<V>, f: (value: V, key: string) => A) => TR.Trie<A>
|
|
281
|
+
>(2, (self, f) =>
|
|
282
|
+
reduce(
|
|
283
|
+
self,
|
|
284
|
+
empty(),
|
|
285
|
+
(trie, value, key) => insert(trie, key, f(value, key))
|
|
286
|
+
))
|
|
287
|
+
|
|
288
|
+
/** @internal */
|
|
289
|
+
export const filter: {
|
|
290
|
+
<A, B extends A>(f: (a: A, k: string) => a is B): (self: TR.Trie<A>) => TR.Trie<B>
|
|
291
|
+
<B extends A, A = B>(f: (a: A, k: string) => boolean): (self: TR.Trie<B>) => TR.Trie<B>
|
|
292
|
+
<A, B extends A>(self: TR.Trie<A>, f: (a: A, k: string) => a is B): TR.Trie<B>
|
|
293
|
+
<A>(self: TR.Trie<A>, f: (a: A, k: string) => boolean): TR.Trie<A>
|
|
294
|
+
} = dual(
|
|
295
|
+
2,
|
|
296
|
+
<A>(self: TR.Trie<A>, f: (a: A, k: string) => boolean): TR.Trie<A> =>
|
|
297
|
+
reduce(
|
|
298
|
+
self,
|
|
299
|
+
empty(),
|
|
300
|
+
(trie, value, key) => f(value, key) ? insert(trie, key, value) : trie
|
|
301
|
+
)
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
/** @internal */
|
|
305
|
+
export const filterMap = dual<
|
|
306
|
+
<A, B>(
|
|
307
|
+
f: (value: A, key: string) => Option.Option<B>
|
|
308
|
+
) => (self: TR.Trie<A>) => TR.Trie<B>,
|
|
309
|
+
<A, B>(self: TR.Trie<A>, f: (value: A, key: string) => Option.Option<B>) => TR.Trie<B>
|
|
310
|
+
>(2, (self, f) =>
|
|
311
|
+
reduce(
|
|
312
|
+
self,
|
|
313
|
+
empty(),
|
|
314
|
+
(trie, value, key) => {
|
|
315
|
+
const option = f(value, key)
|
|
316
|
+
return Option.isSome(option) ? insert(trie, key, option.value) : trie
|
|
317
|
+
}
|
|
318
|
+
))
|
|
319
|
+
|
|
320
|
+
/** @internal */
|
|
321
|
+
export const compact = <A>(self: TR.Trie<Option.Option<A>>) => filterMap(self, identity)
|
|
322
|
+
|
|
323
|
+
/** @internal */
|
|
324
|
+
export const forEach = dual<
|
|
325
|
+
<V>(f: (value: V, key: string) => void) => (self: TR.Trie<V>) => void,
|
|
326
|
+
<V>(self: TR.Trie<V>, f: (value: V, key: string) => void) => void
|
|
327
|
+
>(2, (self, f) => reduce(self, void 0 as void, (_, value, key) => f(value, key)))
|
|
328
|
+
|
|
329
|
+
/** @internal */
|
|
330
|
+
export const keysWithPrefix = dual<
|
|
331
|
+
(prefix: string) => <V>(self: TR.Trie<V>) => IterableIterator<string>,
|
|
332
|
+
<V>(self: TR.Trie<V>, prefix: string) => IterableIterator<string>
|
|
333
|
+
>(
|
|
334
|
+
2,
|
|
335
|
+
<V>(self: TR.Trie<V>, prefix: string): IterableIterator<string> =>
|
|
336
|
+
new TrieIterator(self as TrieImpl<V>, (key) => key, (key) => key.startsWith(prefix))
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
/** @internal */
|
|
340
|
+
export const valuesWithPrefix = dual<
|
|
341
|
+
(prefix: string) => <V>(self: TR.Trie<V>) => IterableIterator<V>,
|
|
342
|
+
<V>(self: TR.Trie<V>, prefix: string) => IterableIterator<V>
|
|
343
|
+
>(
|
|
344
|
+
2,
|
|
345
|
+
<V>(self: TR.Trie<V>, prefix: string): IterableIterator<V> =>
|
|
346
|
+
new TrieIterator(self as TrieImpl<V>, (_, value) => value, (key) => key.startsWith(prefix))
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
/** @internal */
|
|
350
|
+
export const entriesWithPrefix = dual<
|
|
351
|
+
(prefix: string) => <V>(self: TR.Trie<V>) => IterableIterator<[string, V]>,
|
|
352
|
+
<V>(self: TR.Trie<V>, prefix: string) => IterableIterator<[string, V]>
|
|
353
|
+
>(
|
|
354
|
+
2,
|
|
355
|
+
<V>(self: TR.Trie<V>, prefix: string): IterableIterator<[string, V]> =>
|
|
356
|
+
new TrieIterator(self as TrieImpl<V>, (key, value) => [key, value], (key) => key.startsWith(prefix))
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
/** @internal */
|
|
360
|
+
export const toEntriesWithPrefix = dual<
|
|
361
|
+
(prefix: string) => <V>(self: TR.Trie<V>) => Array<[string, V]>,
|
|
362
|
+
<V>(self: TR.Trie<V>, prefix: string) => Array<[string, V]>
|
|
363
|
+
>(
|
|
364
|
+
2,
|
|
365
|
+
<V>(self: TR.Trie<V>, prefix: string): Array<[string, V]> => Array.from(entriesWithPrefix(self, prefix))
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
/** @internal */
|
|
369
|
+
export const get = dual<
|
|
370
|
+
(key: string) => <V>(self: TR.Trie<V>) => Option.Option<V>,
|
|
371
|
+
<V>(self: TR.Trie<V>, key: string) => Option.Option<V>
|
|
372
|
+
>(
|
|
373
|
+
2,
|
|
374
|
+
<V>(self: TR.Trie<V>, key: string) => {
|
|
375
|
+
let n: Node<V> | undefined = (self as TrieImpl<V>)._root
|
|
376
|
+
if (n === undefined || key.length === 0) return Option.none()
|
|
377
|
+
let cIndex = 0
|
|
378
|
+
while (cIndex < key.length) {
|
|
379
|
+
const c = key[cIndex]
|
|
380
|
+
if (c > n.key) {
|
|
381
|
+
if (n.right === undefined) {
|
|
382
|
+
return Option.none()
|
|
383
|
+
} else {
|
|
384
|
+
n = n.right
|
|
385
|
+
}
|
|
386
|
+
} else if (c < n.key) {
|
|
387
|
+
if (n.left === undefined) {
|
|
388
|
+
return Option.none()
|
|
389
|
+
} else {
|
|
390
|
+
n = n.left
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
if (cIndex === key.length - 1) {
|
|
394
|
+
return Option.fromNullable(n.value)
|
|
395
|
+
} else {
|
|
396
|
+
if (n.mid === undefined) {
|
|
397
|
+
return Option.none()
|
|
398
|
+
} else {
|
|
399
|
+
n = n.mid
|
|
400
|
+
cIndex += 1
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return Option.none()
|
|
406
|
+
}
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
/** @internal */
|
|
410
|
+
export const has = dual<
|
|
411
|
+
(key: string) => <V>(self: TR.Trie<V>) => boolean,
|
|
412
|
+
<V>(self: TR.Trie<V>, key: string) => boolean
|
|
413
|
+
>(2, (self, key) => Option.isSome(get(self, key)))
|
|
414
|
+
|
|
415
|
+
/** @internal */
|
|
416
|
+
export const unsafeGet = dual<
|
|
417
|
+
(key: string) => <V>(self: TR.Trie<V>) => V,
|
|
418
|
+
<V>(self: TR.Trie<V>, key: string) => V
|
|
419
|
+
>(2, (self, key) => {
|
|
420
|
+
const element = get(self, key)
|
|
421
|
+
if (Option.isNone(element)) {
|
|
422
|
+
throw new Error("Error: Expected trie to contain key")
|
|
423
|
+
}
|
|
424
|
+
return element.value
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
/** @internal */
|
|
428
|
+
export const remove = dual<
|
|
429
|
+
(key: string) => <V>(self: TR.Trie<V>) => TR.Trie<V>,
|
|
430
|
+
<V>(self: TR.Trie<V>, key: string) => TR.Trie<V>
|
|
431
|
+
>(
|
|
432
|
+
2,
|
|
433
|
+
<V>(self: TR.Trie<V>, key: string) => {
|
|
434
|
+
let n: Node<V> | undefined = (self as TrieImpl<V>)._root
|
|
435
|
+
if (n === undefined || key.length === 0) return self
|
|
436
|
+
|
|
437
|
+
const count = n.count - 1
|
|
438
|
+
// -1:left | 0:mid | 1:right
|
|
439
|
+
const dStack: Array<Ordering.Ordering> = []
|
|
440
|
+
const nStack: Array<Node<V>> = []
|
|
441
|
+
|
|
442
|
+
let cIndex = 0
|
|
443
|
+
while (cIndex < key.length) {
|
|
444
|
+
const c = key[cIndex]
|
|
445
|
+
if (c > n.key) {
|
|
446
|
+
if (n.right === undefined) {
|
|
447
|
+
return self
|
|
448
|
+
} else {
|
|
449
|
+
nStack.push(n)
|
|
450
|
+
dStack.push(1)
|
|
451
|
+
n = n.right
|
|
452
|
+
}
|
|
453
|
+
} else if (c < n.key) {
|
|
454
|
+
if (n.left === undefined) {
|
|
455
|
+
return self
|
|
456
|
+
} else {
|
|
457
|
+
nStack.push(n)
|
|
458
|
+
dStack.push(-1)
|
|
459
|
+
n = n.left
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
if (cIndex === key.length - 1) {
|
|
463
|
+
if (n.value !== undefined) {
|
|
464
|
+
nStack.push(n)
|
|
465
|
+
dStack.push(0)
|
|
466
|
+
cIndex += 1
|
|
467
|
+
} else {
|
|
468
|
+
return self
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
if (n.mid === undefined) {
|
|
472
|
+
return self
|
|
473
|
+
} else {
|
|
474
|
+
nStack.push(n)
|
|
475
|
+
dStack.push(0)
|
|
476
|
+
n = n.mid
|
|
477
|
+
cIndex += 1
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const removeNode = nStack[nStack.length - 1]
|
|
484
|
+
nStack[nStack.length - 1] = {
|
|
485
|
+
key: removeNode.key,
|
|
486
|
+
count,
|
|
487
|
+
left: removeNode.left,
|
|
488
|
+
mid: removeNode.mid,
|
|
489
|
+
right: removeNode.right
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Rebuild path to leaf node (Path-copying immutability)
|
|
493
|
+
for (let s = nStack.length - 2; s >= 0; --s) {
|
|
494
|
+
const n2 = nStack[s]
|
|
495
|
+
const d = dStack[s]
|
|
496
|
+
const child = nStack[s + 1]
|
|
497
|
+
const nc = child.left === undefined && child.mid === undefined && child.right === undefined ? undefined : child
|
|
498
|
+
if (d === -1) {
|
|
499
|
+
// left
|
|
500
|
+
nStack[s] = {
|
|
501
|
+
key: n2.key,
|
|
502
|
+
count,
|
|
503
|
+
value: n2.value,
|
|
504
|
+
left: nc,
|
|
505
|
+
mid: n2.mid,
|
|
506
|
+
right: n2.right
|
|
507
|
+
}
|
|
508
|
+
} else if (d === 1) {
|
|
509
|
+
// right
|
|
510
|
+
nStack[s] = {
|
|
511
|
+
key: n2.key,
|
|
512
|
+
count,
|
|
513
|
+
value: n2.value,
|
|
514
|
+
left: n2.left,
|
|
515
|
+
mid: n2.mid,
|
|
516
|
+
right: nc
|
|
517
|
+
}
|
|
518
|
+
} else {
|
|
519
|
+
// mid
|
|
520
|
+
nStack[s] = {
|
|
521
|
+
key: n2.key,
|
|
522
|
+
count,
|
|
523
|
+
value: n2.value,
|
|
524
|
+
left: n2.left,
|
|
525
|
+
mid: nc,
|
|
526
|
+
right: n2.right
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
nStack[0].count = count
|
|
532
|
+
return makeImpl(nStack[0])
|
|
533
|
+
}
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
/** @internal */
|
|
537
|
+
export const removeMany = dual<
|
|
538
|
+
(keys: Iterable<string>) => <V>(self: TR.Trie<V>) => TR.Trie<V>,
|
|
539
|
+
<V>(self: TR.Trie<V>, keys: Iterable<string>) => TR.Trie<V>
|
|
540
|
+
>(2, (self, keys) => {
|
|
541
|
+
let trie = self
|
|
542
|
+
for (const key of keys) {
|
|
543
|
+
trie = remove(key)(trie)
|
|
544
|
+
}
|
|
545
|
+
return trie
|
|
546
|
+
})
|
|
547
|
+
|
|
548
|
+
/** @internal */
|
|
549
|
+
export const insertMany = dual<
|
|
550
|
+
<V>(iter: Iterable<[string, V]>) => (self: TR.Trie<V>) => TR.Trie<V>,
|
|
551
|
+
<V>(self: TR.Trie<V>, iter: Iterable<[string, V]>) => TR.Trie<V>
|
|
552
|
+
>(2, (self, iter) => {
|
|
553
|
+
let trie = self
|
|
554
|
+
for (const [key, value] of iter) {
|
|
555
|
+
trie = insert(key, value)(trie)
|
|
556
|
+
}
|
|
557
|
+
return trie
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
/** @internal */
|
|
561
|
+
export const modify = dual<
|
|
562
|
+
<V>(key: string, f: (v: V) => V) => (self: TR.Trie<V>) => TR.Trie<V>,
|
|
563
|
+
<V>(self: TR.Trie<V>, key: string, f: (v: V) => V) => TR.Trie<V>
|
|
564
|
+
>(
|
|
565
|
+
3,
|
|
566
|
+
<V>(self: TR.Trie<V>, key: string, f: (v: V) => V): TR.Trie<V> => {
|
|
567
|
+
let n: Node<V> | undefined = (self as TrieImpl<V>)._root
|
|
568
|
+
if (n === undefined || key.length === 0) return self
|
|
569
|
+
|
|
570
|
+
// -1:left | 0:mid | 1:right
|
|
571
|
+
const dStack: Array<Ordering.Ordering> = []
|
|
572
|
+
const nStack: Array<Node<V>> = []
|
|
573
|
+
|
|
574
|
+
let cIndex = 0
|
|
575
|
+
while (cIndex < key.length) {
|
|
576
|
+
const c = key[cIndex]
|
|
577
|
+
if (c > n.key) {
|
|
578
|
+
if (n.right === undefined) {
|
|
579
|
+
return self
|
|
580
|
+
} else {
|
|
581
|
+
nStack.push(n)
|
|
582
|
+
dStack.push(1)
|
|
583
|
+
n = n.right
|
|
584
|
+
}
|
|
585
|
+
} else if (c < n.key) {
|
|
586
|
+
if (n.left === undefined) {
|
|
587
|
+
return self
|
|
588
|
+
} else {
|
|
589
|
+
nStack.push(n)
|
|
590
|
+
dStack.push(-1)
|
|
591
|
+
n = n.left
|
|
592
|
+
}
|
|
593
|
+
} else {
|
|
594
|
+
if (cIndex === key.length - 1) {
|
|
595
|
+
if (n.value !== undefined) {
|
|
596
|
+
nStack.push(n)
|
|
597
|
+
dStack.push(0)
|
|
598
|
+
cIndex += 1
|
|
599
|
+
} else {
|
|
600
|
+
return self
|
|
601
|
+
}
|
|
602
|
+
} else {
|
|
603
|
+
if (n.mid === undefined) {
|
|
604
|
+
return self
|
|
605
|
+
} else {
|
|
606
|
+
nStack.push(n)
|
|
607
|
+
dStack.push(0)
|
|
608
|
+
n = n.mid
|
|
609
|
+
cIndex += 1
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
const updateNode = nStack[nStack.length - 1]
|
|
616
|
+
if (updateNode.value === undefined) {
|
|
617
|
+
return self
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
nStack[nStack.length - 1] = {
|
|
621
|
+
key: updateNode.key,
|
|
622
|
+
count: updateNode.count,
|
|
623
|
+
value: f(updateNode.value), // Update
|
|
624
|
+
left: updateNode.left,
|
|
625
|
+
mid: updateNode.mid,
|
|
626
|
+
right: updateNode.right
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Rebuild path to leaf node (Path-copying immutability)
|
|
630
|
+
for (let s = nStack.length - 2; s >= 0; --s) {
|
|
631
|
+
const n2 = nStack[s]
|
|
632
|
+
const d = dStack[s]
|
|
633
|
+
const child = nStack[s + 1]
|
|
634
|
+
if (d === -1) {
|
|
635
|
+
// left
|
|
636
|
+
nStack[s] = {
|
|
637
|
+
key: n2.key,
|
|
638
|
+
count: n2.count,
|
|
639
|
+
value: n2.value,
|
|
640
|
+
left: child,
|
|
641
|
+
mid: n2.mid,
|
|
642
|
+
right: n2.right
|
|
643
|
+
}
|
|
644
|
+
} else if (d === 1) {
|
|
645
|
+
// right
|
|
646
|
+
nStack[s] = {
|
|
647
|
+
key: n2.key,
|
|
648
|
+
count: n2.count,
|
|
649
|
+
value: n2.value,
|
|
650
|
+
left: n2.left,
|
|
651
|
+
mid: n2.mid,
|
|
652
|
+
right: child
|
|
653
|
+
}
|
|
654
|
+
} else {
|
|
655
|
+
// mid
|
|
656
|
+
nStack[s] = {
|
|
657
|
+
key: n2.key,
|
|
658
|
+
count: n2.count,
|
|
659
|
+
value: n2.value,
|
|
660
|
+
left: n2.left,
|
|
661
|
+
mid: child,
|
|
662
|
+
right: n2.right
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
return makeImpl(nStack[0])
|
|
668
|
+
}
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
/** @internal */
|
|
672
|
+
export const longestPrefixOf = dual<
|
|
673
|
+
(key: string) => <V>(self: TR.Trie<V>) => Option.Option<[string, V]>,
|
|
674
|
+
<V>(self: TR.Trie<V>, key: string) => Option.Option<[string, V]>
|
|
675
|
+
>(
|
|
676
|
+
2,
|
|
677
|
+
<V>(self: TR.Trie<V>, key: string) => {
|
|
678
|
+
let n: Node<V> | undefined = (self as TrieImpl<V>)._root
|
|
679
|
+
if (n === undefined || key.length === 0) return Option.none()
|
|
680
|
+
let longestPrefixNode: [string, V] | undefined = undefined
|
|
681
|
+
let cIndex = 0
|
|
682
|
+
while (cIndex < key.length) {
|
|
683
|
+
const c = key[cIndex]
|
|
684
|
+
if (n.value !== undefined) {
|
|
685
|
+
longestPrefixNode = [key.slice(0, cIndex + 1), n.value]
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (c > n.key) {
|
|
689
|
+
if (n.right === undefined) {
|
|
690
|
+
break
|
|
691
|
+
} else {
|
|
692
|
+
n = n.right
|
|
693
|
+
}
|
|
694
|
+
} else if (c < n.key) {
|
|
695
|
+
if (n.left === undefined) {
|
|
696
|
+
break
|
|
697
|
+
} else {
|
|
698
|
+
n = n.left
|
|
699
|
+
}
|
|
700
|
+
} else {
|
|
701
|
+
if (n.mid === undefined) {
|
|
702
|
+
break
|
|
703
|
+
} else {
|
|
704
|
+
n = n.mid
|
|
705
|
+
cIndex += 1
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return Option.fromNullable(longestPrefixNode)
|
|
711
|
+
}
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
interface Node<V> {
|
|
715
|
+
key: string
|
|
716
|
+
count: number
|
|
717
|
+
value?: V | undefined
|
|
718
|
+
left?: Node<V> | undefined
|
|
719
|
+
mid?: Node<V> | undefined
|
|
720
|
+
right?: Node<V> | undefined
|
|
721
|
+
}
|
package/src/internal/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const moduleVersion = "2.0.
|
|
1
|
+
export const moduleVersion = "2.0.5"
|