@fluidframework/matrix 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191258

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +4 -3
  3. package/dist/handlecache.js +3 -3
  4. package/dist/handlecache.js.map +1 -1
  5. package/dist/handletable.d.ts +8 -1
  6. package/dist/handletable.d.ts.map +1 -1
  7. package/dist/handletable.js +11 -3
  8. package/dist/handletable.js.map +1 -1
  9. package/dist/matrix.d.ts.map +1 -1
  10. package/dist/matrix.js +17 -18
  11. package/dist/matrix.js.map +1 -1
  12. package/dist/packageVersion.d.ts +1 -1
  13. package/dist/packageVersion.js +1 -1
  14. package/dist/packageVersion.js.map +1 -1
  15. package/dist/permutationvector.d.ts.map +1 -1
  16. package/dist/permutationvector.js +11 -8
  17. package/dist/permutationvector.js.map +1 -1
  18. package/dist/serialization.js +2 -2
  19. package/dist/serialization.js.map +1 -1
  20. package/dist/sparsearray2d.d.ts.map +1 -1
  21. package/dist/sparsearray2d.js +1 -0
  22. package/dist/sparsearray2d.js.map +1 -1
  23. package/dist/undoprovider.js +8 -9
  24. package/dist/undoprovider.js.map +1 -1
  25. package/lib/handlecache.js +1 -1
  26. package/lib/handlecache.js.map +1 -1
  27. package/lib/handletable.d.ts +8 -1
  28. package/lib/handletable.d.ts.map +1 -1
  29. package/lib/handletable.js +11 -3
  30. package/lib/handletable.js.map +1 -1
  31. package/lib/matrix.d.ts.map +1 -1
  32. package/lib/matrix.js +3 -4
  33. package/lib/matrix.js.map +1 -1
  34. package/lib/packageVersion.d.ts +1 -1
  35. package/lib/packageVersion.js +1 -1
  36. package/lib/packageVersion.js.map +1 -1
  37. package/lib/permutationvector.d.ts.map +1 -1
  38. package/lib/permutationvector.js +6 -3
  39. package/lib/permutationvector.js.map +1 -1
  40. package/lib/serialization.js +1 -1
  41. package/lib/serialization.js.map +1 -1
  42. package/lib/sparsearray2d.d.ts.map +1 -1
  43. package/lib/sparsearray2d.js +1 -0
  44. package/lib/sparsearray2d.js.map +1 -1
  45. package/lib/undoprovider.js +5 -6
  46. package/lib/undoprovider.js.map +1 -1
  47. package/package.json +27 -31
  48. package/src/handlecache.ts +1 -1
  49. package/src/handletable.ts +22 -2
  50. package/src/matrix.ts +2 -1
  51. package/src/packageVersion.ts +1 -1
  52. package/src/permutationvector.ts +3 -4
  53. package/src/serialization.ts +1 -1
  54. package/src/sparsearray2d.ts +1 -0
  55. package/src/undoprovider.ts +1 -1
  56. package/dist/bspSet.d.ts +0 -125
  57. package/dist/bspSet.d.ts.map +0 -1
  58. package/dist/bspSet.js +0 -425
  59. package/dist/bspSet.js.map +0 -1
  60. package/dist/productSet.d.ts +0 -61
  61. package/dist/productSet.d.ts.map +0 -1
  62. package/dist/productSet.js +0 -679
  63. package/dist/productSet.js.map +0 -1
  64. package/dist/split.d.ts +0 -41
  65. package/dist/split.d.ts.map +0 -1
  66. package/dist/split.js +0 -127
  67. package/dist/split.js.map +0 -1
  68. package/lib/bspSet.d.ts +0 -125
  69. package/lib/bspSet.d.ts.map +0 -1
  70. package/lib/bspSet.js +0 -402
  71. package/lib/bspSet.js.map +0 -1
  72. package/lib/productSet.d.ts +0 -61
  73. package/lib/productSet.d.ts.map +0 -1
  74. package/lib/productSet.js +0 -665
  75. package/lib/productSet.js.map +0 -1
  76. package/lib/split.d.ts +0 -41
  77. package/lib/split.d.ts.map +0 -1
  78. package/lib/split.js +0 -116
  79. package/lib/split.js.map +0 -1
  80. package/src/bspSet.ts +0 -722
  81. package/src/productSet.ts +0 -1038
  82. package/src/split.ts +0 -171
package/src/bspSet.ts DELETED
@@ -1,722 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- import { __assign } from "tslib";
7
- /** An interface for representing a readonly pair */
8
- export type Pair<S, T = S> = readonly [S, T];
9
-
10
- export const pair = <S, T = S>(left: S, right: T): Pair<S, T> => [left, right];
11
-
12
- // using this polyfill, because `Object.assign` is not supported in IE.
13
- const ObjectAssign: typeof Object.assign = __assign;
14
-
15
- export enum SetKind {
16
- Dense,
17
- Empty,
18
- }
19
-
20
- interface TreeNode<Left, Right> {
21
- readonly left: Left;
22
- readonly right: Right;
23
- }
24
-
25
- interface KeyNode<Key, Exact> {
26
- readonly key: Key;
27
- readonly pathKey: Key;
28
- readonly isExact: Exact;
29
- }
30
-
31
- export type Empty = SetKind.Empty;
32
-
33
- /** The term *Dense* means that a given subset contains all the elements of its particular
34
- * bounds. E.g. the whole set would be dense w.r.t. the bounds of the whole space. Or
35
- * if a set represents an interval [a, b), then it would be dense, if there are no holes in it,
36
- * i.e. the set is represented exactly using the current bounds.
37
- */
38
- export type Dense = SetKind.Dense;
39
-
40
- export const dense = SetKind.Dense;
41
- export const empty = SetKind.Empty;
42
-
43
- type KeyUnexact<Key> = KeyNode<Key, false>;
44
-
45
- /** In the BSP-set, each node carries with it implicit bounds just by the position in the tree.
46
- * Furthermore, it can carry around a key. The key can either be an approximation, i.e. an upper bound
47
- * or it can be *exact*. Exact means, that the whole set can be exactly represented in terms of just the key.
48
- *
49
- * One might wonder, why we don't prune the tree at this point. This has to do with the fact that we are
50
- * representing arbitrary sets and so even though one of two sets could be represented exactly the other
51
- * might not be able to yet. In this case we need to unfold the key by splitting further. In order to avoid
52
- * excessive splitting and pruning, we just carry around the key but allow the tree to also be materialized, on-demand.
53
- */
54
- type KeyExact<Key> = KeyNode<Key, true>;
55
-
56
- type KeyUndefined = KeyNode<undefined, false>;
57
- type KeyDefined<Key> = KeyUnexact<Key> | KeyExact<Key>;
58
-
59
- type BalancePropertyHelper<Key, Left, Right> = TreeNode<
60
- UntypedSparse<Key> | Left,
61
- UntypedSparse<Key> | Right
62
- >;
63
-
64
- type TreeDefined<Key> =
65
- | BalancePropertyHelper<Key, Empty, Dense>
66
- | BalancePropertyHelper<Key, Dense, Empty>;
67
- type TreeUndefined = TreeNode<undefined, undefined>;
68
-
69
- type KeyDefinednessProperty<Key> = KeyDefined<Key> | KeyUndefined;
70
-
71
- export type UntypedSparse<Key> =
72
- | (KeyDefinednessProperty<Key> & TreeDefined<Key>)
73
- | (KeyDefined<Key> & TreeUndefined);
74
- /** The term *untyped* refers to the tree representation of a BSP set. Because BSP set trees are only compared in terms
75
- * of their structure, we need to ensure that cuts occur at the same exact points across all possible sets. This is
76
- * enforced by the fact, that at construction time, we attach an `Id` to each BSP set and only allow operations to
77
- * occur on sets with the same `Id`.
78
- *
79
- * The BSP set becomes *untyped*, when we drop that `Id`; now it is possible to operate on sets that are incompatible.
80
- * Doing this, however, allows us to store the set operations only once per set as opposed to carrying them around with
81
- * every node.
82
- */
83
- export type UntypedBspSet<Key> = Empty | Dense | UntypedSparse<Key>;
84
-
85
- /** A set is considred *sparse*, if we know that w.r.t. to it's bounds it is neither empty, nor dense. */
86
- interface Sparse<Key extends Cachable<Key>, Id> {
87
- setOperations: SetOperations<Key, Id>;
88
- root: UntypedSparse<Key>;
89
- }
90
- export type BspSet<Key extends Cachable<Key>, Id> = Empty | Dense | Sparse<Key, Id>;
91
-
92
- export interface KeyCache<T> {
93
- depth?: number;
94
- split?: Pair<Pair<CachedKey<T>, number>>;
95
- }
96
- export type CachedKey<T> = T & KeyCache<T>;
97
- export type Cachable<T> = Disjoint<keyof T, keyof KeyCache<T>>;
98
-
99
- export type Disjoint<T, U> = [T, U] extends [Exclude<T, U>, Exclude<U, T>] ? any : never;
100
- export type RequireAtLeastOne<T> = {
101
- [K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>;
102
- }[keyof T];
103
-
104
- /** This is a concrete set operations implementation, tagged with an arbitrary id. */
105
- export interface SetOperations<Key extends Cachable<Key>, Id> {
106
- /** Id here is just a phantom type, so that we can associate the various set instances together */
107
- readonly id: Id;
108
-
109
- /** Split the key into two. This will only be called when the current key is incomparable with an element.
110
- * E.g. this would never be called if the key is already a 1x1 rectangle. */
111
- readonly split: (key: CachedKey<Key>) => Pair<Pair<CachedKey<Key>, number>>;
112
-
113
- /** Tells, if a given key can be split further */
114
- readonly canSplit: (key: CachedKey<Key>) => boolean;
115
-
116
- /** Tells if two keys overlap at all. */
117
- readonly meets: (key1: Key, key2: Key) => boolean;
118
-
119
- /** Intersect the keys, if it is possible to exactly respresent their intersection.
120
- * An implementation is never required to compute the intersection as this is just an optimization.
121
- * Precondition: It is guaranteed that the keys meet and that they are incomparable.
122
- */
123
- readonly intersect: (key1: Key, key2: Key) => Key | undefined;
124
-
125
- /** Unions the keys, if it is possible to exactly represent their union.
126
- * An implementation is never required to compute the union as this is just an optimization.
127
- * Precondition: It is guaranteed that the keys are incomparable.
128
- */
129
- readonly union: (key1: Key, key2: Key) => Key | undefined;
130
-
131
- /** Computes the set difference between two keys, if it is possible to exactly represent their set difference.
132
- * An implementation is never required to compute the difference as this is just an optimization.
133
- * Precondition: It is guaranteed that the keys meet.
134
- */
135
- readonly except: (key1: Key, key2: Key) => Key | undefined;
136
-
137
- /** Compare two keys */
138
- readonly compare: (key1: Key, key2: Key) => -1 | 0 | 1 | undefined;
139
-
140
- /** The top element of the set. */
141
- readonly top: Key;
142
- }
143
-
144
- export const cacheKeySplitting =
145
- <Key>(
146
- splitFunction: (key: CachedKey<Key>) => Pair<Pair<CachedKey<Key>, number>>,
147
- top: CachedKey<Key>,
148
- maxDepth: number = 10,
149
- ) =>
150
- (key: CachedKey<Key>) => {
151
- if (key.split !== undefined) {
152
- return key.split;
153
- }
154
-
155
- const split = splitFunction(key);
156
- const depth = key === top ? 0 : key.depth;
157
- if (depth !== undefined && depth < maxDepth) {
158
- key.split = split;
159
- split[0][0].depth = depth + 1;
160
- split[1][0].depth = depth + 1;
161
- }
162
-
163
- return split;
164
- };
165
-
166
- export function fromUntyped<Key extends Cachable<Key>, Id>(
167
- setOperations: SetOperations<Key, Id>,
168
- root: UntypedBspSet<Key>,
169
- ): BspSet<Key, Id> {
170
- if (root === empty || root === dense) {
171
- return root;
172
- }
173
- return { setOperations, root };
174
- }
175
-
176
- const sparse = <Key, Exact, Left, Right>(
177
- left: Left,
178
- right: Right,
179
- pathKey: Key,
180
- key: Key,
181
- isExact: Exact,
182
- ) => ({ key, pathKey, left, right, isExact });
183
-
184
- function fromKey<Key>(pathKey: Key, key: Key, isExact: boolean): UntypedSparse<Key> {
185
- if (isExact) {
186
- return sparse(undefined, undefined, pathKey, key, true as const);
187
- }
188
-
189
- return sparse(undefined, undefined, pathKey, key, false as const);
190
- }
191
-
192
- export function lazy<Key extends Cachable<Key>, Id>(
193
- setOperations: SetOperations<Key, Id>,
194
- pathKey: Key,
195
- key: Key,
196
- ): UntypedBspSet<Key> {
197
- if (!setOperations.meets(pathKey, key)) {
198
- return empty;
199
- }
200
- const cmp = setOperations.compare(pathKey, key);
201
- if (cmp !== undefined) {
202
- if (cmp <= 0) {
203
- return dense;
204
- }
205
-
206
- return fromKey(pathKey, key, true);
207
- }
208
-
209
- // this is not exactly necessary, but increases the amount of exact nodes and thus we can often
210
- // prune earlier.
211
- // Also, having intersect always work guarantees exact nodes, thus allowing for more efficient
212
- // storage and computation.
213
- const newKey = setOperations.intersect(pathKey, key);
214
-
215
- if (newKey !== undefined) {
216
- return fromKey(pathKey, newKey, true);
217
- }
218
-
219
- return fromKey(pathKey, key, false);
220
- }
221
-
222
- export function createFromKey<Key extends Cachable<Key>, Id>(
223
- uncachedSetOperations: SetOperations<Key, Id>,
224
- ) {
225
- const setOperations = {
226
- ...uncachedSetOperations,
227
- split: cacheKeySplitting(uncachedSetOperations.split, uncachedSetOperations.top),
228
- };
229
- return (key: Key) => fromUntyped(setOperations, lazy(setOperations, setOperations.top, key));
230
- }
231
-
232
- function unionExact<Key extends Cachable<Key>, Id>(
233
- setOperations: SetOperations<Key, Id>,
234
- left: UntypedBspSet<Key> & KeyExact<Key>,
235
- right: UntypedBspSet<Key> & KeyExact<Key>,
236
- ) {
237
- const { pathKey, key: leftKey } = left;
238
- const { key: rightKey } = right;
239
-
240
- const cmp = setOperations.compare(leftKey, rightKey);
241
- if (cmp !== undefined) {
242
- return cmp < 0 ? right : left;
243
- }
244
-
245
- const combinedKey = setOperations.union(leftKey, rightKey);
246
- if (combinedKey !== undefined) {
247
- const combinedCmp = setOperations.compare(combinedKey, pathKey);
248
- if (combinedCmp !== undefined && combinedCmp === 0) {
249
- return dense;
250
- }
251
- return fromKey(pathKey, combinedKey, true);
252
- }
253
- return undefined;
254
- }
255
-
256
- /** This is an local combination, not a proper union. We use it to have simpler code elsewhere */
257
- function combineChildren<Key>(
258
- left: UntypedBspSet<Key>,
259
- right: UntypedBspSet<Key>,
260
- ): Empty | Dense | (UntypedSparse<Key> & TreeDefined<Key>) {
261
- if (left === empty) {
262
- if (right === empty) {
263
- return empty;
264
- }
265
-
266
- return sparse(left, right, undefined, undefined, false as const);
267
- }
268
-
269
- if (right === empty) {
270
- return sparse(left, right, undefined, undefined, false as const);
271
- }
272
-
273
- if (left === dense) {
274
- if (right === dense) {
275
- return dense;
276
- }
277
- return sparse(left, right, undefined, undefined, false as const);
278
- }
279
-
280
- return sparse(left, right, undefined, undefined, false as const);
281
- }
282
-
283
- function materialize<Key extends Cachable<Key>, Id>(
284
- setOperations: SetOperations<Key, Id>,
285
- set: UntypedSparse<Key>,
286
- ): UntypedSparse<Key> & TreeDefined<Key> {
287
- if (set.left !== undefined) {
288
- return set;
289
- }
290
-
291
- const [[left], [right]] = setOperations.split(set.pathKey);
292
- const lChild = lazy(setOperations, left, set.key);
293
- const rChild = lazy(setOperations, right, set.key);
294
-
295
- const res = combineChildren<Key>(lChild, rChild);
296
-
297
- if (res === empty || res === dense) {
298
- throw new Error("incorrect set operations implementation");
299
- }
300
-
301
- // first check, that res actually has the desired type
302
- const typeCheck: TreeDefined<Key> = res;
303
-
304
- const setAlias: UntypedSparse<Key> = set;
305
- return ObjectAssign(setAlias, {
306
- left: typeCheck.left,
307
- right: typeCheck.right,
308
- });
309
- }
310
-
311
- export function unionUntyped<Key extends Cachable<Key>, Id>(
312
- setOperations: SetOperations<Key, Id>,
313
- left: UntypedBspSet<Key>,
314
- right: UntypedBspSet<Key>,
315
- ): UntypedBspSet<Key> {
316
- if (right === empty) {
317
- return left;
318
- }
319
- if (right === dense) {
320
- return right;
321
- }
322
- if (left === empty) {
323
- return right;
324
- }
325
- if (left === dense) {
326
- return left;
327
- }
328
-
329
- if (left.isExact && right.isExact) {
330
- const res = unionExact<Key, Id>(setOperations, left, right);
331
- if (res !== undefined) {
332
- return res;
333
- }
334
- }
335
-
336
- const newLeft = materialize<Key, Id>(setOperations, left);
337
- const newRight = materialize<Key, Id>(setOperations, right);
338
-
339
- const lChild = unionUntyped(setOperations, newLeft.left, newRight.left);
340
- const rChild = unionUntyped(setOperations, newLeft.right, newRight.right);
341
-
342
- return combineChildren(lChild, rChild);
343
- }
344
-
345
- export function union<Key extends Cachable<Key>, Id>(
346
- left: BspSet<Key, Id>,
347
- right: BspSet<Key, Id>,
348
- ): BspSet<Key, Id> {
349
- if (right === empty) {
350
- return left;
351
- }
352
- if (right === dense) {
353
- return right;
354
- }
355
- if (left === empty) {
356
- return right;
357
- }
358
- if (left === dense) {
359
- return left;
360
- }
361
-
362
- return fromUntyped(
363
- left.setOperations,
364
- unionUntyped<Key, Id>(left.setOperations, left.root, right.root),
365
- );
366
- }
367
-
368
- function intersectExact<Key extends Cachable<Key>, Id>(
369
- setOperations: SetOperations<Key, Id>,
370
- left: UntypedBspSet<Key> & KeyExact<Key>,
371
- right: UntypedBspSet<Key> & KeyExact<Key>,
372
- ) {
373
- const { pathKey, key: leftKey } = left;
374
- const { key: rightKey } = right;
375
-
376
- if (!setOperations.meets(leftKey, rightKey)) {
377
- return empty;
378
- }
379
-
380
- const cmp = setOperations.compare(leftKey, rightKey);
381
- if (cmp !== undefined) {
382
- return cmp < 0 ? left : right;
383
- }
384
-
385
- const combinedKey = setOperations.intersect(leftKey, rightKey);
386
- if (combinedKey !== undefined) {
387
- return fromKey(pathKey, combinedKey, true);
388
- }
389
-
390
- return undefined;
391
- }
392
-
393
- export function intersectUntyped<Key extends Cachable<Key>, Id>(
394
- setOperations: SetOperations<Key, Id>,
395
- left: UntypedBspSet<Key>,
396
- right: UntypedBspSet<Key>,
397
- ): UntypedBspSet<Key> {
398
- if (left === empty) {
399
- return left;
400
- }
401
- if (right === empty) {
402
- return right;
403
- }
404
- if (left === dense) {
405
- return right;
406
- }
407
- if (right === dense) {
408
- return left;
409
- }
410
-
411
- if (left.isExact && right.isExact) {
412
- const res = intersectExact<Key, Id>(setOperations, left, right);
413
- if (res !== undefined) {
414
- return res;
415
- }
416
- }
417
-
418
- const newLeft = materialize<Key, Id>(setOperations, left);
419
- const newRight = materialize<Key, Id>(setOperations, right);
420
-
421
- const lChild = intersectUntyped(setOperations, newLeft.left, newRight.left);
422
- const rChild = intersectUntyped(setOperations, newLeft.right, newRight.right);
423
-
424
- return combineChildren(lChild, rChild);
425
- }
426
-
427
- export function intersect<Key extends Cachable<Key>, Id>(
428
- left: BspSet<Key, Id>,
429
- right: BspSet<Key, Id>,
430
- ): BspSet<Key, Id> {
431
- if (left === empty) {
432
- return left;
433
- }
434
- if (right === empty) {
435
- return right;
436
- }
437
- if (left === dense) {
438
- return right;
439
- }
440
- if (right === dense) {
441
- return left;
442
- }
443
-
444
- return fromUntyped(
445
- left.setOperations,
446
- intersectUntyped<Key, Id>(left.setOperations, left.root, right.root),
447
- );
448
- }
449
-
450
- export function meetsUntyped<Key extends Cachable<Key>, Id>(
451
- setOperations: SetOperations<Key, Id>,
452
- left: UntypedBspSet<Key>,
453
- right: UntypedBspSet<Key>,
454
- ): boolean {
455
- if (left === empty || right === empty) {
456
- return false;
457
- }
458
- if (left === dense || right === dense) {
459
- return true;
460
- }
461
- if (left.isExact && right.isExact) {
462
- return setOperations.meets(left.key, right.key);
463
- }
464
-
465
- const newLeft = materialize<Key, Id>(setOperations, left);
466
- const newRight = materialize<Key, Id>(setOperations, right);
467
-
468
- return (
469
- meetsUntyped(setOperations, newLeft.left, newRight.left) ||
470
- meetsUntyped(setOperations, newLeft.right, newRight.right)
471
- );
472
- }
473
-
474
- export function meets<Key extends Cachable<Key>, Id>(
475
- left: BspSet<Key, Id>,
476
- right: BspSet<Key, Id>,
477
- ): boolean {
478
- if (left === empty || right === empty) {
479
- return false;
480
- }
481
- if (left === dense || right === dense) {
482
- return true;
483
- }
484
- return meetsUntyped<Key, Id>(left.setOperations, left.root, right.root);
485
- }
486
-
487
- function exceptExact<Key extends Cachable<Key>, Id>(
488
- setOperations: SetOperations<Key, Id>,
489
- left: UntypedSparse<Key> & KeyExact<Key>,
490
- right: KeyExact<Key>,
491
- ) {
492
- const { pathKey, key: leftKey } = left;
493
- const { key: rightKey } = right;
494
-
495
- if (!setOperations.meets(leftKey, rightKey)) {
496
- return left;
497
- }
498
-
499
- const combinedKey = setOperations.except(leftKey, rightKey);
500
- if (combinedKey !== undefined) {
501
- return fromKey(pathKey, combinedKey, true);
502
- }
503
-
504
- return undefined;
505
- }
506
-
507
- export function exceptUntyped<Key extends Cachable<Key>, Id>(
508
- setOperations: SetOperations<Key, Id>,
509
- left: UntypedBspSet<Key>,
510
- right: UntypedBspSet<Key>,
511
- ): UntypedBspSet<Key> {
512
- if (left === empty) {
513
- return left;
514
- }
515
- if (right === empty) {
516
- return left;
517
- }
518
- if (right === dense) {
519
- return empty;
520
- }
521
- if (left === dense) {
522
- const newRight_inner = materialize<Key, Id>(setOperations, right);
523
- const lChild_inner = exceptUntyped(setOperations, dense, newRight_inner.left);
524
- const rChild_inner = exceptUntyped(setOperations, dense, newRight_inner.right);
525
- return combineChildren(lChild_inner, rChild_inner);
526
- }
527
- if (left.isExact && right.isExact) {
528
- const res = exceptExact<Key, Id>(setOperations, left, right);
529
- if (res !== undefined) {
530
- return res;
531
- }
532
- }
533
- const newLeft = materialize<Key, Id>(setOperations, left);
534
- const newRight = materialize<Key, Id>(setOperations, right);
535
-
536
- const lChild = exceptUntyped(setOperations, newLeft.left, newRight.left);
537
- const rChild = exceptUntyped(setOperations, newLeft.right, newRight.right);
538
-
539
- return combineChildren(lChild, rChild);
540
- }
541
-
542
- export function except<Key extends Cachable<Key>, Id>(
543
- left: BspSet<Key, Id>,
544
- right: BspSet<Key, Id>,
545
- ): BspSet<Key, Id> {
546
- if (left === empty) {
547
- return left;
548
- }
549
- if (right === empty) {
550
- return left;
551
- }
552
- if (right === dense) {
553
- return empty;
554
- }
555
- if (left === dense) {
556
- return fromUntyped(
557
- right.setOperations,
558
- exceptUntyped<Key, Id>(right.setOperations, left, right.root),
559
- );
560
- }
561
-
562
- return fromUntyped(
563
- left.setOperations,
564
- exceptUntyped<Key, Id>(left.setOperations, left.root, right.root),
565
- );
566
- }
567
-
568
- const compareExact = <Key extends Cachable<Key>, Id>(
569
- setOperations: SetOperations<Key, Id>,
570
- left: KeyExact<Key>,
571
- right: KeyExact<Key>,
572
- ) => setOperations.compare(left.key, right.key);
573
-
574
- export function combineCmp(left: -1 | 0 | 1 | undefined, right: -1 | 0 | 1 | undefined) {
575
- if (left === undefined || right === undefined) {
576
- return undefined;
577
- }
578
- if (left === 0) {
579
- return right;
580
- }
581
- if (right === 0) {
582
- return left;
583
- }
584
- return left === right ? left : undefined;
585
- }
586
-
587
- export function compareUntyped<Key extends Cachable<Key>, Id>(
588
- setOperations: SetOperations<Key, Id>,
589
- left: UntypedBspSet<Key>,
590
- right: UntypedBspSet<Key>,
591
- ): -1 | 0 | 1 | undefined {
592
- if (left === right) {
593
- return 0;
594
- }
595
-
596
- if (left === empty) {
597
- return -1;
598
- }
599
-
600
- if (right === empty) {
601
- return 1;
602
- }
603
-
604
- if (left === dense) {
605
- if (right === dense) {
606
- return 0;
607
- }
608
-
609
- return 1;
610
- }
611
-
612
- if (right === dense) {
613
- return -1;
614
- }
615
-
616
- if (left.isExact && right.isExact) {
617
- return compareExact(setOperations, left, right);
618
- }
619
-
620
- const newLeft = materialize<Key, Id>(setOperations, left);
621
- const newRight = materialize<Key, Id>(setOperations, right);
622
- const lCmp = compareUntyped(setOperations, newLeft.left, newRight.left);
623
- if (lCmp === undefined) {
624
- return undefined;
625
- }
626
-
627
- const rCmp = compareUntyped(setOperations, newLeft.right, newRight.right);
628
-
629
- if (rCmp === undefined) {
630
- return undefined;
631
- }
632
-
633
- return combineCmp(lCmp, rCmp);
634
- }
635
-
636
- export function compare<Key extends Cachable<Key>, Id>(
637
- left: BspSet<Key, Id>,
638
- right: BspSet<Key, Id>,
639
- ) {
640
- if (left === right) {
641
- return 0;
642
- }
643
-
644
- if (left === empty) {
645
- return -1;
646
- }
647
-
648
- if (right === empty) {
649
- return 1;
650
- }
651
-
652
- if (left === dense) {
653
- if (right === dense) {
654
- return 0;
655
- }
656
-
657
- return 1;
658
- }
659
-
660
- if (right === dense) {
661
- return -1;
662
- }
663
-
664
- return compareUntyped<Key, Id>(left.setOperations, left.root, right.root);
665
- }
666
-
667
- export const symmetricDiff = <Key extends Cachable<Key>, Id>(
668
- left: BspSet<Key, Id>,
669
- right: BspSet<Key, Id>,
670
- ) => union(except(left, right), except(right, left));
671
-
672
- export const complement = <Key extends Cachable<Key>, Id>(set: BspSet<Key, Id>) =>
673
- except(dense, set);
674
-
675
- function getNodeCountUntyped<T>(set: UntypedBspSet<T> | undefined): number {
676
- if (set === undefined || set === empty || set === dense) {
677
- return 0;
678
- }
679
-
680
- return getNodeCountUntyped(set.left) + getNodeCountUntyped(set.right) + 1;
681
- }
682
-
683
- export function getNodeCount<Key extends Cachable<Key>, Id>(set: BspSet<Key, Id>) {
684
- if (set === empty || set === dense) {
685
- return 0;
686
- }
687
- return getNodeCountUntyped(set.root);
688
- }
689
-
690
- function forEachKeyUntyped<Key extends Cachable<Key>, Id>(
691
- setOperations: SetOperations<Key, Id>,
692
- set: UntypedBspSet<Key>,
693
- f: (key: Key) => boolean,
694
- ): boolean {
695
- function loop(pathKey: Key, set_inner: UntypedBspSet<Key>): boolean {
696
- if (set_inner === empty) {
697
- return true;
698
- }
699
- if (set_inner === dense) {
700
- return f(pathKey);
701
- }
702
- if (set_inner.isExact) {
703
- return f(set_inner.key);
704
- }
705
-
706
- const newSet = materialize<Key, Id>(setOperations, set_inner);
707
- const [[left], [right]] = setOperations.split(pathKey);
708
- return loop(left, newSet.left) && loop(right, newSet.right);
709
- }
710
-
711
- return loop(setOperations.top, set);
712
- }
713
-
714
- export function forEachKey<Key extends Cachable<Key>, Id>(
715
- set: Empty | Sparse<Key, Id>,
716
- f: (key: Key) => boolean,
717
- ): boolean {
718
- if (set === empty) {
719
- return true;
720
- }
721
- return forEachKeyUntyped(set.setOperations, set.root, f);
722
- }