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