@calcit/ternary-tree 0.0.24 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/map.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { TernaryTreeKind, hashGenerator, } from "./types.mjs";
2
- import { divideTernarySizes, cmp, dataEqual } from "./utils.mjs";
2
+ import { cmp, dataEqual } from "./utils.mjs";
3
3
  let emptyBranch = null;
4
4
  let nilResult = null;
5
5
  function getMax(tree) {
@@ -29,7 +29,6 @@ function getMin(tree) {
29
29
  }
30
30
  }
31
31
  export function getMapDepth(tree) {
32
- // console.log( "calling...", tree)
33
32
  if (tree == null) {
34
33
  return 0;
35
34
  }
@@ -37,11 +36,21 @@ export function getMapDepth(tree) {
37
36
  case TernaryTreeKind.ternaryTreeLeaf:
38
37
  return 1;
39
38
  case TernaryTreeKind.ternaryTreeBranch:
40
- return Math.max(getMapDepth(tree.left), getMapDepth(tree.middle), getMapDepth(tree.right)) + 1;
39
+ return tree.depth; // use cached depth — O(1)
41
40
  default:
42
41
  throw new Error("Unknown");
43
42
  }
44
43
  }
44
+ function decideMapBranchDepth(left, middle, right) {
45
+ // Inline getMapDepth to avoid 3 indirect function calls per invocation
46
+ let dl = left == null ? 0 : left.kind === TernaryTreeKind.ternaryTreeLeaf ? 1 : left.depth;
47
+ let dm = middle == null ? 0 : middle.kind === TernaryTreeKind.ternaryTreeLeaf ? 1 : middle.depth;
48
+ let dr = right == null ? 0 : right.kind === TernaryTreeKind.ternaryTreeLeaf ? 1 : right.depth;
49
+ let d = dl > dm ? dl : dm;
50
+ if (dr > d)
51
+ d = dr;
52
+ return d + 1;
53
+ }
45
54
  function createLeaf(k, v) {
46
55
  let result = {
47
56
  kind: TernaryTreeKind.ternaryTreeLeaf,
@@ -81,7 +90,8 @@ function makeTernaryTreeMap(size, offset, xs) {
81
90
  left: createLeafFromHashEntry(leftPair),
82
91
  middle: createLeafFromHashEntry(middlePair),
83
92
  right: emptyBranch,
84
- depth: 1,
93
+ depth: 2,
94
+ size: leftPair.pairs.length + middlePair.pairs.length,
85
95
  };
86
96
  return result;
87
97
  }
@@ -96,15 +106,21 @@ function makeTernaryTreeMap(size, offset, xs) {
96
106
  left: createLeafFromHashEntry(leftPair),
97
107
  middle: createLeafFromHashEntry(middlePair),
98
108
  right: createLeafFromHashEntry(rightPair),
99
- depth: 1,
109
+ depth: 2,
110
+ size: leftPair.pairs.length + middlePair.pairs.length + rightPair.pairs.length,
100
111
  };
101
112
  return result;
102
113
  }
103
114
  default: {
104
- let divided = divideTernarySizes(size);
105
- let left = makeTernaryTreeMap(divided.left, offset, xs);
106
- let middle = makeTernaryTreeMap(divided.middle, offset + divided.left, xs);
107
- let right = makeTernaryTreeMap(divided.right, offset + divided.left + divided.middle, xs);
115
+ // Inline divideTernarySizes to avoid heap object allocation per recursive call
116
+ let extra = size % 3;
117
+ let groupSize = (size / 3) | 0;
118
+ let leftSize = groupSize + (extra === 2 ? 1 : 0);
119
+ let middleSize = groupSize + (extra === 1 ? 1 : 0);
120
+ let rightSize = groupSize + (extra === 2 ? 1 : 0);
121
+ let left = makeTernaryTreeMap(leftSize, offset, xs);
122
+ let middle = makeTernaryTreeMap(middleSize, offset + leftSize, xs);
123
+ let right = makeTernaryTreeMap(rightSize, offset + leftSize + middleSize, xs);
108
124
  let result = {
109
125
  kind: TernaryTreeKind.ternaryTreeBranch,
110
126
  maxHash: getMax(right),
@@ -112,7 +128,8 @@ function makeTernaryTreeMap(size, offset, xs) {
112
128
  left: left,
113
129
  middle: middle,
114
130
  right: right,
115
- depth: Math.max(getMapDepth(left), getMapDepth(middle), getMapDepth(right)) + 1,
131
+ depth: decideMapBranchDepth(left, middle, right),
132
+ size: mapLen(left) + mapLen(middle) + mapLen(right),
116
133
  };
117
134
  return result;
118
135
  }
@@ -159,24 +176,21 @@ export function initTernaryTreeMap(t) {
159
176
  }
160
177
  // use for..in for performance
161
178
  export function initTernaryTreeMapFromArray(t) {
162
- let groupBuffers = {};
179
+ // Use Map instead of Record for better performance with numeric keys
180
+ let groupBuffers = new Map();
163
181
  let xs = [];
164
- for (let idx = 0; idx < t.length; idx++) {
182
+ const length = t.length;
183
+ for (let idx = 0; idx < length; idx++) {
165
184
  let k = t[idx][0];
166
185
  let v = t[idx][1];
167
186
  let h = hashGenerator(k);
168
- if (groupBuffers[h] != null) {
169
- let branch = groupBuffers[h];
170
- if (branch != null) {
171
- branch.push([k, v]);
172
- }
173
- else {
174
- throw new Error("Expected referece to pairs");
175
- }
187
+ let branch = groupBuffers.get(h);
188
+ if (branch != null) {
189
+ branch.push([k, v]);
176
190
  }
177
191
  else {
178
192
  let pairs = [[k, v]];
179
- groupBuffers[h] = pairs;
193
+ groupBuffers.set(h, pairs);
180
194
  xs.push({
181
195
  hash: h,
182
196
  pairs: pairs,
@@ -205,7 +219,7 @@ export function mapLen(tree) {
205
219
  case TernaryTreeKind.ternaryTreeLeaf:
206
220
  return tree.elements.length;
207
221
  case TernaryTreeKind.ternaryTreeBranch:
208
- return mapLen(tree.left) + mapLen(tree.middle) + mapLen(tree.right); // TODO
222
+ return tree.size; // O(1) via cached size field
209
223
  default:
210
224
  throw new Error("Unknown");
211
225
  }
@@ -267,13 +281,13 @@ export function isMapEmpty(tree) {
267
281
  }
268
282
  export function isMapOfOne(tree, counted = 0) {
269
283
  if (tree == null) {
270
- return true;
284
+ return false;
271
285
  }
272
286
  switch (tree.kind) {
273
287
  case TernaryTreeKind.ternaryTreeLeaf:
274
- return false;
288
+ return tree.elements.length === 1;
275
289
  case TernaryTreeKind.ternaryTreeBranch:
276
- return tree.left == null && tree.middle == null && tree.right == null;
290
+ return mapLenBound(tree, 2) === 1;
277
291
  default:
278
292
  throw new Error("Unknown");
279
293
  }
@@ -285,11 +299,15 @@ function collectHashSortedArray(tree, acc, idx) {
285
299
  else {
286
300
  switch (tree.kind) {
287
301
  case TernaryTreeKind.ternaryTreeLeaf: {
288
- for (let i = 0; i < tree.elements.length; i++) {
289
- let item = tree.elements[i];
290
- acc[idx.value] = item;
291
- idx.value = idx.value + 1;
302
+ // Cache elements and current index to reduce property access
303
+ const elements = tree.elements;
304
+ const length = elements.length;
305
+ let currentIdx = idx.value;
306
+ for (let i = 0; i < length; i++) {
307
+ acc[currentIdx] = elements[i];
308
+ currentIdx++;
292
309
  }
310
+ idx.value = currentIdx;
293
311
  break;
294
312
  }
295
313
  case TernaryTreeKind.ternaryTreeBranch: {
@@ -317,8 +335,10 @@ function collectOrderedHashEntries(tree, acc, idx) {
317
335
  else {
318
336
  switch (tree.kind) {
319
337
  case TernaryTreeKind.ternaryTreeLeaf: {
320
- acc[idx.value] = { hash: tree.hash, pairs: tree.elements };
321
- idx.value = idx.value + 1;
338
+ // Cache current index to reduce property access
339
+ const currentIdx = idx.value;
340
+ acc[currentIdx] = { hash: tree.hash, pairs: tree.elements };
341
+ idx.value = currentIdx + 1;
322
342
  break;
323
343
  }
324
344
  case TernaryTreeKind.ternaryTreeBranch: {
@@ -344,85 +364,88 @@ export function contains(originalTree, item) {
344
364
  if (originalTree == null) {
345
365
  return false;
346
366
  }
347
- // TODO
348
367
  // reduce redundant computation by reusing hash result
349
368
  let hx = hashGenerator(item);
350
369
  let tree = originalTree;
351
370
  whileLoop: while (tree != null) {
352
371
  if (tree.kind === TernaryTreeKind.ternaryTreeLeaf) {
353
372
  if (hx === tree.hash) {
354
- let size = tree.elements.length;
373
+ // Cache elements length to avoid repeated property access
374
+ const elements = tree.elements;
375
+ const size = elements.length;
355
376
  for (let idx = 0; idx < size; idx++) {
356
- let pair = tree.elements[idx];
357
- if (dataEqual(pair[0], item)) {
377
+ if (dataEqual(elements[idx][0], item)) {
358
378
  return true;
359
379
  }
360
380
  }
361
381
  }
362
382
  return false;
363
383
  }
364
- // echo "looking for: ", hx, " ", item, " in ", tree.formatInline(true)
365
- if (tree.left == null) {
384
+ // Optimize branch navigation with early exits
385
+ const left = tree.left;
386
+ if (left == null) {
366
387
  return false;
367
388
  }
368
- if (tree.left.kind === TernaryTreeKind.ternaryTreeLeaf) {
369
- if (hx < tree.left.hash) {
389
+ if (left.kind === TernaryTreeKind.ternaryTreeLeaf) {
390
+ if (hx < left.hash) {
370
391
  return false;
371
392
  }
372
- if (tree.left.hash === hx) {
373
- tree = tree.left;
374
- continue whileLoop; // notice, it jumps to while loop
393
+ if (left.hash === hx) {
394
+ tree = left;
395
+ continue whileLoop;
375
396
  }
376
397
  }
377
398
  else {
378
- if (hx < tree.left.minHash) {
399
+ if (hx < left.minHash) {
379
400
  return false;
380
401
  }
381
- if (hx <= tree.left.maxHash) {
382
- tree = tree.left;
383
- continue whileLoop; // notice, it jumps to while loop
402
+ if (hx <= left.maxHash) {
403
+ tree = left;
404
+ continue whileLoop;
384
405
  }
385
406
  }
386
- if (tree.middle == null) {
407
+ const middle = tree.middle;
408
+ if (middle == null) {
387
409
  return false;
388
410
  }
389
- if (tree.middle.kind === TernaryTreeKind.ternaryTreeLeaf) {
390
- if (hx < tree.middle.hash) {
411
+ if (middle.kind === TernaryTreeKind.ternaryTreeLeaf) {
412
+ if (hx < middle.hash) {
391
413
  return false;
392
414
  }
393
- if (tree.middle.hash === hx) {
394
- tree = tree.middle;
395
- continue whileLoop; // notice, it jumps to while loop
415
+ if (middle.hash === hx) {
416
+ tree = middle;
417
+ continue whileLoop;
396
418
  }
397
419
  }
398
420
  else {
399
- if (hx < tree.middle.minHash) {
421
+ if (hx < middle.minHash) {
400
422
  return false;
401
423
  }
402
- if (hx <= tree.middle.maxHash) {
403
- tree = tree.middle;
404
- continue whileLoop; // notice, it jumps to while loop
424
+ if (hx <= middle.maxHash) {
425
+ tree = middle;
426
+ continue whileLoop;
405
427
  }
406
428
  }
407
- if (tree.right == null) {
429
+ const right = tree.right;
430
+ if (right == null) {
408
431
  return false;
409
432
  }
410
- if (tree.right.kind === TernaryTreeKind.ternaryTreeLeaf) {
411
- if (hx < tree.right.hash) {
433
+ if (right.kind === TernaryTreeKind.ternaryTreeLeaf) {
434
+ if (hx < right.hash) {
412
435
  return false;
413
436
  }
414
- if (tree.right.hash === hx) {
415
- tree = tree.right;
416
- continue whileLoop; // notice, it jumps to while loop
437
+ if (right.hash === hx) {
438
+ tree = right;
439
+ continue whileLoop;
417
440
  }
418
441
  }
419
442
  else {
420
- if (hx < tree.right.minHash) {
443
+ if (hx < right.minHash) {
421
444
  return false;
422
445
  }
423
- if (hx <= tree.right.maxHash) {
424
- tree = tree.right;
425
- continue whileLoop; // notice, it jumps to while loop
446
+ if (hx <= right.maxHash) {
447
+ tree = right;
448
+ continue whileLoop;
426
449
  }
427
450
  }
428
451
  return false;
@@ -434,77 +457,81 @@ export function mapGetDefault(originalTree, item, v0) {
434
457
  let tree = originalTree;
435
458
  whileLoop: while (tree != null) {
436
459
  if (tree.kind === TernaryTreeKind.ternaryTreeLeaf) {
437
- let size = tree.elements.length;
460
+ // Cache elements array to avoid repeated property access
461
+ const elements = tree.elements;
462
+ const size = elements.length;
438
463
  for (let i = 0; i < size; i++) {
439
- let pair = tree.elements[i];
440
- if (dataEqual(pair[0], item)) {
441
- return pair[1];
464
+ if (dataEqual(elements[i][0], item)) {
465
+ return elements[i][1];
442
466
  }
443
467
  }
444
468
  return v0;
445
469
  }
446
- // echo "looking for: ", hx, " ", item, " in ", tree.formatInline
447
- if (tree.left == null) {
470
+ // Cache tree children to avoid repeated property access
471
+ const left = tree.left;
472
+ if (left == null) {
448
473
  return v0;
449
474
  }
450
- if (tree.left.kind == TernaryTreeKind.ternaryTreeLeaf) {
451
- if (hx < tree.left.hash) {
475
+ if (left.kind == TernaryTreeKind.ternaryTreeLeaf) {
476
+ if (hx < left.hash) {
452
477
  return v0;
453
478
  }
454
- if (tree.left.hash === hx) {
455
- tree = tree.left;
456
- continue whileLoop; // notice, it jumps to while loop
479
+ if (left.hash === hx) {
480
+ tree = left;
481
+ continue whileLoop;
457
482
  }
458
483
  }
459
484
  else {
460
- if (hx < tree.left.minHash) {
485
+ if (hx < left.minHash) {
461
486
  return v0;
462
487
  }
463
- if (hx <= tree.left.maxHash) {
464
- tree = tree.left;
465
- continue whileLoop; // notice, it jumps to while loop
488
+ if (hx <= left.maxHash) {
489
+ tree = left;
490
+ continue whileLoop;
466
491
  }
467
492
  }
468
- if (tree.middle == null) {
493
+ const middle = tree.middle;
494
+ if (middle == null) {
469
495
  return v0;
470
496
  }
471
- if (tree.middle.kind == TernaryTreeKind.ternaryTreeLeaf) {
472
- if (hx < tree.middle.hash) {
497
+ if (middle.kind == TernaryTreeKind.ternaryTreeLeaf) {
498
+ if (hx < middle.hash) {
473
499
  return v0;
474
500
  }
475
- if (tree.middle.hash === hx) {
476
- tree = tree.middle;
477
- continue whileLoop; // notice, it jumps to while loop
501
+ if (middle.hash === hx) {
502
+ tree = middle;
503
+ continue whileLoop;
478
504
  }
479
505
  }
480
506
  else {
481
- if (hx < tree.middle.minHash) {
507
+ if (hx < middle.minHash) {
482
508
  return v0;
483
509
  }
484
- if (hx <= tree.middle.maxHash) {
485
- tree = tree.middle;
486
- continue whileLoop; // notice, it jumps to while loop
510
+ if (hx <= middle.maxHash) {
511
+ tree = middle;
512
+ continue whileLoop;
487
513
  }
488
514
  }
489
- if (tree.right == null) {
515
+ const right = tree.right;
516
+ if (right == null) {
490
517
  return v0;
491
518
  }
492
- if (tree.right.kind == TernaryTreeKind.ternaryTreeLeaf) {
493
- if (hx < tree.right.hash) {
519
+ if (right.kind == TernaryTreeKind.ternaryTreeLeaf) {
520
+ if (hx < right.hash) {
494
521
  return v0;
495
522
  }
496
- if (tree.right.hash === hx) {
497
- tree = tree.right;
498
- continue whileLoop; // notice, it jumps to while loop
523
+ if (right.hash === hx) {
524
+ tree = right;
525
+ continue whileLoop;
499
526
  }
500
527
  }
501
528
  else {
502
- if (hx < tree.right.minHash) {
529
+ if (hx < right.minHash) {
503
530
  return v0;
504
531
  }
505
- if (hx <= tree.right.maxHash) {
506
- tree = tree.right;
507
- continue whileLoop; // notice, it jumps to while loop
532
+ if (hx <= right.maxHash) {
533
+ tree = right;
534
+ continue whileLoop;
508
535
  }
509
536
  }
510
537
  return v0;
@@ -524,7 +551,7 @@ export function checkMapStructure(tree) {
524
551
  throw new Error(`Bad hash at leaf node ${tree}`);
525
552
  }
526
553
  }
527
- if (mapLenBound(tree, 2) !== 1) {
554
+ if (mapLenBound(tree, 2) < 1) {
528
555
  throw new Error(`Bad len at leaf node ${tree}`);
529
556
  }
530
557
  }
@@ -619,46 +646,49 @@ function assocExisted(tree, key, item, thisHash = null) {
619
646
  throw new Error("Unexpected missing hash in assoc, found not branch");
620
647
  }
621
648
  if (rangeContainsHash(tree.left, thisHash)) {
622
- let result = {
649
+ let newLeft = assocExisted(tree.left, key, item, thisHash);
650
+ return {
623
651
  kind: TernaryTreeKind.ternaryTreeBranch,
624
652
  maxHash: tree.maxHash,
625
653
  minHash: tree.minHash,
626
- left: assocExisted(tree.left, key, item, thisHash),
654
+ left: newLeft,
627
655
  middle: tree.middle,
628
656
  right: tree.right,
629
- depth: 0, // TODO
657
+ depth: decideMapBranchDepth(newLeft, tree.middle, tree.right),
658
+ size: tree.size,
630
659
  };
631
- return result;
632
660
  }
633
661
  if (tree.middle == null) {
634
662
  throw new Error("Unexpected missing hash in assoc, found not branch");
635
663
  }
636
664
  if (rangeContainsHash(tree.middle, thisHash)) {
637
- let result = {
665
+ let newMiddle = assocExisted(tree.middle, key, item, thisHash);
666
+ return {
638
667
  kind: TernaryTreeKind.ternaryTreeBranch,
639
668
  maxHash: tree.maxHash,
640
669
  minHash: tree.minHash,
641
670
  left: tree.left,
642
- middle: assocExisted(tree.middle, key, item, thisHash),
671
+ middle: newMiddle,
643
672
  right: tree.right,
644
- depth: 0, // TODO
673
+ depth: decideMapBranchDepth(tree.left, newMiddle, tree.right),
674
+ size: tree.size,
645
675
  };
646
- return result;
647
676
  }
648
677
  if (tree.right == null) {
649
678
  throw new Error("Unexpected missing hash in assoc, found not branch");
650
679
  }
651
680
  if (rangeContainsHash(tree.right, thisHash)) {
652
- let result = {
681
+ let newRight = assocExisted(tree.right, key, item, thisHash);
682
+ return {
653
683
  kind: TernaryTreeKind.ternaryTreeBranch,
654
684
  maxHash: tree.maxHash,
655
685
  minHash: tree.minHash,
656
686
  left: tree.left,
657
687
  middle: tree.middle,
658
- right: assocExisted(tree.right, key, item, thisHash),
659
- depth: 0, // TODO
688
+ right: newRight,
689
+ depth: decideMapBranchDepth(tree.left, tree.middle, newRight),
690
+ size: tree.size,
660
691
  };
661
- return result;
662
692
  }
663
693
  throw new Error("Unexpected missing hash in assoc, found not branch");
664
694
  }
@@ -682,7 +712,8 @@ function assocNew(tree, key, item, thisHash = null) {
682
712
  left: tree,
683
713
  middle: childBranch,
684
714
  right: emptyBranch,
685
- depth: 0, // TODO
715
+ depth: decideMapBranchDepth(tree, childBranch, emptyBranch),
716
+ size: mapLen(tree) + 1,
686
717
  };
687
718
  return result;
688
719
  }
@@ -699,7 +730,8 @@ function assocNew(tree, key, item, thisHash = null) {
699
730
  left: childBranch,
700
731
  middle: tree,
701
732
  right: emptyBranch,
702
- depth: 0, // TODO
733
+ depth: decideMapBranchDepth(childBranch, tree, emptyBranch),
734
+ size: mapLen(tree) + 1,
703
735
  };
704
736
  return result;
705
737
  }
@@ -740,7 +772,8 @@ function assocNew(tree, key, item, thisHash = null) {
740
772
  left: childBranch,
741
773
  middle: tree.left,
742
774
  right: tree.middle,
743
- depth: 0, // TODO
775
+ depth: decideMapBranchDepth(childBranch, tree.left, tree.middle),
776
+ size: tree.size + 1,
744
777
  };
745
778
  return result;
746
779
  }
@@ -757,7 +790,8 @@ function assocNew(tree, key, item, thisHash = null) {
757
790
  left: childBranch,
758
791
  middle: tree,
759
792
  right: emptyBranch,
760
- depth: 0, // TODO
793
+ depth: decideMapBranchDepth(childBranch, tree, emptyBranch),
794
+ size: tree.size + 1,
761
795
  };
762
796
  return result;
763
797
  }
@@ -777,7 +811,8 @@ function assocNew(tree, key, item, thisHash = null) {
777
811
  left: tree.left,
778
812
  middle: childBranch,
779
813
  right: emptyBranch,
780
- depth: 0, // TODO
814
+ depth: decideMapBranchDepth(tree.left, childBranch, emptyBranch),
815
+ size: tree.size + 1,
781
816
  };
782
817
  return result;
783
818
  }
@@ -794,7 +829,8 @@ function assocNew(tree, key, item, thisHash = null) {
794
829
  left: tree.left,
795
830
  middle: tree.middle,
796
831
  right: childBranch,
797
- depth: 0, // TODO
832
+ depth: decideMapBranchDepth(tree.left, tree.middle, childBranch),
833
+ size: tree.size + 1,
798
834
  };
799
835
  return result;
800
836
  }
@@ -811,73 +847,79 @@ function assocNew(tree, key, item, thisHash = null) {
811
847
  left: tree,
812
848
  middle: childBranch,
813
849
  right: emptyBranch,
814
- depth: 0, // TODO
850
+ depth: decideMapBranchDepth(tree, childBranch, emptyBranch),
851
+ size: tree.size + 1,
815
852
  };
816
853
  return result;
817
854
  }
818
855
  }
819
856
  if (rangeContainsHash(tree.left, thisHash)) {
820
- let result = {
857
+ let newLeft = assocNew(tree.left, key, item, thisHash);
858
+ return {
821
859
  kind: TernaryTreeKind.ternaryTreeBranch,
822
860
  maxHash: tree.maxHash,
823
861
  minHash: tree.minHash,
824
- left: assocNew(tree.left, key, item, thisHash),
862
+ left: newLeft,
825
863
  middle: tree.middle,
826
864
  right: tree.right,
827
- depth: 0, // TODO
865
+ depth: decideMapBranchDepth(newLeft, tree.middle, tree.right),
866
+ size: tree.size + 1,
828
867
  };
829
- return result;
830
868
  }
831
869
  if (rangeContainsHash(tree.middle, thisHash)) {
832
- let result = {
870
+ let newMiddle = assocNew(tree.middle, key, item, thisHash);
871
+ return {
833
872
  kind: TernaryTreeKind.ternaryTreeBranch,
834
873
  maxHash: tree.maxHash,
835
874
  minHash: tree.minHash,
836
875
  left: tree.left,
837
- middle: assocNew(tree.middle, key, item, thisHash),
876
+ middle: newMiddle,
838
877
  right: tree.right,
839
- depth: 0, // TODO
878
+ depth: decideMapBranchDepth(tree.left, newMiddle, tree.right),
879
+ size: tree.size + 1,
840
880
  };
841
- return result;
842
881
  }
843
882
  if (rangeContainsHash(tree.right, thisHash)) {
844
- let result = {
883
+ let newRight = assocNew(tree.right, key, item, thisHash);
884
+ return {
845
885
  kind: TernaryTreeKind.ternaryTreeBranch,
846
886
  maxHash: tree.maxHash,
847
887
  minHash: tree.minHash,
848
888
  left: tree.left,
849
889
  middle: tree.middle,
850
- right: assocNew(tree.right, key, item, thisHash),
851
- depth: 0, // TODO
890
+ right: newRight,
891
+ depth: decideMapBranchDepth(tree.left, tree.middle, newRight),
892
+ size: tree.size + 1,
852
893
  };
853
- return result;
854
894
  }
855
895
  if (tree.middle == null) {
856
896
  throw new Error("unreachable. if inside range, then middle should be here");
857
897
  }
858
898
  if (thisHash < getMin(tree.middle)) {
859
- let result = {
899
+ let newLeft = assocNew(tree.left, key, item, thisHash);
900
+ return {
860
901
  kind: TernaryTreeKind.ternaryTreeBranch,
861
902
  maxHash: tree.maxHash,
862
903
  minHash: tree.minHash,
863
- left: assocNew(tree.left, key, item, thisHash),
904
+ left: newLeft,
864
905
  middle: tree.middle,
865
906
  right: tree.right,
866
- depth: 0, // TODO
907
+ depth: decideMapBranchDepth(newLeft, tree.middle, tree.right),
908
+ size: tree.size + 1,
867
909
  };
868
- return result;
869
910
  }
870
911
  else {
871
- let result = {
912
+ let newRight = assocNew(tree.right, key, item, thisHash);
913
+ return {
872
914
  kind: TernaryTreeKind.ternaryTreeBranch,
873
915
  maxHash: tree.maxHash,
874
916
  minHash: tree.minHash,
875
917
  left: tree.left,
876
918
  middle: tree.middle,
877
- right: assocNew(tree.right, key, item, thisHash),
878
- depth: 0, // TODO
919
+ right: newRight,
920
+ depth: decideMapBranchDepth(tree.left, tree.middle, newRight),
921
+ size: tree.size + 1,
879
922
  };
880
- return result;
881
923
  }
882
924
  }
883
925
  }
@@ -938,7 +980,8 @@ function dissocExisted(tree, key) {
938
980
  left: tree.middle,
939
981
  middle: tree.right,
940
982
  right: emptyBranch,
941
- depth: 0, // TODO
983
+ depth: decideMapBranchDepth(tree.middle, tree.right, emptyBranch),
984
+ size: tree.size - 1,
942
985
  };
943
986
  return result;
944
987
  }
@@ -950,7 +993,8 @@ function dissocExisted(tree, key) {
950
993
  left: changedBranch,
951
994
  middle: tree.middle,
952
995
  right: tree.right,
953
- depth: 0, // TODO
996
+ depth: decideMapBranchDepth(changedBranch, tree.middle, tree.right),
997
+ size: tree.size - 1,
954
998
  };
955
999
  return result;
956
1000
  }
@@ -968,7 +1012,8 @@ function dissocExisted(tree, key) {
968
1012
  left: tree.left,
969
1013
  middle: tree.right,
970
1014
  right: emptyBranch,
971
- depth: 0, // TODO
1015
+ depth: decideMapBranchDepth(tree.left, tree.right, emptyBranch),
1016
+ size: tree.size - 1,
972
1017
  };
973
1018
  return result;
974
1019
  }
@@ -980,7 +1025,8 @@ function dissocExisted(tree, key) {
980
1025
  left: tree.left,
981
1026
  middle: changedBranch,
982
1027
  right: tree.right,
983
- depth: 0, // TODO
1028
+ depth: decideMapBranchDepth(tree.left, changedBranch, tree.right),
1029
+ size: tree.size - 1,
984
1030
  };
985
1031
  return result;
986
1032
  }
@@ -995,7 +1041,8 @@ function dissocExisted(tree, key) {
995
1041
  left: tree.left,
996
1042
  middle: tree.middle,
997
1043
  right: emptyBranch,
998
- depth: 0, // TODO
1044
+ depth: decideMapBranchDepth(tree.left, tree.middle, emptyBranch),
1045
+ size: tree.size - 1,
999
1046
  };
1000
1047
  return result;
1001
1048
  }
@@ -1007,7 +1054,8 @@ function dissocExisted(tree, key) {
1007
1054
  left: tree.left,
1008
1055
  middle: tree.middle,
1009
1056
  right: changedBranch,
1010
- depth: 0, // TODO
1057
+ depth: decideMapBranchDepth(tree.left, tree.middle, changedBranch),
1058
+ size: tree.size - 1,
1011
1059
  };
1012
1060
  return result;
1013
1061
  }
@@ -1025,28 +1073,38 @@ export function dissocMap(tree, key) {
1025
1073
  function collectToPairsArray(acc, tree) {
1026
1074
  if (tree != null) {
1027
1075
  if (tree.kind === TernaryTreeKind.ternaryTreeLeaf) {
1028
- for (let i = 0; i < tree.elements.length; i++) {
1029
- let pair = tree.elements[i];
1030
- acc.push(pair);
1076
+ // Cache elements array and use batch push for better performance
1077
+ const elements = tree.elements;
1078
+ const length = elements.length;
1079
+ for (let i = 0; i < length; i++) {
1080
+ acc.push(elements[i]);
1031
1081
  }
1032
1082
  }
1033
1083
  else {
1034
- if (tree.left != null) {
1035
- collectToPairsArray(acc, tree.left);
1084
+ // Cache children to avoid repeated property access
1085
+ const left = tree.left;
1086
+ const middle = tree.middle;
1087
+ const right = tree.right;
1088
+ if (left != null) {
1089
+ collectToPairsArray(acc, left);
1036
1090
  }
1037
- if (tree.middle != null) {
1038
- collectToPairsArray(acc, tree.middle);
1091
+ if (middle != null) {
1092
+ collectToPairsArray(acc, middle);
1039
1093
  }
1040
- if (tree.right != null) {
1041
- collectToPairsArray(acc, tree.right);
1094
+ if (right != null) {
1095
+ collectToPairsArray(acc, right);
1042
1096
  }
1043
1097
  }
1044
1098
  }
1045
1099
  }
1046
1100
  /** similar to `toPairs`, but using Array.push directly */
1047
1101
  export function toPairsArray(tree) {
1048
- let result = [];
1049
- collectToPairsArray(result, tree);
1102
+ // Pre-allocate array with known size for better performance
1103
+ const totalSize = mapLen(tree);
1104
+ let result = new Array(totalSize);
1105
+ let idx = { value: 0 };
1106
+ // Use the more efficient collectHashSortedArray instead
1107
+ collectHashSortedArray(tree, result, idx);
1050
1108
  return result;
1051
1109
  }
1052
1110
  export function* toPairs(tree) {
@@ -1254,10 +1312,13 @@ export function mapMapValues(tree, f) {
1254
1312
  }
1255
1313
  switch (tree.kind) {
1256
1314
  case TernaryTreeKind.ternaryTreeLeaf: {
1257
- let newElements = new Array(tree.elements.length);
1258
- let size = tree.elements.length;
1315
+ // Cache elements array and pre-allocate result
1316
+ const elements = tree.elements;
1317
+ const size = elements.length;
1318
+ let newElements = new Array(size);
1259
1319
  for (let idx = 0; idx < size; idx++) {
1260
- newElements[idx] = [tree.elements[idx][0], f(tree.elements[idx][1])];
1320
+ const element = elements[idx];
1321
+ newElements[idx] = [element[0], f(element[1])];
1261
1322
  }
1262
1323
  let result = {
1263
1324
  kind: TernaryTreeKind.ternaryTreeLeaf,
@@ -1275,6 +1336,7 @@ export function mapMapValues(tree, f) {
1275
1336
  left: mapMapValues(tree.left, f),
1276
1337
  middle: mapMapValues(tree.middle, f),
1277
1338
  right: mapMapValues(tree.right, f),
1339
+ size: tree.size,
1278
1340
  };
1279
1341
  return result;
1280
1342
  }