@calcit/ternary-tree 0.0.23 → 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.d.mts +2 -0
- package/lib/list.mjs +178 -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} +5 -0
- package/package.json +13 -5
- /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);
|
@@ -879,7 +910,15 @@ export function listEqual(xs, ys) {
|
|
879
910
|
}
|
880
911
|
return true;
|
881
912
|
}
|
913
|
+
var skipListStructureCheck = false;
|
914
|
+
/** in some cases we disable for performance */
|
915
|
+
export let disableListStructureCheck = () => {
|
916
|
+
skipListStructureCheck = true;
|
917
|
+
};
|
882
918
|
export function checkListStructure(tree) {
|
919
|
+
if (skipListStructureCheck) {
|
920
|
+
return true;
|
921
|
+
}
|
883
922
|
if (tree == null || listLen(tree) === 0) {
|
884
923
|
return true;
|
885
924
|
}
|
@@ -894,22 +933,29 @@ export function checkListStructure(tree) {
|
|
894
933
|
if (tree.size >= 6 && tree.depth >= tree.size) {
|
895
934
|
throw new Error(`Bad depth at branch ${formatListInline(tree)}`);
|
896
935
|
}
|
897
|
-
|
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) {
|
898
944
|
throw new Error(`Bad size at branch ${formatListInline(tree)}`);
|
899
945
|
}
|
900
|
-
if (
|
946
|
+
if (left == null && middle != null) {
|
901
947
|
throw new Error("morformed tree");
|
902
948
|
}
|
903
|
-
if (
|
949
|
+
if (middle == null && right != null) {
|
904
950
|
throw new Error("morformed tree");
|
905
951
|
}
|
906
|
-
if (tree.depth !== decideParentDepth(
|
907
|
-
let x = decideParentDepth(
|
952
|
+
if (tree.depth !== decideParentDepth(left, middle, right)) {
|
953
|
+
let x = decideParentDepth(left, middle, right);
|
908
954
|
throw new Error(`Bad depth at branch ${formatListInline(tree)}`);
|
909
955
|
}
|
910
|
-
checkListStructure(
|
911
|
-
checkListStructure(
|
912
|
-
checkListStructure(
|
956
|
+
checkListStructure(left);
|
957
|
+
checkListStructure(middle);
|
958
|
+
checkListStructure(right);
|
913
959
|
break;
|
914
960
|
}
|
915
961
|
}
|
@@ -941,34 +987,38 @@ export function slice(tree, startIdx, endIdx) {
|
|
941
987
|
if (startIdx === 0 && endIdx === listLen(tree)) {
|
942
988
|
return tree;
|
943
989
|
}
|
944
|
-
|
945
|
-
|
946
|
-
|
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;
|
947
997
|
// echo "sizes: {leftSize} {middleSize} {rightSize}"
|
948
998
|
if (startIdx >= leftSize + middleSize) {
|
949
|
-
return slice(
|
999
|
+
return slice(right, startIdx - leftSize - middleSize, endIdx - leftSize - middleSize);
|
950
1000
|
}
|
951
1001
|
if (startIdx >= leftSize)
|
952
1002
|
if (endIdx <= leftSize + middleSize) {
|
953
|
-
return slice(
|
1003
|
+
return slice(middle, startIdx - leftSize, endIdx - leftSize);
|
954
1004
|
}
|
955
1005
|
else {
|
956
|
-
let middleCut = slice(
|
957
|
-
let rightCut = slice(
|
1006
|
+
let middleCut = slice(middle, startIdx - leftSize, middleSize);
|
1007
|
+
let rightCut = slice(right, 0, endIdx - leftSize - middleSize);
|
958
1008
|
return concat(middleCut, rightCut);
|
959
1009
|
}
|
960
1010
|
if (endIdx <= leftSize) {
|
961
|
-
return slice(
|
1011
|
+
return slice(left, startIdx, endIdx);
|
962
1012
|
}
|
963
1013
|
if (endIdx <= leftSize + middleSize) {
|
964
|
-
let leftCut = slice(
|
965
|
-
let middleCut = slice(
|
1014
|
+
let leftCut = slice(left, startIdx, leftSize);
|
1015
|
+
let middleCut = slice(middle, 0, endIdx - leftSize);
|
966
1016
|
return concat(leftCut, middleCut);
|
967
1017
|
}
|
968
1018
|
if (endIdx <= leftSize + middleSize + rightSize) {
|
969
|
-
let leftCut = slice(
|
970
|
-
let rightCut = slice(
|
971
|
-
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);
|
972
1022
|
}
|
973
1023
|
throw new Error("Unknown");
|
974
1024
|
}
|
@@ -1011,13 +1061,17 @@ export function listMapValues(tree, f) {
|
|
1011
1061
|
return result;
|
1012
1062
|
}
|
1013
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;
|
1014
1068
|
let result = {
|
1015
1069
|
kind: TernaryTreeKind.ternaryTreeBranch,
|
1016
1070
|
size: tree.size,
|
1017
1071
|
depth: tree.depth,
|
1018
|
-
left:
|
1019
|
-
middle:
|
1020
|
-
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),
|
1021
1075
|
};
|
1022
1076
|
return result;
|
1023
1077
|
}
|