@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/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +6 -0
- package/README.md +24 -4
- package/TESTING.md +155 -0
- package/lib/bench.d.mts +11 -0
- package/lib/bench.mjs +99 -0
- package/lib/benchmark.d.mts +1 -0
- package/lib/benchmark.mjs +67 -0
- package/lib/list.d.mts +1 -0
- package/lib/list.mjs +265 -188
- package/lib/map.mjs +223 -161
- 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/lib/types.d.mts +1 -0
- package/package.json +14 -5
- /package/lib/{main.d.mts → test.d.mts} +0 -0
package/lib/map.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TernaryTreeKind, hashGenerator, } from "./types.mjs";
|
|
2
|
-
import {
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
105
|
-
let
|
|
106
|
-
let
|
|
107
|
-
let
|
|
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:
|
|
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
|
-
|
|
179
|
+
// Use Map instead of Record for better performance with numeric keys
|
|
180
|
+
let groupBuffers = new Map();
|
|
163
181
|
let xs = [];
|
|
164
|
-
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
|
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
|
|
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
|
|
284
|
+
return false;
|
|
271
285
|
}
|
|
272
286
|
switch (tree.kind) {
|
|
273
287
|
case TernaryTreeKind.ternaryTreeLeaf:
|
|
274
|
-
return
|
|
288
|
+
return tree.elements.length === 1;
|
|
275
289
|
case TernaryTreeKind.ternaryTreeBranch:
|
|
276
|
-
return tree
|
|
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
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
|
|
321
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
365
|
-
|
|
384
|
+
// Optimize branch navigation with early exits
|
|
385
|
+
const left = tree.left;
|
|
386
|
+
if (left == null) {
|
|
366
387
|
return false;
|
|
367
388
|
}
|
|
368
|
-
if (
|
|
369
|
-
if (hx <
|
|
389
|
+
if (left.kind === TernaryTreeKind.ternaryTreeLeaf) {
|
|
390
|
+
if (hx < left.hash) {
|
|
370
391
|
return false;
|
|
371
392
|
}
|
|
372
|
-
if (
|
|
373
|
-
tree =
|
|
374
|
-
continue whileLoop;
|
|
393
|
+
if (left.hash === hx) {
|
|
394
|
+
tree = left;
|
|
395
|
+
continue whileLoop;
|
|
375
396
|
}
|
|
376
397
|
}
|
|
377
398
|
else {
|
|
378
|
-
if (hx <
|
|
399
|
+
if (hx < left.minHash) {
|
|
379
400
|
return false;
|
|
380
401
|
}
|
|
381
|
-
if (hx <=
|
|
382
|
-
tree =
|
|
383
|
-
continue whileLoop;
|
|
402
|
+
if (hx <= left.maxHash) {
|
|
403
|
+
tree = left;
|
|
404
|
+
continue whileLoop;
|
|
384
405
|
}
|
|
385
406
|
}
|
|
386
|
-
|
|
407
|
+
const middle = tree.middle;
|
|
408
|
+
if (middle == null) {
|
|
387
409
|
return false;
|
|
388
410
|
}
|
|
389
|
-
if (
|
|
390
|
-
if (hx <
|
|
411
|
+
if (middle.kind === TernaryTreeKind.ternaryTreeLeaf) {
|
|
412
|
+
if (hx < middle.hash) {
|
|
391
413
|
return false;
|
|
392
414
|
}
|
|
393
|
-
if (
|
|
394
|
-
tree =
|
|
395
|
-
continue whileLoop;
|
|
415
|
+
if (middle.hash === hx) {
|
|
416
|
+
tree = middle;
|
|
417
|
+
continue whileLoop;
|
|
396
418
|
}
|
|
397
419
|
}
|
|
398
420
|
else {
|
|
399
|
-
if (hx <
|
|
421
|
+
if (hx < middle.minHash) {
|
|
400
422
|
return false;
|
|
401
423
|
}
|
|
402
|
-
if (hx <=
|
|
403
|
-
tree =
|
|
404
|
-
continue whileLoop;
|
|
424
|
+
if (hx <= middle.maxHash) {
|
|
425
|
+
tree = middle;
|
|
426
|
+
continue whileLoop;
|
|
405
427
|
}
|
|
406
428
|
}
|
|
407
|
-
|
|
429
|
+
const right = tree.right;
|
|
430
|
+
if (right == null) {
|
|
408
431
|
return false;
|
|
409
432
|
}
|
|
410
|
-
if (
|
|
411
|
-
if (hx <
|
|
433
|
+
if (right.kind === TernaryTreeKind.ternaryTreeLeaf) {
|
|
434
|
+
if (hx < right.hash) {
|
|
412
435
|
return false;
|
|
413
436
|
}
|
|
414
|
-
if (
|
|
415
|
-
tree =
|
|
416
|
-
continue whileLoop;
|
|
437
|
+
if (right.hash === hx) {
|
|
438
|
+
tree = right;
|
|
439
|
+
continue whileLoop;
|
|
417
440
|
}
|
|
418
441
|
}
|
|
419
442
|
else {
|
|
420
|
-
if (hx <
|
|
443
|
+
if (hx < right.minHash) {
|
|
421
444
|
return false;
|
|
422
445
|
}
|
|
423
|
-
if (hx <=
|
|
424
|
-
tree =
|
|
425
|
-
continue whileLoop;
|
|
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
|
-
|
|
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
|
-
|
|
440
|
-
|
|
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
|
-
//
|
|
447
|
-
|
|
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 (
|
|
451
|
-
if (hx <
|
|
475
|
+
if (left.kind == TernaryTreeKind.ternaryTreeLeaf) {
|
|
476
|
+
if (hx < left.hash) {
|
|
452
477
|
return v0;
|
|
453
478
|
}
|
|
454
|
-
if (
|
|
455
|
-
tree =
|
|
456
|
-
continue whileLoop;
|
|
479
|
+
if (left.hash === hx) {
|
|
480
|
+
tree = left;
|
|
481
|
+
continue whileLoop;
|
|
457
482
|
}
|
|
458
483
|
}
|
|
459
484
|
else {
|
|
460
|
-
if (hx <
|
|
485
|
+
if (hx < left.minHash) {
|
|
461
486
|
return v0;
|
|
462
487
|
}
|
|
463
|
-
if (hx <=
|
|
464
|
-
tree =
|
|
465
|
-
continue whileLoop;
|
|
488
|
+
if (hx <= left.maxHash) {
|
|
489
|
+
tree = left;
|
|
490
|
+
continue whileLoop;
|
|
466
491
|
}
|
|
467
492
|
}
|
|
468
|
-
|
|
493
|
+
const middle = tree.middle;
|
|
494
|
+
if (middle == null) {
|
|
469
495
|
return v0;
|
|
470
496
|
}
|
|
471
|
-
if (
|
|
472
|
-
if (hx <
|
|
497
|
+
if (middle.kind == TernaryTreeKind.ternaryTreeLeaf) {
|
|
498
|
+
if (hx < middle.hash) {
|
|
473
499
|
return v0;
|
|
474
500
|
}
|
|
475
|
-
if (
|
|
476
|
-
tree =
|
|
477
|
-
continue whileLoop;
|
|
501
|
+
if (middle.hash === hx) {
|
|
502
|
+
tree = middle;
|
|
503
|
+
continue whileLoop;
|
|
478
504
|
}
|
|
479
505
|
}
|
|
480
506
|
else {
|
|
481
|
-
if (hx <
|
|
507
|
+
if (hx < middle.minHash) {
|
|
482
508
|
return v0;
|
|
483
509
|
}
|
|
484
|
-
if (hx <=
|
|
485
|
-
tree =
|
|
486
|
-
continue whileLoop;
|
|
510
|
+
if (hx <= middle.maxHash) {
|
|
511
|
+
tree = middle;
|
|
512
|
+
continue whileLoop;
|
|
487
513
|
}
|
|
488
514
|
}
|
|
489
|
-
|
|
515
|
+
const right = tree.right;
|
|
516
|
+
if (right == null) {
|
|
490
517
|
return v0;
|
|
491
518
|
}
|
|
492
|
-
if (
|
|
493
|
-
if (hx <
|
|
519
|
+
if (right.kind == TernaryTreeKind.ternaryTreeLeaf) {
|
|
520
|
+
if (hx < right.hash) {
|
|
494
521
|
return v0;
|
|
495
522
|
}
|
|
496
|
-
if (
|
|
497
|
-
tree =
|
|
498
|
-
continue whileLoop;
|
|
523
|
+
if (right.hash === hx) {
|
|
524
|
+
tree = right;
|
|
525
|
+
continue whileLoop;
|
|
499
526
|
}
|
|
500
527
|
}
|
|
501
528
|
else {
|
|
502
|
-
if (hx <
|
|
529
|
+
if (hx < right.minHash) {
|
|
503
530
|
return v0;
|
|
504
531
|
}
|
|
505
|
-
if (hx <=
|
|
506
|
-
tree =
|
|
507
|
-
continue whileLoop;
|
|
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)
|
|
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
|
|
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:
|
|
654
|
+
left: newLeft,
|
|
627
655
|
middle: tree.middle,
|
|
628
656
|
right: tree.right,
|
|
629
|
-
depth:
|
|
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
|
|
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:
|
|
671
|
+
middle: newMiddle,
|
|
643
672
|
right: tree.right,
|
|
644
|
-
depth:
|
|
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
|
|
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:
|
|
659
|
-
depth:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
862
|
+
left: newLeft,
|
|
825
863
|
middle: tree.middle,
|
|
826
864
|
right: tree.right,
|
|
827
|
-
depth:
|
|
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
|
|
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:
|
|
876
|
+
middle: newMiddle,
|
|
838
877
|
right: tree.right,
|
|
839
|
-
depth:
|
|
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
|
|
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:
|
|
851
|
-
depth:
|
|
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
|
|
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:
|
|
904
|
+
left: newLeft,
|
|
864
905
|
middle: tree.middle,
|
|
865
906
|
right: tree.right,
|
|
866
|
-
depth:
|
|
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
|
|
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:
|
|
878
|
-
depth:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
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
|
-
|
|
1035
|
-
|
|
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 (
|
|
1038
|
-
collectToPairsArray(acc,
|
|
1091
|
+
if (middle != null) {
|
|
1092
|
+
collectToPairsArray(acc, middle);
|
|
1039
1093
|
}
|
|
1040
|
-
if (
|
|
1041
|
-
collectToPairsArray(acc,
|
|
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
|
-
|
|
1049
|
-
|
|
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
|
-
|
|
1258
|
-
|
|
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
|
-
|
|
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
|
}
|