@fluidframework/merge-tree 3.1.0 → 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 (46) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.d.ts +1 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -7
  5. package/dist/index.js.map +1 -1
  6. package/dist/referencePositions.d.ts +0 -10
  7. package/dist/referencePositions.d.ts.map +1 -1
  8. package/dist/referencePositions.js +0 -16
  9. package/dist/referencePositions.js.map +1 -1
  10. package/dist/test/index.d.ts +1 -1
  11. package/dist/test/index.d.ts.map +1 -1
  12. package/dist/test/index.js +2 -5
  13. package/dist/test/index.js.map +1 -1
  14. package/lib/index.d.ts +1 -2
  15. package/lib/index.d.ts.map +1 -1
  16. package/lib/index.js +1 -2
  17. package/lib/index.js.map +1 -1
  18. package/lib/referencePositions.d.ts +0 -10
  19. package/lib/referencePositions.d.ts.map +1 -1
  20. package/lib/referencePositions.js +0 -14
  21. package/lib/referencePositions.js.map +1 -1
  22. package/lib/test/index.d.ts +1 -1
  23. package/lib/test/index.d.ts.map +1 -1
  24. package/lib/test/index.js +1 -1
  25. package/lib/test/index.js.map +1 -1
  26. package/package.json +16 -16
  27. package/src/index.ts +0 -17
  28. package/src/referencePositions.ts +0 -16
  29. package/dist/collections/index.d.ts +0 -6
  30. package/dist/collections/index.d.ts.map +0 -1
  31. package/dist/collections/index.js +0 -11
  32. package/dist/collections/index.js.map +0 -1
  33. package/dist/collections/rbTree.d.ts +0 -160
  34. package/dist/collections/rbTree.d.ts.map +0 -1
  35. package/dist/collections/rbTree.js +0 -496
  36. package/dist/collections/rbTree.js.map +0 -1
  37. package/lib/collections/index.d.ts +0 -6
  38. package/lib/collections/index.d.ts.map +0 -1
  39. package/lib/collections/index.js +0 -6
  40. package/lib/collections/index.js.map +0 -1
  41. package/lib/collections/rbTree.d.ts +0 -160
  42. package/lib/collections/rbTree.d.ts.map +0 -1
  43. package/lib/collections/rbTree.js +0 -492
  44. package/lib/collections/rbTree.js.map +0 -1
  45. package/src/collections/index.ts +0 -20
  46. package/src/collections/rbTree.ts +0 -721
@@ -1,721 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- /**
7
- * @internal
8
- */
9
- export const RBColor = {
10
- RED: 0,
11
- BLACK: 1,
12
- } as const;
13
-
14
- /**
15
- * @internal
16
- */
17
- export type RBColor = (typeof RBColor)[keyof typeof RBColor];
18
-
19
- /**
20
- * @internal
21
- */
22
- export interface RBNode<TKey, TData> {
23
- key: TKey;
24
- data: TData;
25
- left: RBNode<TKey, TData> | undefined;
26
- right: RBNode<TKey, TData> | undefined;
27
- color: RBColor;
28
- size: number;
29
- }
30
- /**
31
- * @internal
32
- */
33
- export interface IRBAugmentation<TKey, TData> {
34
- update(node: RBNode<TKey, TData>): void;
35
- }
36
- /**
37
- * @internal
38
- */
39
- export interface IRBMatcher<TKey, TData> {
40
- continueSubtree(node: RBNode<TKey, TData> | undefined, key: TKey): boolean;
41
- matchNode(node: RBNode<TKey, TData> | undefined, key: TKey): boolean;
42
- }
43
-
44
- /**
45
- * @internal
46
- */
47
- export interface RBNodeActions<TKey, TData> {
48
- infix?(node: RBNode<TKey, TData>): boolean;
49
- pre?(node: RBNode<TKey, TData>): boolean;
50
- post?(node: RBNode<TKey, TData>): boolean;
51
- showStructure?: boolean;
52
- }
53
-
54
- /**
55
- * @internal
56
- */
57
- export interface KeyComparer<TKey> {
58
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
59
- (a: TKey, b: TKey): number;
60
- }
61
-
62
- /**
63
- * @internal
64
- */
65
- export interface Property<TKey, TData> {
66
- key: TKey;
67
- data: TData;
68
- }
69
-
70
- /**
71
- * @internal
72
- */
73
- export interface PropertyAction<TKey, TData> {
74
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
75
- <TAccum>(p: Property<TKey, TData>, accum?: TAccum): boolean;
76
- }
77
-
78
- /**
79
- * @internal
80
- */
81
- export interface QProperty<TKey, TData> {
82
- key?: TKey;
83
- data?: TData;
84
- }
85
-
86
- /**
87
- * @internal
88
- */
89
- export type ConflictAction<TKey, TData> = (
90
- key: TKey,
91
- currentKey: TKey,
92
- data: TData,
93
- currentData: TData,
94
- ) => QProperty<TKey, TData>;
95
-
96
- /**
97
- * @internal
98
- */
99
- export interface SortedDictionary<TKey, TData> extends Dictionary<TKey, TData> {
100
- max(): Property<TKey, TData> | undefined;
101
- min(): Property<TKey, TData> | undefined;
102
- mapRange<TAccum>(
103
- action: PropertyAction<TKey, TData>,
104
- accum?: TAccum,
105
- start?: TKey,
106
- end?: TKey,
107
- ): void;
108
- }
109
-
110
- /**
111
- * @internal
112
- */
113
- export interface Dictionary<TKey, TData> {
114
- get(key: TKey): Property<TKey, TData> | undefined;
115
- put(key: TKey, data: TData, conflict?: ConflictAction<TKey, TData>): void;
116
- remove(key: TKey): void;
117
- map<TAccum>(action: PropertyAction<TKey, TData>, accum?: TAccum): void;
118
- }
119
-
120
- /**
121
- * @internal
122
- */
123
- export class RedBlackTree<TKey, TData> implements SortedDictionary<TKey, TData> {
124
- private root: RBNode<TKey, TData> | undefined;
125
-
126
- constructor(
127
- private readonly compareKeys: KeyComparer<TKey>,
128
- private readonly aug?: IRBAugmentation<TKey, TData>,
129
- ) {}
130
-
131
- private makeNode(key: TKey, data: TData, color: RBColor, size: number): RBNode<TKey, TData> {
132
- return { key, data, color, size } as unknown as RBNode<TKey, TData>;
133
- }
134
-
135
- private isRed(node: RBNode<TKey, TData> | undefined): boolean {
136
- return !!node && node.color === RBColor.RED;
137
- }
138
-
139
- private nodeSize(node: RBNode<TKey, TData> | undefined): number {
140
- return node ? node.size : 0;
141
- }
142
- public size(): number {
143
- return this.nodeSize(this.root);
144
- }
145
- public isEmpty(): boolean {
146
- return !this.root;
147
- }
148
- public get(key: TKey): RBNode<TKey, TData> | undefined {
149
- if (key !== undefined) {
150
- return this.nodeGet(this.root, key);
151
- }
152
- }
153
- private nodeGet(
154
- node: RBNode<TKey, TData> | undefined,
155
- key: TKey,
156
- ): RBNode<TKey, TData> | undefined {
157
- let _node = node;
158
- while (_node) {
159
- const cmp = this.compareKeys(key, _node.key);
160
- if (cmp < 0) {
161
- _node = _node.left;
162
- } else if (cmp > 0) {
163
- _node = _node.right;
164
- } else {
165
- return _node;
166
- }
167
- }
168
- }
169
- private contains(key: TKey): RBNode<TKey, TData> | undefined {
170
- return this.get(key);
171
- }
172
-
173
- public gather(key: TKey, matcher: IRBMatcher<TKey, TData>): RBNode<TKey, TData>[] {
174
- const results = [] as RBNode<TKey, TData>[];
175
- if (key !== undefined) {
176
- this.nodeGather(this.root, results, key, matcher);
177
- }
178
- return results;
179
- }
180
-
181
- private nodeGather(
182
- node: RBNode<TKey, TData> | undefined,
183
- results: RBNode<TKey, TData>[],
184
- key: TKey,
185
- matcher: IRBMatcher<TKey, TData>,
186
- ): void {
187
- if (node) {
188
- if (matcher.continueSubtree(node.left, key)) {
189
- this.nodeGather(node.left, results, key, matcher);
190
- }
191
- if (matcher.matchNode(node, key)) {
192
- results.push(node);
193
- }
194
- if (matcher.continueSubtree(node.right, key)) {
195
- this.nodeGather(node.right, results, key, matcher);
196
- }
197
- }
198
- }
199
-
200
- public walkExactMatchesForward(
201
- compareFn: (node: RBNode<TKey, TData>) => number,
202
- actionFn: (node: RBNode<TKey, TData>) => void,
203
- continueLeftFn: (number: number) => boolean,
204
- continueRightFn: (number: number) => boolean,
205
- ): void {
206
- this.nodeWalkExactMatchesForward(
207
- this.root,
208
- compareFn,
209
- actionFn,
210
- continueLeftFn,
211
- continueRightFn,
212
- );
213
- }
214
-
215
- private nodeWalkExactMatchesForward(
216
- node: RBNode<TKey, TData> | undefined,
217
- compareFn: (node: RBNode<TKey, TData>) => number,
218
- actionFn: (node: RBNode<TKey, TData>) => void,
219
- continueLeftFn: (number: number) => boolean,
220
- continueRightFn: (number: number) => boolean,
221
- ): void {
222
- if (!node) {
223
- return;
224
- }
225
- const result: number = compareFn(node);
226
- if (continueLeftFn(result)) {
227
- this.nodeWalkExactMatchesForward(
228
- node.left,
229
- compareFn,
230
- actionFn,
231
- continueLeftFn,
232
- continueRightFn,
233
- );
234
- }
235
- if (result === 0) {
236
- actionFn(node);
237
- }
238
- if (continueRightFn(result)) {
239
- this.nodeWalkExactMatchesForward(
240
- node.right,
241
- compareFn,
242
- actionFn,
243
- continueLeftFn,
244
- continueRightFn,
245
- );
246
- }
247
- }
248
-
249
- public walkExactMatchesBackward(
250
- compareFn: (node: RBNode<TKey, TData>) => number,
251
- actionFn: (node: RBNode<TKey, TData>) => void,
252
- continueLeftFn: (number: number) => boolean,
253
- continueRightFn: (number: number) => boolean,
254
- ): void {
255
- this.nodeWalkExactMatchesBackward(
256
- this.root,
257
- compareFn,
258
- actionFn,
259
- continueLeftFn,
260
- continueRightFn,
261
- );
262
- }
263
-
264
- private nodeWalkExactMatchesBackward(
265
- node: RBNode<TKey, TData> | undefined,
266
- compareFn: (node: RBNode<TKey, TData>) => number,
267
- actionFn: (node: RBNode<TKey, TData>) => void,
268
- continueLeftFn: (cmp: number) => boolean,
269
- continueRightFn: (cmp: number) => boolean,
270
- ): void {
271
- if (!node) {
272
- return;
273
- }
274
- const result: number = compareFn(node);
275
- if (continueRightFn(result)) {
276
- this.nodeWalkExactMatchesBackward(
277
- node.right,
278
- compareFn,
279
- actionFn,
280
- continueLeftFn,
281
- continueRightFn,
282
- );
283
- }
284
- if (result === 0) {
285
- actionFn(node);
286
- }
287
- if (continueLeftFn(result)) {
288
- this.nodeWalkExactMatchesBackward(
289
- node.left,
290
- compareFn,
291
- actionFn,
292
- continueLeftFn,
293
- continueRightFn,
294
- );
295
- }
296
- }
297
-
298
- public put(key: TKey, data: TData, conflict?: ConflictAction<TKey, TData>): void {
299
- if (key !== undefined) {
300
- if (data === undefined) {
301
- this.remove(key);
302
- } else {
303
- this.root = this.nodePut(this.root, key, data, conflict);
304
- this.root.color = RBColor.BLACK;
305
- }
306
- }
307
- }
308
-
309
- private nodePut(
310
- node: RBNode<TKey, TData> | undefined,
311
- key: TKey,
312
- data: TData,
313
- conflict?: ConflictAction<TKey, TData>,
314
- ): RBNode<TKey, TData> {
315
- let _node = node;
316
- if (_node) {
317
- const cmp = this.compareKeys(key, _node.key);
318
- if (cmp < 0) {
319
- _node.left = this.nodePut(_node.left, key, data, conflict);
320
- } else if (cmp > 0) {
321
- _node.right = this.nodePut(_node.right, key, data, conflict);
322
- } else {
323
- if (conflict) {
324
- const kd = conflict(key, _node.key, data, _node.data);
325
- if (kd.key) {
326
- _node.key = kd.key;
327
- }
328
- _node.data = kd.data ?? data;
329
- } else {
330
- _node.data = data;
331
- }
332
- }
333
- if (this.isRed(_node.right) && !this.isRed(_node.left)) {
334
- _node = this.rotateLeft(_node);
335
- }
336
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
337
- if (this.isRed(_node.left) && this.isRed(_node.left!.left)) {
338
- _node = this.rotateRight(_node);
339
- }
340
- if (this.isRed(_node.left) && this.isRed(_node.right)) {
341
- this.flipColors(_node);
342
- }
343
- _node.size = this.nodeSize(_node.left) + this.nodeSize(_node.right) + 1;
344
- if (this.aug) {
345
- this.updateLocal(_node);
346
- }
347
- return _node;
348
- } else {
349
- return this.makeNode(key, data, RBColor.RED, 1);
350
- }
351
- }
352
-
353
- private updateLocal(node: RBNode<TKey, TData>): void {
354
- if (this.aug) {
355
- if (this.isRed(node.left)) {
356
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
357
- this.aug.update(node.left!);
358
- }
359
- if (this.isRed(node.right)) {
360
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
361
- this.aug.update(node.right!);
362
- }
363
- this.aug.update(node);
364
- }
365
- }
366
-
367
- private nodeRemoveMin(node: RBNode<TKey, TData>): RBNode<TKey, TData> | undefined {
368
- let _node = node;
369
- if (_node.left) {
370
- if (!this.isRed(_node.left) && !this.isRed(_node.left.left)) {
371
- _node = this.moveRedLeft(_node);
372
- }
373
-
374
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
375
- _node.left = this.nodeRemoveMin(_node.left!);
376
- return this.balance(_node);
377
- }
378
- }
379
-
380
- public remove(key: TKey): void {
381
- if (key !== undefined) {
382
- if (!this.contains(key)) {
383
- return;
384
- }
385
-
386
- this.removeExisting(key);
387
- }
388
- // TODO: error on undefined key
389
- }
390
-
391
- public removeExisting(key: TKey): void {
392
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
393
- if (!this.isRed(this.root!.left) && !this.isRed(this.root!.right)) {
394
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
395
- this.root!.color = RBColor.RED;
396
- }
397
-
398
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
399
- this.root = this.nodeRemove(this.root!, key);
400
- }
401
-
402
- private nodeRemove(node: RBNode<TKey, TData>, key: TKey): RBNode<TKey, TData> | undefined {
403
- let _node = node;
404
- if (this.compareKeys(key, _node.key) < 0) {
405
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
406
- if (!this.isRed(_node.left) && !this.isRed(_node.left!.left)) {
407
- _node = this.moveRedLeft(_node);
408
- }
409
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
410
- _node.left = this.nodeRemove(_node.left!, key);
411
- } else {
412
- if (this.isRed(_node.left)) {
413
- _node = this.rotateRight(_node);
414
- }
415
- if (this.compareKeys(key, _node.key) === 0 && !_node.right) {
416
- return undefined;
417
- }
418
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
419
- if (!this.isRed(_node.right) && !this.isRed(_node.right!.left)) {
420
- _node = this.moveRedRight(_node);
421
- }
422
- if (this.compareKeys(key, _node.key) === 0) {
423
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
424
- const subtreeMin = this.nodeMin(_node.right!);
425
- _node.key = subtreeMin.key;
426
- _node.data = subtreeMin.data;
427
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
428
- _node.right = this.nodeRemoveMin(_node.right!);
429
- } else {
430
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
431
- _node.right = this.nodeRemove(_node.right!, key);
432
- }
433
- }
434
- return this.balance(_node);
435
- }
436
-
437
- /**
438
- * Finds the largest node that is less than or equal to a given key.
439
- */
440
- public floor(key: TKey): RBNode<TKey, TData> | undefined {
441
- if (!this.isEmpty()) {
442
- return this.nodeFloor(this.root, key);
443
- }
444
- }
445
-
446
- private nodeFloor(
447
- node: RBNode<TKey, TData> | undefined,
448
- key: TKey,
449
- ): RBNode<TKey, TData> | undefined {
450
- if (node) {
451
- const cmp = this.compareKeys(key, node.key);
452
- if (cmp === 0) {
453
- return node;
454
- } else if (cmp < 0) {
455
- return this.nodeFloor(node.left, key);
456
- } else {
457
- const rightFloor = this.nodeFloor(node.right, key);
458
- return rightFloor ?? node;
459
- }
460
- }
461
- }
462
-
463
- /**
464
- * Finds the smallest node that is greater than or equal to a given key.
465
- */
466
- public ceil(key: TKey): RBNode<TKey, TData> | undefined {
467
- if (!this.isEmpty()) {
468
- return this.nodeCeil(this.root, key);
469
- }
470
- }
471
-
472
- private nodeCeil(
473
- node: RBNode<TKey, TData> | undefined,
474
- key: TKey,
475
- ): RBNode<TKey, TData> | undefined {
476
- if (node) {
477
- const cmp = this.compareKeys(key, node.key);
478
- if (cmp === 0) {
479
- return node;
480
- } else if (cmp > 0) {
481
- return this.nodeCeil(node.right, key);
482
- } else {
483
- const leftCeil = this.nodeCeil(node.left, key);
484
- return leftCeil ?? node;
485
- }
486
- }
487
- }
488
-
489
- public min(): RBNode<TKey, TData> | undefined {
490
- if (this.root) {
491
- return this.nodeMin(this.root);
492
- }
493
- }
494
-
495
- private nodeMin(node: RBNode<TKey, TData>): RBNode<TKey, TData> {
496
- return node.left ? this.nodeMin(node.left) : node;
497
- }
498
-
499
- public max(): RBNode<TKey, TData> | undefined {
500
- if (this.root) {
501
- return this.nodeMax(this.root);
502
- }
503
- }
504
-
505
- private nodeMax(node: RBNode<TKey, TData>): RBNode<TKey, TData> {
506
- return node.right ? this.nodeMax(node.right) : node;
507
- }
508
-
509
- private rotateRight(node: RBNode<TKey, TData>): RBNode<TKey, TData> {
510
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
511
- const leftChild = node.left!;
512
- node.left = leftChild.right;
513
- leftChild.right = node;
514
- leftChild.color = leftChild.right.color;
515
- leftChild.right.color = RBColor.RED;
516
- leftChild.size = node.size;
517
- node.size = this.nodeSize(node.left) + this.nodeSize(node.right) + 1;
518
- if (this.aug) {
519
- this.updateLocal(node);
520
- this.updateLocal(leftChild);
521
- }
522
- return leftChild;
523
- }
524
-
525
- private rotateLeft(node: RBNode<TKey, TData>): RBNode<TKey, TData> {
526
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
527
- const rightChild = node.right!;
528
- node.right = rightChild.left;
529
- rightChild.left = node;
530
- rightChild.color = rightChild.left.color;
531
- rightChild.left.color = RBColor.RED;
532
- rightChild.size = node.size;
533
- node.size = this.nodeSize(node.left) + this.nodeSize(node.right) + 1;
534
- if (this.aug) {
535
- this.updateLocal(node);
536
- this.updateLocal(rightChild);
537
- }
538
- return rightChild;
539
- }
540
-
541
- private oppositeColor(c: RBColor): RBColor {
542
- return c === RBColor.BLACK ? RBColor.RED : RBColor.BLACK;
543
- }
544
-
545
- private flipColors(node: RBNode<TKey, TData>): void {
546
- node.color = this.oppositeColor(node.color);
547
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
548
- node.left!.color = this.oppositeColor(node.left!.color);
549
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
550
- node.right!.color = this.oppositeColor(node.right!.color);
551
- }
552
-
553
- private moveRedLeft(node: RBNode<TKey, TData>): RBNode<TKey, TData> {
554
- let _node = node;
555
- this.flipColors(_node);
556
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
557
- if (this.isRed(_node.right!.left)) {
558
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
559
- _node.right = this.rotateRight(_node.right!);
560
- _node = this.rotateLeft(_node);
561
- this.flipColors(_node);
562
- }
563
- return _node;
564
- }
565
-
566
- private moveRedRight(node: RBNode<TKey, TData>): RBNode<TKey, TData> {
567
- let _node = node;
568
- this.flipColors(_node);
569
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
570
- if (this.isRed(_node.left!.left)) {
571
- _node = this.rotateRight(_node);
572
- this.flipColors(_node);
573
- }
574
- return _node;
575
- }
576
-
577
- private balance(input: RBNode<TKey, TData>): RBNode<TKey, TData> {
578
- let node: RBNode<TKey, TData> | undefined = input;
579
- if (this.isRed(node.right)) {
580
- node = this.rotateLeft(node);
581
- }
582
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
583
- if (this.isRed(node.left) && this.isRed(node.left!.left)) {
584
- node = this.rotateRight(node);
585
- }
586
- if (this.isRed(node.left) && this.isRed(node.right)) {
587
- this.flipColors(node);
588
- }
589
- node.size = this.nodeSize(node.left) + this.nodeSize(node.right) + 1;
590
- if (this.aug) {
591
- this.aug.update(node);
592
- }
593
- return node;
594
- }
595
-
596
- public mapRange<TAccum>(
597
- action: PropertyAction<TKey, TData>,
598
- accum?: TAccum,
599
- start?: TKey,
600
- end?: TKey,
601
- ): void {
602
- this.nodeMap(this.root, action, accum, start, end);
603
- }
604
-
605
- public map<TAccum>(action: PropertyAction<TKey, TData>, accum?: TAccum): void {
606
- // TODO: optimize to avoid comparisons
607
- this.nodeMap(this.root, action, accum);
608
- }
609
-
610
- public keys(): TKey[] {
611
- const keyList: TKey[] = [];
612
- const actions: RBNodeActions<TKey, TData> = {
613
- showStructure: true,
614
- infix: (node) => {
615
- keyList.push(node.key);
616
- return true;
617
- },
618
- };
619
- this.walk(actions);
620
- return keyList;
621
- }
622
-
623
- /**
624
- * Depth-first traversal with custom action; if action returns
625
- * false, traversal is halted.
626
- * @param action - action to apply to each node
627
- */
628
- public walk(actions: RBNodeActions<TKey, TData>): void {
629
- this.nodeWalk(this.root, actions);
630
- }
631
-
632
- public walkBackward(actions: RBNodeActions<TKey, TData>): void {
633
- this.nodeWalkBackward(this.root, actions);
634
- }
635
-
636
- private nodeWalk(
637
- node: RBNode<TKey, TData> | undefined,
638
- actions: RBNodeActions<TKey, TData>,
639
- ): boolean {
640
- let go = true;
641
- if (node) {
642
- if (actions.pre && (!!actions.showStructure || node.color === RBColor.BLACK)) {
643
- go = actions.pre(node);
644
- }
645
- if (node.left) {
646
- go = this.nodeWalk(node.left, actions);
647
- }
648
- if (go && actions.infix && (!!actions.showStructure || node.color === RBColor.BLACK)) {
649
- go = actions.infix(node);
650
- }
651
- if (go) {
652
- go = this.nodeWalk(node.right, actions);
653
- }
654
- if (go && actions.post && (!!actions.showStructure || node.color === RBColor.BLACK)) {
655
- go = actions.post(node);
656
- }
657
- }
658
- return go;
659
- }
660
-
661
- private nodeWalkBackward(
662
- node: RBNode<TKey, TData> | undefined,
663
- actions: RBNodeActions<TKey, TData>,
664
- ): boolean {
665
- let go = true;
666
- if (node) {
667
- if (actions.pre && (!!actions.showStructure || node.color === RBColor.BLACK)) {
668
- go = actions.pre(node);
669
- }
670
- if (node.right) {
671
- go = this.nodeWalkBackward(node.right, actions);
672
- }
673
- if (go && actions.infix && (!!actions.showStructure || node.color === RBColor.BLACK)) {
674
- go = actions.infix(node);
675
- }
676
- if (go) {
677
- go = this.nodeWalkBackward(node.left, actions);
678
- }
679
- if (go && actions.post && (!!actions.showStructure || node.color === RBColor.BLACK)) {
680
- go = actions.post(node);
681
- }
682
- }
683
- return go;
684
- }
685
-
686
- private nodeMap<TAccum>(
687
- node: RBNode<TKey, TData> | undefined,
688
- action: PropertyAction<TKey, TData>,
689
- accum?: TAccum,
690
- start?: TKey,
691
- end?: TKey,
692
- ): boolean {
693
- let _start = start;
694
- let _end = end;
695
- if (!node) {
696
- return true;
697
- }
698
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy
699
- if (_start === undefined) {
700
- _start = this.nodeMin(node).key;
701
- }
702
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy
703
- if (_end === undefined) {
704
- _end = this.nodeMax(node).key;
705
- }
706
- const cmpStart = this.compareKeys(_start, node.key);
707
- const cmpEnd = this.compareKeys(_end, node.key);
708
- let go = true;
709
- if (cmpStart < 0) {
710
- go = this.nodeMap(node.left, action, accum, _start, _end);
711
- }
712
- if (go && cmpStart <= 0 && cmpEnd >= 0) {
713
- // REVIEW: test for black node here
714
- go = action(node, accum);
715
- }
716
- if (go && cmpEnd > 0) {
717
- go = this.nodeMap(node.right, action, accum, _start, _end);
718
- }
719
- return go;
720
- }
721
- }