@calcit/ternary-tree 0.0.24 → 0.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -4
- package/TESTING.md +155 -0
- package/lib/benchmark.d.mts +1 -0
- package/lib/benchmark.mjs +67 -0
- package/lib/list.mjs +170 -124
- package/lib/map.mjs +124 -101
- package/lib/test-list-detailed-perf.d.mts +1 -0
- package/lib/test-list-detailed-perf.mjs +165 -0
- package/lib/test-list-perf.d.mts +1 -0
- package/lib/test-list-perf.mjs +153 -0
- package/lib/test-list.mjs +202 -203
- package/lib/test-map-perf.d.mts +1 -0
- package/lib/test-map-perf.mjs +70 -0
- package/lib/test-map.mjs +201 -208
- package/lib/test-utils.d.mts +9 -5
- package/lib/test-utils.mjs +131 -18
- package/lib/{main.mjs → test.mjs} +3 -0
- package/package.json +10 -2
- /package/lib/{main.d.mts → test.d.mts} +0 -0
package/lib/list.mjs
CHANGED
@@ -41,7 +41,7 @@ export function makeTernaryTreeList(size, offset, xs) {
|
|
41
41
|
let middle = xs[offset + 1];
|
42
42
|
let result = {
|
43
43
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
44
|
-
size:
|
44
|
+
size: left.size + middle.size,
|
45
45
|
left: left,
|
46
46
|
middle: middle,
|
47
47
|
right: emptyBranch,
|
@@ -56,7 +56,7 @@ export function makeTernaryTreeList(size, offset, xs) {
|
|
56
56
|
let right = xs[offset + 2];
|
57
57
|
let result = {
|
58
58
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
59
|
-
size:
|
59
|
+
size: left.size + middle.size + right.size,
|
60
60
|
left: left,
|
61
61
|
middle: middle,
|
62
62
|
right: right,
|
@@ -72,7 +72,7 @@ export function makeTernaryTreeList(size, offset, xs) {
|
|
72
72
|
let right = makeTernaryTreeList(divided.right, offset + divided.left + divided.middle, xs);
|
73
73
|
let result = {
|
74
74
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
75
|
-
size:
|
75
|
+
size: left.size + middle.size + right.size,
|
76
76
|
depth: decideParentDepth(left, middle, right),
|
77
77
|
left: left,
|
78
78
|
middle: middle,
|
@@ -84,22 +84,22 @@ export function makeTernaryTreeList(size, offset, xs) {
|
|
84
84
|
}
|
85
85
|
}
|
86
86
|
export function initTernaryTreeList(xs) {
|
87
|
-
|
88
|
-
let
|
87
|
+
const size = xs.length;
|
88
|
+
let ys = new Array(size);
|
89
|
+
// Use cached size instead of accessing xs.length repeatedly
|
89
90
|
for (let idx = 0; idx < size; idx++) {
|
90
|
-
|
91
|
-
ys[idx] = { kind: TernaryTreeKind.ternaryTreeLeaf, size: 1, value: x };
|
91
|
+
ys[idx] = { kind: TernaryTreeKind.ternaryTreeLeaf, size: 1, value: xs[idx] };
|
92
92
|
}
|
93
|
-
return makeTernaryTreeList(
|
93
|
+
return makeTernaryTreeList(size, 0, ys);
|
94
94
|
}
|
95
95
|
// from a slice of an existed array
|
96
96
|
export function initTernaryTreeListFromRange(xs, from, to) {
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
ys[idx
|
97
|
+
const length = to - from;
|
98
|
+
let ys = new Array(length);
|
99
|
+
for (let idx = 0; idx < length; idx++) {
|
100
|
+
ys[idx] = { kind: TernaryTreeKind.ternaryTreeLeaf, size: 1, value: xs[idx + from] };
|
101
101
|
}
|
102
|
-
return makeTernaryTreeList(
|
102
|
+
return makeTernaryTreeList(length, 0, ys);
|
103
103
|
}
|
104
104
|
export function initEmptyTernaryTreeList() {
|
105
105
|
return { kind: TernaryTreeKind.ternaryTreeBranch, size: 0, depth: 1, middle: emptyBranch, left: emptyBranch, right: emptyBranch };
|
@@ -141,18 +141,22 @@ export function* listToItems(tree) {
|
|
141
141
|
break;
|
142
142
|
}
|
143
143
|
case TernaryTreeKind.ternaryTreeBranch: {
|
144
|
-
|
145
|
-
|
144
|
+
// Cache children to avoid repeated property access
|
145
|
+
const left = tree.left;
|
146
|
+
const middle = tree.middle;
|
147
|
+
const right = tree.right;
|
148
|
+
if (left != null) {
|
149
|
+
for (let x of listToItems(left)) {
|
146
150
|
yield x;
|
147
151
|
}
|
148
152
|
}
|
149
|
-
if (
|
150
|
-
for (let x of listToItems(
|
153
|
+
if (middle != null) {
|
154
|
+
for (let x of listToItems(middle)) {
|
151
155
|
yield x;
|
152
156
|
}
|
153
157
|
}
|
154
|
-
if (
|
155
|
-
for (let x of listToItems(
|
158
|
+
if (right != null) {
|
159
|
+
for (let x of listToItems(right)) {
|
156
160
|
yield x;
|
157
161
|
}
|
158
162
|
}
|
@@ -176,17 +180,21 @@ export function findIndex(tree, f) {
|
|
176
180
|
}
|
177
181
|
}
|
178
182
|
case TernaryTreeKind.ternaryTreeBranch: {
|
179
|
-
|
183
|
+
// Cache children to avoid repeated property access
|
184
|
+
const left = tree.left;
|
185
|
+
const middle = tree.middle;
|
186
|
+
const right = tree.right;
|
187
|
+
let tryLeft = findIndex(left, f);
|
180
188
|
if (tryLeft >= 0) {
|
181
189
|
return tryLeft;
|
182
190
|
}
|
183
|
-
let tryMiddle = findIndex(
|
191
|
+
let tryMiddle = findIndex(middle, f);
|
184
192
|
if (tryMiddle >= 0) {
|
185
|
-
return tryMiddle +
|
193
|
+
return tryMiddle + (left == null ? 0 : left.size);
|
186
194
|
}
|
187
|
-
let tryRight = findIndex(
|
195
|
+
let tryRight = findIndex(right, f);
|
188
196
|
if (tryRight >= 0) {
|
189
|
-
return tryRight +
|
197
|
+
return tryRight + (left == null ? 0 : left.size) + (middle == null ? 0 : middle.size);
|
190
198
|
}
|
191
199
|
return -1;
|
192
200
|
}
|
@@ -205,17 +213,21 @@ export function indexOf(tree, item) {
|
|
205
213
|
default:
|
206
214
|
return -1;
|
207
215
|
case TernaryTreeKind.ternaryTreeBranch:
|
208
|
-
|
216
|
+
// Cache children to avoid repeated property access
|
217
|
+
const left = tree.left;
|
218
|
+
const middle = tree.middle;
|
219
|
+
const right = tree.right;
|
220
|
+
let tryLeft = indexOf(left, item);
|
209
221
|
if (tryLeft >= 0) {
|
210
222
|
return tryLeft;
|
211
223
|
}
|
212
|
-
let tryMiddle = indexOf(
|
224
|
+
let tryMiddle = indexOf(middle, item);
|
213
225
|
if (tryMiddle >= 0) {
|
214
|
-
return tryMiddle +
|
226
|
+
return tryMiddle + (left == null ? 0 : left.size);
|
215
227
|
}
|
216
|
-
let tryRight = indexOf(
|
228
|
+
let tryRight = indexOf(right, item);
|
217
229
|
if (tryRight >= 0) {
|
218
|
-
return tryRight +
|
230
|
+
return tryRight + (left == null ? 0 : left.size) + (middle == null ? 0 : middle.size);
|
219
231
|
}
|
220
232
|
return -1;
|
221
233
|
}
|
@@ -227,25 +239,28 @@ function writeLeavesArray(tree, acc, idx) {
|
|
227
239
|
else {
|
228
240
|
switch (tree.kind) {
|
229
241
|
case TernaryTreeKind.ternaryTreeLeaf: {
|
230
|
-
|
231
|
-
|
242
|
+
// Cache current index to reduce property access
|
243
|
+
const currentIdx = idx.value;
|
244
|
+
acc[currentIdx] = tree;
|
245
|
+
idx.value = currentIdx + 1;
|
232
246
|
break;
|
233
247
|
}
|
234
248
|
case TernaryTreeKind.ternaryTreeBranch: {
|
235
|
-
|
236
|
-
|
249
|
+
// Cache children to avoid repeated property access
|
250
|
+
const left = tree.left;
|
251
|
+
const middle = tree.middle;
|
252
|
+
const right = tree.right;
|
253
|
+
if (left != null) {
|
254
|
+
writeLeavesArray(left, acc, idx);
|
237
255
|
}
|
238
|
-
if (
|
239
|
-
writeLeavesArray(
|
256
|
+
if (middle != null) {
|
257
|
+
writeLeavesArray(middle, acc, idx);
|
240
258
|
}
|
241
|
-
if (
|
242
|
-
writeLeavesArray(
|
259
|
+
if (right != null) {
|
260
|
+
writeLeavesArray(right, acc, idx);
|
243
261
|
}
|
244
262
|
break;
|
245
263
|
}
|
246
|
-
default: {
|
247
|
-
throw new Error("Unknown");
|
248
|
-
}
|
249
264
|
}
|
250
265
|
}
|
251
266
|
}
|
@@ -285,17 +300,21 @@ export function listGet(originalTree, originalIdx) {
|
|
285
300
|
if (idx > tree.size - 1) {
|
286
301
|
throw new Error("Index too large");
|
287
302
|
}
|
288
|
-
|
289
|
-
|
290
|
-
|
303
|
+
// Cache child sizes to avoid repeated property access
|
304
|
+
const left = tree.left;
|
305
|
+
const middle = tree.middle;
|
306
|
+
const right = tree.right;
|
307
|
+
const leftSize = left == null ? 0 : left.size;
|
308
|
+
const middleSize = middle == null ? 0 : middle.size;
|
309
|
+
const rightSize = right == null ? 0 : right.size;
|
291
310
|
if (leftSize + middleSize + rightSize !== tree.size) {
|
292
311
|
throw new Error("tree.size does not match sum case branch sizes");
|
293
312
|
}
|
294
313
|
if (idx <= leftSize - 1) {
|
295
|
-
tree =
|
314
|
+
tree = left;
|
296
315
|
}
|
297
316
|
else if (idx <= leftSize + middleSize - 1) {
|
298
|
-
tree =
|
317
|
+
tree = middle;
|
299
318
|
idx = idx - leftSize;
|
300
319
|
}
|
301
320
|
else {
|
@@ -336,45 +355,49 @@ export function assocList(tree, idx, item) {
|
|
336
355
|
throw new Error(`Cannot get from leaf with index ${idx}`);
|
337
356
|
}
|
338
357
|
}
|
339
|
-
|
340
|
-
|
341
|
-
|
358
|
+
// Cache children and their sizes to avoid repeated property access
|
359
|
+
const left = tree.left;
|
360
|
+
const middle = tree.middle;
|
361
|
+
const right = tree.right;
|
362
|
+
const leftSize = left == null ? 0 : left.size;
|
363
|
+
const middleSize = middle == null ? 0 : middle.size;
|
364
|
+
const rightSize = right == null ? 0 : right.size;
|
342
365
|
if (leftSize + middleSize + rightSize !== tree.size)
|
343
366
|
throw new Error("tree.size does not match sum case branch sizes");
|
344
367
|
if (idx <= leftSize - 1) {
|
345
|
-
let changedBranch = assocList(
|
368
|
+
let changedBranch = assocList(left, idx, item);
|
346
369
|
let result = {
|
347
370
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
348
371
|
size: tree.size,
|
349
|
-
depth: decideParentDepth(changedBranch,
|
372
|
+
depth: decideParentDepth(changedBranch, middle, right),
|
350
373
|
left: changedBranch,
|
351
|
-
middle:
|
352
|
-
right:
|
374
|
+
middle: middle,
|
375
|
+
right: right,
|
353
376
|
};
|
354
377
|
checkListStructure(result);
|
355
378
|
return result;
|
356
379
|
}
|
357
380
|
else if (idx <= leftSize + middleSize - 1) {
|
358
|
-
let changedBranch = assocList(
|
381
|
+
let changedBranch = assocList(middle, idx - leftSize, item);
|
359
382
|
let result = {
|
360
383
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
361
384
|
size: tree.size,
|
362
|
-
depth: decideParentDepth(
|
363
|
-
left:
|
385
|
+
depth: decideParentDepth(left, changedBranch, right),
|
386
|
+
left: left,
|
364
387
|
middle: changedBranch,
|
365
|
-
right:
|
388
|
+
right: right,
|
366
389
|
};
|
367
390
|
checkListStructure(result);
|
368
391
|
return result;
|
369
392
|
}
|
370
393
|
else {
|
371
|
-
let changedBranch = assocList(
|
394
|
+
let changedBranch = assocList(right, idx - leftSize - middleSize, item);
|
372
395
|
let result = {
|
373
396
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
374
397
|
size: tree.size,
|
375
|
-
depth: decideParentDepth(
|
376
|
-
left:
|
377
|
-
middle:
|
398
|
+
depth: decideParentDepth(left, middle, changedBranch),
|
399
|
+
left: left,
|
400
|
+
middle: middle,
|
378
401
|
right: changedBranch,
|
379
402
|
};
|
380
403
|
checkListStructure(result);
|
@@ -400,22 +423,26 @@ export function dissocList(tree, idx) {
|
|
400
423
|
if (tree.kind === TernaryTreeKind.ternaryTreeLeaf) {
|
401
424
|
throw new Error("dissoc should be handled at branches");
|
402
425
|
}
|
403
|
-
|
404
|
-
|
405
|
-
|
426
|
+
// Cache children and their sizes to avoid repeated property access
|
427
|
+
const left = tree.left;
|
428
|
+
const middle = tree.middle;
|
429
|
+
const right = tree.right;
|
430
|
+
const leftSize = left == null ? 0 : left.size;
|
431
|
+
const middleSize = middle == null ? 0 : middle.size;
|
432
|
+
const rightSize = right == null ? 0 : right.size;
|
406
433
|
if (leftSize + middleSize + rightSize !== tree.size) {
|
407
434
|
throw new Error("tree.size does not match sum from branch sizes");
|
408
435
|
}
|
409
436
|
let result = emptyBranch;
|
410
437
|
if (idx <= leftSize - 1) {
|
411
|
-
let changedBranch = dissocList(
|
438
|
+
let changedBranch = dissocList(left, idx);
|
412
439
|
if (changedBranch == null || changedBranch.size === 0) {
|
413
440
|
result = {
|
414
441
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
415
442
|
size: tree.size - 1,
|
416
|
-
depth: decideParentDepth(
|
417
|
-
left:
|
418
|
-
middle:
|
443
|
+
depth: decideParentDepth(middle, right),
|
444
|
+
left: middle,
|
445
|
+
middle: right,
|
419
446
|
right: emptyBranch,
|
420
447
|
};
|
421
448
|
}
|
@@ -423,22 +450,22 @@ export function dissocList(tree, idx) {
|
|
423
450
|
result = {
|
424
451
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
425
452
|
size: tree.size - 1,
|
426
|
-
depth: decideParentDepth(changedBranch,
|
453
|
+
depth: decideParentDepth(changedBranch, middle, right),
|
427
454
|
left: changedBranch,
|
428
|
-
middle:
|
429
|
-
right:
|
455
|
+
middle: middle,
|
456
|
+
right: right,
|
430
457
|
};
|
431
458
|
}
|
432
459
|
}
|
433
460
|
else if (idx <= leftSize + middleSize - 1) {
|
434
|
-
let changedBranch = dissocList(
|
461
|
+
let changedBranch = dissocList(middle, idx - leftSize);
|
435
462
|
if (changedBranch == null || changedBranch.size === 0) {
|
436
463
|
result = {
|
437
464
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
438
465
|
size: tree.size - 1,
|
439
|
-
depth: decideParentDepth(
|
440
|
-
left:
|
441
|
-
middle:
|
466
|
+
depth: decideParentDepth(left, changedBranch, right),
|
467
|
+
left: left,
|
468
|
+
middle: right,
|
442
469
|
right: emptyBranch,
|
443
470
|
};
|
444
471
|
}
|
@@ -446,24 +473,24 @@ export function dissocList(tree, idx) {
|
|
446
473
|
result = {
|
447
474
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
448
475
|
size: tree.size - 1,
|
449
|
-
depth: decideParentDepth(
|
450
|
-
left:
|
476
|
+
depth: decideParentDepth(left, changedBranch, right),
|
477
|
+
left: left,
|
451
478
|
middle: changedBranch,
|
452
|
-
right:
|
479
|
+
right: right,
|
453
480
|
};
|
454
481
|
}
|
455
482
|
}
|
456
483
|
else {
|
457
|
-
let changedBranch = dissocList(
|
484
|
+
let changedBranch = dissocList(right, idx - leftSize - middleSize);
|
458
485
|
if (changedBranch == null || changedBranch.size === 0) {
|
459
486
|
changedBranch = emptyBranch;
|
460
487
|
}
|
461
488
|
result = {
|
462
489
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
463
490
|
size: tree.size - 1,
|
464
|
-
depth: decideParentDepth(
|
465
|
-
left:
|
466
|
-
middle:
|
491
|
+
depth: decideParentDepth(left, middle, changedBranch),
|
492
|
+
left: left,
|
493
|
+
middle: middle,
|
467
494
|
right: changedBranch,
|
468
495
|
};
|
469
496
|
}
|
@@ -612,15 +639,19 @@ export function insert(tree, idx, item, after = false) {
|
|
612
639
|
}
|
613
640
|
}
|
614
641
|
}
|
615
|
-
|
616
|
-
|
617
|
-
|
642
|
+
// Cache children and their sizes to avoid repeated property access
|
643
|
+
const left = tree.left;
|
644
|
+
const middle = tree.middle;
|
645
|
+
const right = tree.right;
|
646
|
+
const leftSize = left == null ? 0 : left.size;
|
647
|
+
const middleSize = middle == null ? 0 : middle.size;
|
648
|
+
const rightSize = right == null ? 0 : right.size;
|
618
649
|
if (leftSize + middleSize + rightSize !== tree.size) {
|
619
650
|
throw new Error("tree.size does not match sum case branch sizes");
|
620
651
|
}
|
621
652
|
// echo "picking: ", idx, " ", leftSize, " ", middleSize, " ", rightSize
|
622
653
|
if (idx === 0 && !after) {
|
623
|
-
if (
|
654
|
+
if (leftSize >= middleSize && leftSize >= rightSize) {
|
624
655
|
let result = {
|
625
656
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
626
657
|
size: tree.size + 1,
|
@@ -634,7 +665,7 @@ export function insert(tree, idx, item, after = false) {
|
|
634
665
|
}
|
635
666
|
}
|
636
667
|
if (idx === listLen(tree) - 1 && after) {
|
637
|
-
if (
|
668
|
+
if (rightSize >= middleSize && rightSize >= leftSize) {
|
638
669
|
let result = {
|
639
670
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
640
671
|
size: tree.size + 1,
|
@@ -665,46 +696,46 @@ export function insert(tree, idx, item, after = false) {
|
|
665
696
|
size: tree.size + 1,
|
666
697
|
depth: tree.depth,
|
667
698
|
left: { kind: TernaryTreeKind.ternaryTreeLeaf, size: 1, value: item },
|
668
|
-
middle:
|
669
|
-
right:
|
699
|
+
middle: left,
|
700
|
+
right: middle,
|
670
701
|
};
|
671
702
|
checkListStructure(result);
|
672
703
|
return result;
|
673
704
|
}
|
674
705
|
if (idx <= leftSize - 1) {
|
675
|
-
let changedBranch = insert(
|
706
|
+
let changedBranch = insert(left, idx, item, after);
|
676
707
|
let result = {
|
677
708
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
678
709
|
size: tree.size + 1,
|
679
|
-
depth: decideParentDepth(changedBranch,
|
710
|
+
depth: decideParentDepth(changedBranch, middle, right),
|
680
711
|
left: changedBranch,
|
681
|
-
middle:
|
682
|
-
right:
|
712
|
+
middle: middle,
|
713
|
+
right: right,
|
683
714
|
};
|
684
715
|
checkListStructure(result);
|
685
716
|
return result;
|
686
717
|
}
|
687
718
|
else if (idx <= leftSize + middleSize - 1) {
|
688
|
-
let changedBranch = insert(
|
719
|
+
let changedBranch = insert(middle, idx - leftSize, item, after);
|
689
720
|
let result = {
|
690
721
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
691
722
|
size: tree.size + 1,
|
692
|
-
depth: decideParentDepth(
|
693
|
-
left:
|
723
|
+
depth: decideParentDepth(left, changedBranch, right),
|
724
|
+
left: left,
|
694
725
|
middle: changedBranch,
|
695
|
-
right:
|
726
|
+
right: right,
|
696
727
|
};
|
697
728
|
checkListStructure(result);
|
698
729
|
return result;
|
699
730
|
}
|
700
731
|
else {
|
701
|
-
let changedBranch = insert(
|
732
|
+
let changedBranch = insert(right, idx - leftSize - middleSize, item, after);
|
702
733
|
let result = {
|
703
734
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
704
735
|
size: tree.size + 1,
|
705
|
-
depth: decideParentDepth(
|
706
|
-
left:
|
707
|
-
middle:
|
736
|
+
depth: decideParentDepth(left, middle, changedBranch),
|
737
|
+
left: left,
|
738
|
+
middle: middle,
|
708
739
|
right: changedBranch,
|
709
740
|
};
|
710
741
|
checkListStructure(result);
|
@@ -902,22 +933,29 @@ export function checkListStructure(tree) {
|
|
902
933
|
if (tree.size >= 6 && tree.depth >= tree.size) {
|
903
934
|
throw new Error(`Bad depth at branch ${formatListInline(tree)}`);
|
904
935
|
}
|
905
|
-
|
936
|
+
// Cache children and their sizes to avoid repeated property access
|
937
|
+
const left = tree.left;
|
938
|
+
const middle = tree.middle;
|
939
|
+
const right = tree.right;
|
940
|
+
const leftSize = left == null ? 0 : left.size;
|
941
|
+
const middleSize = middle == null ? 0 : middle.size;
|
942
|
+
const rightSize = right == null ? 0 : right.size;
|
943
|
+
if (tree.size !== leftSize + middleSize + rightSize) {
|
906
944
|
throw new Error(`Bad size at branch ${formatListInline(tree)}`);
|
907
945
|
}
|
908
|
-
if (
|
946
|
+
if (left == null && middle != null) {
|
909
947
|
throw new Error("morformed tree");
|
910
948
|
}
|
911
|
-
if (
|
949
|
+
if (middle == null && right != null) {
|
912
950
|
throw new Error("morformed tree");
|
913
951
|
}
|
914
|
-
if (tree.depth !== decideParentDepth(
|
915
|
-
let x = decideParentDepth(
|
952
|
+
if (tree.depth !== decideParentDepth(left, middle, right)) {
|
953
|
+
let x = decideParentDepth(left, middle, right);
|
916
954
|
throw new Error(`Bad depth at branch ${formatListInline(tree)}`);
|
917
955
|
}
|
918
|
-
checkListStructure(
|
919
|
-
checkListStructure(
|
920
|
-
checkListStructure(
|
956
|
+
checkListStructure(left);
|
957
|
+
checkListStructure(middle);
|
958
|
+
checkListStructure(right);
|
921
959
|
break;
|
922
960
|
}
|
923
961
|
}
|
@@ -949,34 +987,38 @@ export function slice(tree, startIdx, endIdx) {
|
|
949
987
|
if (startIdx === 0 && endIdx === listLen(tree)) {
|
950
988
|
return tree;
|
951
989
|
}
|
952
|
-
|
953
|
-
|
954
|
-
|
990
|
+
// Cache children and their sizes to avoid repeated property access
|
991
|
+
const left = tree.left;
|
992
|
+
const middle = tree.middle;
|
993
|
+
const right = tree.right;
|
994
|
+
const leftSize = left == null ? 0 : left.size;
|
995
|
+
const middleSize = middle == null ? 0 : middle.size;
|
996
|
+
const rightSize = right == null ? 0 : right.size;
|
955
997
|
// echo "sizes: {leftSize} {middleSize} {rightSize}"
|
956
998
|
if (startIdx >= leftSize + middleSize) {
|
957
|
-
return slice(
|
999
|
+
return slice(right, startIdx - leftSize - middleSize, endIdx - leftSize - middleSize);
|
958
1000
|
}
|
959
1001
|
if (startIdx >= leftSize)
|
960
1002
|
if (endIdx <= leftSize + middleSize) {
|
961
|
-
return slice(
|
1003
|
+
return slice(middle, startIdx - leftSize, endIdx - leftSize);
|
962
1004
|
}
|
963
1005
|
else {
|
964
|
-
let middleCut = slice(
|
965
|
-
let rightCut = slice(
|
1006
|
+
let middleCut = slice(middle, startIdx - leftSize, middleSize);
|
1007
|
+
let rightCut = slice(right, 0, endIdx - leftSize - middleSize);
|
966
1008
|
return concat(middleCut, rightCut);
|
967
1009
|
}
|
968
1010
|
if (endIdx <= leftSize) {
|
969
|
-
return slice(
|
1011
|
+
return slice(left, startIdx, endIdx);
|
970
1012
|
}
|
971
1013
|
if (endIdx <= leftSize + middleSize) {
|
972
|
-
let leftCut = slice(
|
973
|
-
let middleCut = slice(
|
1014
|
+
let leftCut = slice(left, startIdx, leftSize);
|
1015
|
+
let middleCut = slice(middle, 0, endIdx - leftSize);
|
974
1016
|
return concat(leftCut, middleCut);
|
975
1017
|
}
|
976
1018
|
if (endIdx <= leftSize + middleSize + rightSize) {
|
977
|
-
let leftCut = slice(
|
978
|
-
let rightCut = slice(
|
979
|
-
return concat(concat(leftCut,
|
1019
|
+
let leftCut = slice(left, startIdx, leftSize);
|
1020
|
+
let rightCut = slice(right, 0, endIdx - leftSize - middleSize);
|
1021
|
+
return concat(concat(leftCut, middle), rightCut);
|
980
1022
|
}
|
981
1023
|
throw new Error("Unknown");
|
982
1024
|
}
|
@@ -1019,13 +1061,17 @@ export function listMapValues(tree, f) {
|
|
1019
1061
|
return result;
|
1020
1062
|
}
|
1021
1063
|
case TernaryTreeKind.ternaryTreeBranch: {
|
1064
|
+
// Cache children to avoid repeated property access
|
1065
|
+
const left = tree.left;
|
1066
|
+
const middle = tree.middle;
|
1067
|
+
const right = tree.right;
|
1022
1068
|
let result = {
|
1023
1069
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
1024
1070
|
size: tree.size,
|
1025
1071
|
depth: tree.depth,
|
1026
|
-
left:
|
1027
|
-
middle:
|
1028
|
-
right:
|
1072
|
+
left: left == null ? emptyBranch : listMapValues(left, f),
|
1073
|
+
middle: middle == null ? emptyBranch : listMapValues(middle, f),
|
1074
|
+
right: right == null ? emptyBranch : listMapValues(right, f),
|
1029
1075
|
};
|
1030
1076
|
return result;
|
1031
1077
|
}
|