@tanstack/db-ivm 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -0
- package/package.json +63 -0
- package/src/d2.ts +150 -0
- package/src/graph.ts +131 -0
- package/src/index.ts +4 -0
- package/src/indexes.ts +117 -0
- package/src/multiset.ts +215 -0
- package/src/operators/concat.ts +45 -0
- package/src/operators/consolidate.ts +50 -0
- package/src/operators/count.ts +52 -0
- package/src/operators/debug.ts +58 -0
- package/src/operators/distinct.ts +98 -0
- package/src/operators/filter.ts +48 -0
- package/src/operators/filterBy.ts +31 -0
- package/src/operators/groupBy.ts +354 -0
- package/src/operators/index.ts +18 -0
- package/src/operators/join.ts +265 -0
- package/src/operators/keying.ts +34 -0
- package/src/operators/map.ts +48 -0
- package/src/operators/negate.ts +33 -0
- package/src/operators/orderBy.ts +213 -0
- package/src/operators/orderByBTree.ts +20 -0
- package/src/operators/output.ts +53 -0
- package/src/operators/pipe.ts +55 -0
- package/src/operators/reduce.ts +124 -0
- package/src/operators/topK.ts +92 -0
- package/src/operators/topKWithFractionalIndex.ts +347 -0
- package/src/operators/topKWithFractionalIndexBTree.ts +306 -0
- package/src/types.ts +376 -0
- package/src/utils.ts +163 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import type { MultiSet, MultiSetArray } from "./multiset.js"
|
|
2
|
+
import type {
|
|
3
|
+
BinaryOperator,
|
|
4
|
+
DifferenceStreamReader,
|
|
5
|
+
DifferenceStreamWriter,
|
|
6
|
+
UnaryOperator,
|
|
7
|
+
} from "./graph.js"
|
|
8
|
+
|
|
9
|
+
export type KeyValue<K, V> = [K, V]
|
|
10
|
+
|
|
11
|
+
export interface IOperator<_T> {
|
|
12
|
+
run: () => void
|
|
13
|
+
hasPendingWork: () => boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface IDifferenceStreamReader<T> {
|
|
17
|
+
drain: () => Array<MultiSet<T>>
|
|
18
|
+
isEmpty: () => boolean
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface IDifferenceStreamWriter<T> {
|
|
22
|
+
sendData: (collection: MultiSet<T> | MultiSetArray<T>) => void
|
|
23
|
+
newReader: () => IDifferenceStreamReader<T>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ID2 {
|
|
27
|
+
getNextOperatorId: () => number
|
|
28
|
+
newInput: <T>() => IStreamBuilder<T>
|
|
29
|
+
addOperator: (operator: UnaryOperator<any> | BinaryOperator<any>) => void
|
|
30
|
+
addStream: (stream: DifferenceStreamReader<any>) => void
|
|
31
|
+
finalize: () => void
|
|
32
|
+
step: () => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface IStreamBuilder<T> {
|
|
36
|
+
writer: DifferenceStreamWriter<T>
|
|
37
|
+
connectReader: () => DifferenceStreamReader<T>
|
|
38
|
+
graph: ID2
|
|
39
|
+
|
|
40
|
+
// Don't judge, this is the only way to type this function.
|
|
41
|
+
// rxjs has very similar code to type its pipe function
|
|
42
|
+
// https://github.com/ReactiveX/rxjs/blob/master/packages/rxjs/src/internal/util/pipe.ts
|
|
43
|
+
// We go to 20 operators deep, because surly that's enough for anyone...
|
|
44
|
+
// A user can always split the pipe into multiple pipes to get around this.
|
|
45
|
+
pipe: (<O>(o1: PipedOperator<T, O>) => IStreamBuilder<O>) &
|
|
46
|
+
(<T2, O>(
|
|
47
|
+
o1: PipedOperator<T, T2>,
|
|
48
|
+
o2: PipedOperator<T2, O>
|
|
49
|
+
) => IStreamBuilder<O>) &
|
|
50
|
+
(<T2, T3, O>(
|
|
51
|
+
o1: PipedOperator<T, T2>,
|
|
52
|
+
o2: PipedOperator<T2, T3>,
|
|
53
|
+
o3: PipedOperator<T3, O>
|
|
54
|
+
) => IStreamBuilder<O>) &
|
|
55
|
+
(<T2, T3, T4, O>(
|
|
56
|
+
o1: PipedOperator<T, T2>,
|
|
57
|
+
o2: PipedOperator<T2, T3>,
|
|
58
|
+
o3: PipedOperator<T3, T4>,
|
|
59
|
+
o4: PipedOperator<T4, O>
|
|
60
|
+
) => IStreamBuilder<O>) &
|
|
61
|
+
(<T2, T3, T4, T5, O>(
|
|
62
|
+
o1: PipedOperator<T, T2>,
|
|
63
|
+
o2: PipedOperator<T2, T3>,
|
|
64
|
+
o3: PipedOperator<T3, T4>,
|
|
65
|
+
o4: PipedOperator<T4, T5>,
|
|
66
|
+
o5: PipedOperator<T5, O>
|
|
67
|
+
) => IStreamBuilder<O>) &
|
|
68
|
+
(<T2, T3, T4, T5, T6, O>(
|
|
69
|
+
o1: PipedOperator<T, T2>,
|
|
70
|
+
o2: PipedOperator<T2, T3>,
|
|
71
|
+
o3: PipedOperator<T3, T4>,
|
|
72
|
+
o4: PipedOperator<T4, T5>,
|
|
73
|
+
o5: PipedOperator<T5, T6>,
|
|
74
|
+
o6: PipedOperator<T6, O>
|
|
75
|
+
) => IStreamBuilder<O>) &
|
|
76
|
+
(<T2, T3, T4, T5, T6, T7, O>(
|
|
77
|
+
o1: PipedOperator<T, T2>,
|
|
78
|
+
o2: PipedOperator<T2, T3>,
|
|
79
|
+
o3: PipedOperator<T3, T4>,
|
|
80
|
+
o4: PipedOperator<T4, T5>,
|
|
81
|
+
o5: PipedOperator<T5, T6>,
|
|
82
|
+
o6: PipedOperator<T6, T7>,
|
|
83
|
+
o7: PipedOperator<T7, O>
|
|
84
|
+
) => IStreamBuilder<O>) &
|
|
85
|
+
(<T2, T3, T4, T5, T6, T7, T8, O>(
|
|
86
|
+
o1: PipedOperator<T, T2>,
|
|
87
|
+
o2: PipedOperator<T2, T3>,
|
|
88
|
+
o3: PipedOperator<T3, T4>,
|
|
89
|
+
o4: PipedOperator<T4, T5>,
|
|
90
|
+
o5: PipedOperator<T5, T6>,
|
|
91
|
+
o6: PipedOperator<T6, T7>,
|
|
92
|
+
o7: PipedOperator<T7, T8>,
|
|
93
|
+
o8: PipedOperator<T8, O>
|
|
94
|
+
) => IStreamBuilder<O>) &
|
|
95
|
+
(<T2, T3, T4, T5, T6, T7, T8, T9, O>(
|
|
96
|
+
o1: PipedOperator<T, T2>,
|
|
97
|
+
o2: PipedOperator<T2, T3>,
|
|
98
|
+
o3: PipedOperator<T3, T4>,
|
|
99
|
+
o4: PipedOperator<T4, T5>,
|
|
100
|
+
o5: PipedOperator<T5, T6>,
|
|
101
|
+
o6: PipedOperator<T6, T7>,
|
|
102
|
+
o7: PipedOperator<T7, T8>,
|
|
103
|
+
o8: PipedOperator<T8, T9>,
|
|
104
|
+
o9: PipedOperator<T9, O>
|
|
105
|
+
) => IStreamBuilder<O>) &
|
|
106
|
+
(<T2, T3, T4, T5, T6, T7, T8, T9, T10, O>(
|
|
107
|
+
o1: PipedOperator<T, T2>,
|
|
108
|
+
o2: PipedOperator<T2, T3>,
|
|
109
|
+
o3: PipedOperator<T3, T4>,
|
|
110
|
+
o4: PipedOperator<T4, T5>,
|
|
111
|
+
o5: PipedOperator<T5, T6>,
|
|
112
|
+
o6: PipedOperator<T6, T7>,
|
|
113
|
+
o7: PipedOperator<T7, T8>,
|
|
114
|
+
o8: PipedOperator<T8, T9>,
|
|
115
|
+
o9: PipedOperator<T9, T10>,
|
|
116
|
+
o10: PipedOperator<T10, O>
|
|
117
|
+
) => IStreamBuilder<O>) &
|
|
118
|
+
(<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, O>(
|
|
119
|
+
o1: PipedOperator<T, T2>,
|
|
120
|
+
o2: PipedOperator<T2, T3>,
|
|
121
|
+
o3: PipedOperator<T3, T4>,
|
|
122
|
+
o4: PipedOperator<T4, T5>,
|
|
123
|
+
o5: PipedOperator<T5, T6>,
|
|
124
|
+
o6: PipedOperator<T6, T7>,
|
|
125
|
+
o7: PipedOperator<T7, T8>,
|
|
126
|
+
o8: PipedOperator<T8, T9>,
|
|
127
|
+
o9: PipedOperator<T9, T10>,
|
|
128
|
+
o10: PipedOperator<T10, T11>,
|
|
129
|
+
o11: PipedOperator<T11, O>
|
|
130
|
+
) => IStreamBuilder<O>) &
|
|
131
|
+
(<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, O>(
|
|
132
|
+
o1: PipedOperator<T, T2>,
|
|
133
|
+
o2: PipedOperator<T2, T3>,
|
|
134
|
+
o3: PipedOperator<T3, T4>,
|
|
135
|
+
o4: PipedOperator<T4, T5>,
|
|
136
|
+
o5: PipedOperator<T5, T6>,
|
|
137
|
+
o6: PipedOperator<T6, T7>,
|
|
138
|
+
o7: PipedOperator<T7, T8>,
|
|
139
|
+
o8: PipedOperator<T8, T9>,
|
|
140
|
+
o9: PipedOperator<T9, T10>,
|
|
141
|
+
o10: PipedOperator<T10, T11>,
|
|
142
|
+
o11: PipedOperator<T11, T12>,
|
|
143
|
+
o12: PipedOperator<T12, O>
|
|
144
|
+
) => IStreamBuilder<O>) &
|
|
145
|
+
(<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, O>(
|
|
146
|
+
o1: PipedOperator<T, T2>,
|
|
147
|
+
o2: PipedOperator<T2, T3>,
|
|
148
|
+
o3: PipedOperator<T3, T4>,
|
|
149
|
+
o4: PipedOperator<T4, T5>,
|
|
150
|
+
o5: PipedOperator<T5, T6>,
|
|
151
|
+
o6: PipedOperator<T6, T7>,
|
|
152
|
+
o7: PipedOperator<T7, T8>,
|
|
153
|
+
o8: PipedOperator<T8, T9>,
|
|
154
|
+
o9: PipedOperator<T9, T10>,
|
|
155
|
+
o10: PipedOperator<T10, T11>,
|
|
156
|
+
o11: PipedOperator<T11, T12>,
|
|
157
|
+
o12: PipedOperator<T12, T13>,
|
|
158
|
+
o13: PipedOperator<T13, O>
|
|
159
|
+
) => IStreamBuilder<O>) &
|
|
160
|
+
(<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, O>(
|
|
161
|
+
o1: PipedOperator<T, T2>,
|
|
162
|
+
o2: PipedOperator<T2, T3>,
|
|
163
|
+
o3: PipedOperator<T3, T4>,
|
|
164
|
+
o4: PipedOperator<T4, T5>,
|
|
165
|
+
o5: PipedOperator<T5, T6>,
|
|
166
|
+
o6: PipedOperator<T6, T7>,
|
|
167
|
+
o7: PipedOperator<T7, T8>,
|
|
168
|
+
o8: PipedOperator<T8, T9>,
|
|
169
|
+
o9: PipedOperator<T9, T10>,
|
|
170
|
+
o10: PipedOperator<T10, T11>,
|
|
171
|
+
o11: PipedOperator<T11, T12>,
|
|
172
|
+
o12: PipedOperator<T12, T13>,
|
|
173
|
+
o13: PipedOperator<T13, T14>,
|
|
174
|
+
o14: PipedOperator<T14, O>
|
|
175
|
+
) => IStreamBuilder<O>) &
|
|
176
|
+
(<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, O>(
|
|
177
|
+
o1: PipedOperator<T, T2>,
|
|
178
|
+
o2: PipedOperator<T2, T3>,
|
|
179
|
+
o3: PipedOperator<T3, T4>,
|
|
180
|
+
o4: PipedOperator<T4, T5>,
|
|
181
|
+
o5: PipedOperator<T5, T6>,
|
|
182
|
+
o6: PipedOperator<T6, T7>,
|
|
183
|
+
o7: PipedOperator<T7, T8>,
|
|
184
|
+
o8: PipedOperator<T8, T9>,
|
|
185
|
+
o9: PipedOperator<T9, T10>,
|
|
186
|
+
o10: PipedOperator<T10, T11>,
|
|
187
|
+
o11: PipedOperator<T11, T12>,
|
|
188
|
+
o12: PipedOperator<T12, T13>,
|
|
189
|
+
o13: PipedOperator<T13, T14>,
|
|
190
|
+
o14: PipedOperator<T14, T15>,
|
|
191
|
+
o15: PipedOperator<T15, O>
|
|
192
|
+
) => IStreamBuilder<O>) &
|
|
193
|
+
(<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, O>(
|
|
194
|
+
o1: PipedOperator<T, T2>,
|
|
195
|
+
o2: PipedOperator<T2, T3>,
|
|
196
|
+
o3: PipedOperator<T3, T4>,
|
|
197
|
+
o4: PipedOperator<T4, T5>,
|
|
198
|
+
o5: PipedOperator<T5, T6>,
|
|
199
|
+
o6: PipedOperator<T6, T7>,
|
|
200
|
+
o7: PipedOperator<T7, T8>,
|
|
201
|
+
o8: PipedOperator<T8, T9>,
|
|
202
|
+
o9: PipedOperator<T9, T10>,
|
|
203
|
+
o10: PipedOperator<T10, T11>,
|
|
204
|
+
o11: PipedOperator<T11, T12>,
|
|
205
|
+
o12: PipedOperator<T12, T13>,
|
|
206
|
+
o13: PipedOperator<T13, T14>,
|
|
207
|
+
o14: PipedOperator<T14, T15>,
|
|
208
|
+
o15: PipedOperator<T15, T16>,
|
|
209
|
+
o16: PipedOperator<T16, O>
|
|
210
|
+
) => IStreamBuilder<O>) &
|
|
211
|
+
(<
|
|
212
|
+
T2,
|
|
213
|
+
T3,
|
|
214
|
+
T4,
|
|
215
|
+
T5,
|
|
216
|
+
T6,
|
|
217
|
+
T7,
|
|
218
|
+
T8,
|
|
219
|
+
T9,
|
|
220
|
+
T10,
|
|
221
|
+
T11,
|
|
222
|
+
T12,
|
|
223
|
+
T13,
|
|
224
|
+
T14,
|
|
225
|
+
T15,
|
|
226
|
+
T16,
|
|
227
|
+
T17,
|
|
228
|
+
O,
|
|
229
|
+
>(
|
|
230
|
+
o1: PipedOperator<T, T2>,
|
|
231
|
+
o2: PipedOperator<T2, T3>,
|
|
232
|
+
o3: PipedOperator<T3, T4>,
|
|
233
|
+
o4: PipedOperator<T4, T5>,
|
|
234
|
+
o5: PipedOperator<T5, T6>,
|
|
235
|
+
o6: PipedOperator<T6, T7>,
|
|
236
|
+
o7: PipedOperator<T7, T8>,
|
|
237
|
+
o8: PipedOperator<T8, T9>,
|
|
238
|
+
o9: PipedOperator<T9, T10>,
|
|
239
|
+
o10: PipedOperator<T10, T11>,
|
|
240
|
+
o11: PipedOperator<T11, T12>,
|
|
241
|
+
o12: PipedOperator<T12, T13>,
|
|
242
|
+
o13: PipedOperator<T13, T14>,
|
|
243
|
+
o14: PipedOperator<T14, T15>,
|
|
244
|
+
o15: PipedOperator<T15, T16>,
|
|
245
|
+
o16: PipedOperator<T16, T17>,
|
|
246
|
+
o17: PipedOperator<T17, O>
|
|
247
|
+
) => IStreamBuilder<O>) &
|
|
248
|
+
(<
|
|
249
|
+
T2,
|
|
250
|
+
T3,
|
|
251
|
+
T4,
|
|
252
|
+
T5,
|
|
253
|
+
T6,
|
|
254
|
+
T7,
|
|
255
|
+
T8,
|
|
256
|
+
T9,
|
|
257
|
+
T10,
|
|
258
|
+
T11,
|
|
259
|
+
T12,
|
|
260
|
+
T13,
|
|
261
|
+
T14,
|
|
262
|
+
T15,
|
|
263
|
+
T16,
|
|
264
|
+
T17,
|
|
265
|
+
T18,
|
|
266
|
+
O,
|
|
267
|
+
>(
|
|
268
|
+
o1: PipedOperator<T, T2>,
|
|
269
|
+
o2: PipedOperator<T2, T3>,
|
|
270
|
+
o3: PipedOperator<T3, T4>,
|
|
271
|
+
o4: PipedOperator<T4, T5>,
|
|
272
|
+
o5: PipedOperator<T5, T6>,
|
|
273
|
+
o6: PipedOperator<T6, T7>,
|
|
274
|
+
o7: PipedOperator<T7, T8>,
|
|
275
|
+
o8: PipedOperator<T8, T9>,
|
|
276
|
+
o9: PipedOperator<T9, T10>,
|
|
277
|
+
o10: PipedOperator<T10, T11>,
|
|
278
|
+
o11: PipedOperator<T11, T12>,
|
|
279
|
+
o12: PipedOperator<T12, T13>,
|
|
280
|
+
o13: PipedOperator<T13, T14>,
|
|
281
|
+
o14: PipedOperator<T14, T15>,
|
|
282
|
+
o15: PipedOperator<T15, T16>,
|
|
283
|
+
o16: PipedOperator<T16, T17>,
|
|
284
|
+
o17: PipedOperator<T17, T18>,
|
|
285
|
+
o18: PipedOperator<T18, O>
|
|
286
|
+
) => IStreamBuilder<O>) &
|
|
287
|
+
(<
|
|
288
|
+
T2,
|
|
289
|
+
T3,
|
|
290
|
+
T4,
|
|
291
|
+
T5,
|
|
292
|
+
T6,
|
|
293
|
+
T7,
|
|
294
|
+
T8,
|
|
295
|
+
T9,
|
|
296
|
+
T10,
|
|
297
|
+
T11,
|
|
298
|
+
T12,
|
|
299
|
+
T13,
|
|
300
|
+
T14,
|
|
301
|
+
T15,
|
|
302
|
+
T16,
|
|
303
|
+
T17,
|
|
304
|
+
T18,
|
|
305
|
+
T19,
|
|
306
|
+
O,
|
|
307
|
+
>(
|
|
308
|
+
o1: PipedOperator<T, T2>,
|
|
309
|
+
o2: PipedOperator<T2, T3>,
|
|
310
|
+
o3: PipedOperator<T3, T4>,
|
|
311
|
+
o4: PipedOperator<T4, T5>,
|
|
312
|
+
o5: PipedOperator<T5, T6>,
|
|
313
|
+
o6: PipedOperator<T6, T7>,
|
|
314
|
+
o7: PipedOperator<T7, T8>,
|
|
315
|
+
o8: PipedOperator<T8, T9>,
|
|
316
|
+
o9: PipedOperator<T9, T10>,
|
|
317
|
+
o10: PipedOperator<T10, T11>,
|
|
318
|
+
o11: PipedOperator<T11, T12>,
|
|
319
|
+
o12: PipedOperator<T12, T13>,
|
|
320
|
+
o13: PipedOperator<T13, T14>,
|
|
321
|
+
o14: PipedOperator<T14, T15>,
|
|
322
|
+
o15: PipedOperator<T15, T16>,
|
|
323
|
+
o16: PipedOperator<T16, T17>,
|
|
324
|
+
o17: PipedOperator<T17, T18>,
|
|
325
|
+
o18: PipedOperator<T18, T19>,
|
|
326
|
+
o19: PipedOperator<T19, O>
|
|
327
|
+
) => IStreamBuilder<O>) &
|
|
328
|
+
(<
|
|
329
|
+
T2,
|
|
330
|
+
T3,
|
|
331
|
+
T4,
|
|
332
|
+
T5,
|
|
333
|
+
T6,
|
|
334
|
+
T7,
|
|
335
|
+
T8,
|
|
336
|
+
T9,
|
|
337
|
+
T10,
|
|
338
|
+
T11,
|
|
339
|
+
T12,
|
|
340
|
+
T13,
|
|
341
|
+
T14,
|
|
342
|
+
T15,
|
|
343
|
+
T16,
|
|
344
|
+
T17,
|
|
345
|
+
T18,
|
|
346
|
+
T19,
|
|
347
|
+
T20,
|
|
348
|
+
O,
|
|
349
|
+
>(
|
|
350
|
+
o1: PipedOperator<T, T2>,
|
|
351
|
+
o2: PipedOperator<T2, T3>,
|
|
352
|
+
o3: PipedOperator<T3, T4>,
|
|
353
|
+
o4: PipedOperator<T4, T5>,
|
|
354
|
+
o5: PipedOperator<T5, T6>,
|
|
355
|
+
o6: PipedOperator<T6, T7>,
|
|
356
|
+
o7: PipedOperator<T7, T8>,
|
|
357
|
+
o8: PipedOperator<T8, T9>,
|
|
358
|
+
o9: PipedOperator<T9, T10>,
|
|
359
|
+
o10: PipedOperator<T10, T11>,
|
|
360
|
+
o11: PipedOperator<T11, T12>,
|
|
361
|
+
o12: PipedOperator<T12, T13>,
|
|
362
|
+
o13: PipedOperator<T13, T14>,
|
|
363
|
+
o14: PipedOperator<T14, T15>,
|
|
364
|
+
o15: PipedOperator<T15, T16>,
|
|
365
|
+
o16: PipedOperator<T16, T17>,
|
|
366
|
+
o17: PipedOperator<T17, T18>,
|
|
367
|
+
o18: PipedOperator<T18, T19>,
|
|
368
|
+
o19: PipedOperator<T19, T20>,
|
|
369
|
+
o20: PipedOperator<T20, O>
|
|
370
|
+
) => IStreamBuilder<O>) &
|
|
371
|
+
(<O>(...operators: Array<PipedOperator<any, any>>) => IStreamBuilder<O>)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export type PipedOperator<I, O> = (
|
|
375
|
+
stream: IStreamBuilder<I>
|
|
376
|
+
) => IStreamBuilder<O>
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import murmurhash from "murmurhash-js"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A map that returns a default value for keys that are not present.
|
|
5
|
+
*/
|
|
6
|
+
export class DefaultMap<K, V> extends Map<K, V> {
|
|
7
|
+
constructor(
|
|
8
|
+
private defaultValue: () => V,
|
|
9
|
+
entries?: Iterable<[K, V]>
|
|
10
|
+
) {
|
|
11
|
+
super(entries)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get(key: K): V {
|
|
15
|
+
if (!this.has(key)) {
|
|
16
|
+
this.set(key, this.defaultValue())
|
|
17
|
+
}
|
|
18
|
+
return super.get(key)!
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Update the value for a key using a function.
|
|
23
|
+
*/
|
|
24
|
+
update(key: K, updater: (value: V) => V): V {
|
|
25
|
+
const value = this.get(key)
|
|
26
|
+
const newValue = updater(value)
|
|
27
|
+
this.set(key, newValue)
|
|
28
|
+
return newValue
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// JS engines have various limits on how many args can be passed to a function
|
|
33
|
+
// with a spread operator, so we need to split the operation into chunks
|
|
34
|
+
// 32767 is the max for Chrome 14, all others are higher
|
|
35
|
+
// TODO: investigate the performance of this and other approaches
|
|
36
|
+
const chunkSize = 30000
|
|
37
|
+
export function chunkedArrayPush(array: Array<unknown>, other: Array<unknown>) {
|
|
38
|
+
if (other.length <= chunkSize) {
|
|
39
|
+
array.push(...other)
|
|
40
|
+
} else {
|
|
41
|
+
for (let i = 0; i < other.length; i += chunkSize) {
|
|
42
|
+
const chunk = other.slice(i, i + chunkSize)
|
|
43
|
+
array.push(...chunk)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const hashCache = new WeakMap()
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Replacer function for JSON.stringify that converts unsupported types to strings
|
|
52
|
+
*/
|
|
53
|
+
function hashReplacer(_key: string, value: any): any {
|
|
54
|
+
if (typeof value === `bigint`) {
|
|
55
|
+
return String(value)
|
|
56
|
+
} else if (typeof value === `symbol`) {
|
|
57
|
+
return String(value)
|
|
58
|
+
} else if (typeof value === `function`) {
|
|
59
|
+
return String(value)
|
|
60
|
+
} else if (value === undefined) {
|
|
61
|
+
return `undefined`
|
|
62
|
+
} else if (value instanceof Map) {
|
|
63
|
+
return `Map(${JSON.stringify(Array.from(value.entries()), hashReplacer)})`
|
|
64
|
+
} else if (value instanceof Set) {
|
|
65
|
+
return `Set(${JSON.stringify(Array.from(value.values()), hashReplacer)})`
|
|
66
|
+
}
|
|
67
|
+
return value
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A hash method that caches the hash of a value in a week map
|
|
72
|
+
*/
|
|
73
|
+
export function hash(data: any): string {
|
|
74
|
+
if (
|
|
75
|
+
data === null ||
|
|
76
|
+
data === undefined ||
|
|
77
|
+
(typeof data !== `object` && typeof data !== `function`)
|
|
78
|
+
) {
|
|
79
|
+
// Can't be cached in the weak map because it's not an object
|
|
80
|
+
const serialized = JSON.stringify(data, hashReplacer)
|
|
81
|
+
return murmurhash.murmur3(serialized).toString(16)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (hashCache.has(data)) {
|
|
85
|
+
return hashCache.get(data)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const serialized = JSON.stringify(data, hashReplacer)
|
|
89
|
+
const hashValue = murmurhash.murmur3(serialized).toString(16)
|
|
90
|
+
hashCache.set(data, hashValue)
|
|
91
|
+
return hashValue
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function binarySearch<T>(
|
|
95
|
+
array: Array<T>,
|
|
96
|
+
value: T,
|
|
97
|
+
comparator: (a: T, b: T) => number
|
|
98
|
+
): number {
|
|
99
|
+
let low = 0
|
|
100
|
+
let high = array.length
|
|
101
|
+
while (low < high) {
|
|
102
|
+
const mid = Math.floor((low + high) / 2)
|
|
103
|
+
const comparison = comparator(array[mid]!, value)
|
|
104
|
+
if (comparison < 0) {
|
|
105
|
+
low = mid + 1
|
|
106
|
+
} else if (comparison > 0) {
|
|
107
|
+
high = mid
|
|
108
|
+
} else {
|
|
109
|
+
return mid
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return low
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Utility for generating unique IDs for objects and values.
|
|
117
|
+
* Uses WeakMap for object reference tracking and consistent hashing for primitives.
|
|
118
|
+
*/
|
|
119
|
+
export class ObjectIdGenerator {
|
|
120
|
+
private objectIds = new WeakMap<object, number>()
|
|
121
|
+
private nextId = 0
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Get a unique identifier for any value.
|
|
125
|
+
* - Objects: Uses WeakMap for reference-based identity
|
|
126
|
+
* - Primitives: Uses consistent string-based hashing
|
|
127
|
+
*/
|
|
128
|
+
getId(value: any): number {
|
|
129
|
+
// For primitives, use a simple hash of their string representation
|
|
130
|
+
if (typeof value !== `object` || value === null) {
|
|
131
|
+
const str = String(value)
|
|
132
|
+
let hashValue = 0
|
|
133
|
+
for (let i = 0; i < str.length; i++) {
|
|
134
|
+
const char = str.charCodeAt(i)
|
|
135
|
+
hashValue = (hashValue << 5) - hashValue + char
|
|
136
|
+
hashValue = hashValue & hashValue // Convert to 32-bit integer
|
|
137
|
+
}
|
|
138
|
+
return hashValue
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// For objects, use WeakMap to assign unique IDs
|
|
142
|
+
if (!this.objectIds.has(value)) {
|
|
143
|
+
this.objectIds.set(value, this.nextId++)
|
|
144
|
+
}
|
|
145
|
+
return this.objectIds.get(value)!
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Get a string representation of the ID for use in composite keys.
|
|
150
|
+
*/
|
|
151
|
+
getStringId(value: any): string {
|
|
152
|
+
if (value === null) return `null`
|
|
153
|
+
if (value === undefined) return `undefined`
|
|
154
|
+
if (typeof value !== `object`) return `str_${String(value)}`
|
|
155
|
+
|
|
156
|
+
return `obj_${this.getId(value)}`
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Global instance for cases where a shared object ID space is needed.
|
|
162
|
+
*/
|
|
163
|
+
export const globalObjectIdGenerator = new ObjectIdGenerator()
|