@frostpillar/frostpillar-btree 0.2.6 → 0.2.7

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/dist/core.cjs CHANGED
@@ -68,11 +68,12 @@ var createBranchNode = (children, parent) => {
68
68
  const child = children[i];
69
69
  child.parent = branch;
70
70
  child.indexInParent = i;
71
- const target = { key: void 0, sequence: 0 };
71
+ const target = {
72
+ key: void 0,
73
+ sequence: 0
74
+ };
72
75
  if (!writeMinKeyTo(child, target)) {
73
- throw new BTreeInvariantError(
74
- "branch child has no min key"
75
- );
76
+ throw new BTreeInvariantError("branch child has no min key");
76
77
  }
77
78
  keys.push(target);
78
79
  }
@@ -126,7 +127,14 @@ var leafInsertAt = (leaf, logicalIndex, entry) => {
126
127
  leaf.entryOffset -= 1;
127
128
  leaf.entries[phys - 1] = entry;
128
129
  } else {
129
- leaf.entries.splice(phys, 0, entry);
130
+ const len = leaf.entries.length;
131
+ if (phys >= len) {
132
+ leaf.entries.push(entry);
133
+ } else {
134
+ leaf.entries.push(leaf.entries[len - 1]);
135
+ leaf.entries.copyWithin(phys + 1, phys, len);
136
+ leaf.entries[phys] = entry;
137
+ }
130
138
  }
131
139
  };
132
140
  var leafCompact = (leaf) => {
@@ -155,7 +163,11 @@ var branchInsertAt = (branch, logicalIndex, child, key) => {
155
163
  const phys = branch.childOffset + logicalIndex;
156
164
  const count = branch.children.length - branch.childOffset;
157
165
  if (branch.childOffset > 0 && logicalIndex < count >>> 1) {
158
- branch.children.copyWithin(branch.childOffset - 1, branch.childOffset, phys);
166
+ branch.children.copyWithin(
167
+ branch.childOffset - 1,
168
+ branch.childOffset,
169
+ phys
170
+ );
159
171
  branch.keys.copyWithin(branch.childOffset - 1, branch.childOffset, phys);
160
172
  branch.childOffset -= 1;
161
173
  branch.children[phys - 1] = child;
@@ -176,8 +188,16 @@ var branchRemoveAt = (branch, physIndex) => {
176
188
  const logicalIndex = physIndex - branch.childOffset;
177
189
  const count = branch.children.length - branch.childOffset;
178
190
  if (logicalIndex < count - 1 - logicalIndex) {
179
- branch.children.copyWithin(branch.childOffset + 1, branch.childOffset, physIndex);
180
- branch.keys.copyWithin(branch.childOffset + 1, branch.childOffset, physIndex);
191
+ branch.children.copyWithin(
192
+ branch.childOffset + 1,
193
+ branch.childOffset,
194
+ physIndex
195
+ );
196
+ branch.keys.copyWithin(
197
+ branch.childOffset + 1,
198
+ branch.childOffset,
199
+ physIndex
200
+ );
181
201
  branch.childOffset += 1;
182
202
  for (let i = branch.childOffset; i <= physIndex; i += 1) {
183
203
  branch.children[i].indexInParent = i;
@@ -207,17 +227,21 @@ var normalizeDuplicateKeyPolicy = (value) => {
207
227
  return "replace";
208
228
  }
209
229
  if (value !== "allow" && value !== "reject" && value !== "replace") {
210
- throw new BTreeValidationError(
211
- `Invalid duplicateKeys option.`
212
- );
230
+ throw new BTreeValidationError(`Invalid duplicateKeys option.`);
213
231
  }
214
232
  return value;
215
233
  };
216
- var toPublicEntry = (entry) => ({
217
- entryId: entry.entryId,
218
- key: entry.key,
219
- value: entry.value
220
- });
234
+ var normalizeDeleteRebalancePolicy = (value) => {
235
+ if (value === void 0) {
236
+ return "standard";
237
+ }
238
+ if (value !== "standard" && value !== "lazy") {
239
+ throw new BTreeValidationError(`Invalid deleteRebalancePolicy option.`);
240
+ }
241
+ return value;
242
+ };
243
+ var freezeEntry = (entry) => Object.freeze(entry);
244
+ var createEntry = (key, entryId, value) => Object.freeze({ key, entryId, value });
221
245
  var isLeafNode = (node) => {
222
246
  return node.kind === NODE_LEAF;
223
247
  };
@@ -367,7 +391,11 @@ var hasKeyEntry = (state, key) => {
367
391
  var findNextHigherKey = (state, key) => {
368
392
  if (state.entryCount === 0) return null;
369
393
  const compare = state.compareKeys;
370
- let leaf = findLeafForKey(state, key, Number.MAX_SAFE_INTEGER);
394
+ let leaf = findLeafForKey(
395
+ state,
396
+ key,
397
+ Number.MAX_SAFE_INTEGER
398
+ );
371
399
  let idx = upperBoundInLeaf(state, leaf, key, Number.MAX_SAFE_INTEGER);
372
400
  while (leaf !== null) {
373
401
  if (idx < leafEntryCount(leaf)) {
@@ -470,55 +498,57 @@ var countRangeEntries = (state, startKey, endKey, options) => {
470
498
  cursorIndex = 0;
471
499
  continue;
472
500
  }
473
- const lastEntry = leafEntryAt(cursorLeaf, leafCount - 1);
474
- const cmpLast = compare(lastEntry.key, endKey);
475
- if (upperExclusive ? cmpLast < 0 : cmpLast <= 0) {
501
+ const lastKey = leafEntryAt(cursorLeaf, leafCount - 1).key;
502
+ if (isLastEntryInRange(lastKey, endKey, compare, upperExclusive)) {
476
503
  count += leafCount - cursorIndex;
477
504
  cursorLeaf = cursorLeaf.next;
478
505
  cursorIndex = 0;
479
506
  continue;
480
507
  }
481
- const endSeq = upperExclusive ? 0 : Number.MAX_SAFE_INTEGER;
482
- const endBound = upperExclusive ? lowerBoundInLeaf(state, cursorLeaf, endKey, endSeq) : upperBoundInLeaf(state, cursorLeaf, endKey, endSeq);
483
- const limit = endBound < leafCount ? endBound : leafCount;
484
- count += limit - cursorIndex;
508
+ count += findBoundaryEnd(state, cursorLeaf, endKey, upperExclusive, leafCount) - cursorIndex;
485
509
  return count;
486
510
  }
487
511
  return count;
488
512
  };
513
+ var isLastEntryInRange = (lastKey, endKey, compare, upperExclusive) => {
514
+ const cmp = compare(lastKey, endKey);
515
+ return upperExclusive ? cmp < 0 : cmp <= 0;
516
+ };
517
+ var findBoundaryEnd = (state, leaf, endKey, upperExclusive, leafCount) => {
518
+ const endSeq = upperExclusive ? 0 : Number.MAX_SAFE_INTEGER;
519
+ const endBound = upperExclusive ? lowerBoundInLeaf(state, leaf, endKey, endSeq) : upperBoundInLeaf(state, leaf, endKey, endSeq);
520
+ return endBound < leafCount ? endBound : leafCount;
521
+ };
489
522
  var RANGE_PREALLOC_THRESHOLD = 200;
490
- var allocateRangeOutput = (state, cursorLeaf, cursorIndex, compare, upperExclusive, startKey, endKey, options) => {
491
- const firstLeafCount = leafEntryCount(cursorLeaf);
492
- const firstLeafRemainder = firstLeafCount - cursorIndex;
493
- if (firstLeafRemainder >= RANGE_PREALLOC_THRESHOLD && cursorLeaf.next !== null) {
494
- const lastEntry = leafEntryAt(cursorLeaf, firstLeafCount - 1);
495
- const cmpLast = compare(lastEntry.key, endKey);
496
- if (upperExclusive ? cmpLast < 0 : cmpLast <= 0) {
497
- const total = countRangeEntries(state, startKey, endKey, options);
498
- return new Array(total);
523
+ var allocateRangeOutput = (state, cursor, startKey, endKey, options) => {
524
+ const firstLeafCount = leafEntryCount(cursor.leaf);
525
+ const firstLeafRemainder = firstLeafCount - cursor.index;
526
+ if (firstLeafRemainder >= RANGE_PREALLOC_THRESHOLD && cursor.leaf.next !== null) {
527
+ const lastKey = leafEntryAt(cursor.leaf, firstLeafCount - 1).key;
528
+ if (isLastEntryInRange(lastKey, endKey, cursor.compare, cursor.upperExclusive)) {
529
+ return new Array(
530
+ countRangeEntries(state, startKey, endKey, options)
531
+ );
499
532
  }
500
533
  }
501
534
  return [];
502
535
  };
503
- var appendLeafSlice = (leaf, from, to, output, useIndexed, writeIdx) => {
536
+ var appendLeafSlicePublic = (leaf, from, to, output, useIndexed, writeIdx) => {
504
537
  if (useIndexed) {
505
538
  for (let i = from; i < to; i += 1) {
506
- output[writeIdx++] = leafEntryAt(leaf, i);
539
+ output[writeIdx++] = freezeEntry(leafEntryAt(leaf, i));
507
540
  }
508
541
  } else {
509
542
  for (let i = from; i < to; i += 1) {
510
- output.push(leafEntryAt(leaf, i));
543
+ output.push(freezeEntry(leafEntryAt(leaf, i)));
511
544
  }
512
545
  }
513
546
  return writeIdx;
514
547
  };
515
- var rangeQueryEntries = (state, startKey, endKey, options) => {
516
- const cursor = initRangeCursor(state, startKey, endKey, options);
517
- if (cursor === null) return [];
548
+ var collectPublicEntries = (state, cursor, endKey, output) => {
549
+ const { compare, upperExclusive } = cursor;
518
550
  let cursorLeaf = cursor.leaf;
519
551
  let cursorIndex = cursor.index;
520
- const { compare, upperExclusive } = cursor;
521
- const output = allocateRangeOutput(state, cursorLeaf, cursorIndex, compare, upperExclusive, startKey, endKey, options);
522
552
  let writeIdx = 0;
523
553
  const useIndexed = output.length > 0;
524
554
  while (cursorLeaf !== null) {
@@ -528,24 +558,82 @@ var rangeQueryEntries = (state, startKey, endKey, options) => {
528
558
  cursorIndex = 0;
529
559
  continue;
530
560
  }
531
- const lastEntry = leafEntryAt(cursorLeaf, leafCount - 1);
532
- const cmpLast = compare(lastEntry.key, endKey);
533
- if (upperExclusive ? cmpLast < 0 : cmpLast <= 0) {
534
- writeIdx = appendLeafSlice(cursorLeaf, cursorIndex, leafCount, output, useIndexed, writeIdx);
561
+ const lastKey = leafEntryAt(cursorLeaf, leafCount - 1).key;
562
+ if (isLastEntryInRange(lastKey, endKey, compare, upperExclusive)) {
563
+ writeIdx = appendLeafSlicePublic(
564
+ cursorLeaf,
565
+ cursorIndex,
566
+ leafCount,
567
+ output,
568
+ useIndexed,
569
+ writeIdx
570
+ );
535
571
  cursorLeaf = cursorLeaf.next;
536
572
  cursorIndex = 0;
537
573
  continue;
538
574
  }
539
- const endSeq = upperExclusive ? 0 : Number.MAX_SAFE_INTEGER;
540
- const endBound = upperExclusive ? lowerBoundInLeaf(state, cursorLeaf, endKey, endSeq) : upperBoundInLeaf(state, cursorLeaf, endKey, endSeq);
541
- const limit = endBound < leafCount ? endBound : leafCount;
542
- appendLeafSlice(cursorLeaf, cursorIndex, limit, output, useIndexed, writeIdx);
543
- return output;
575
+ const limit = findBoundaryEnd(
576
+ state,
577
+ cursorLeaf,
578
+ endKey,
579
+ upperExclusive,
580
+ leafCount
581
+ );
582
+ appendLeafSlicePublic(
583
+ cursorLeaf,
584
+ cursorIndex,
585
+ limit,
586
+ output,
587
+ useIndexed,
588
+ writeIdx
589
+ );
590
+ return;
544
591
  }
592
+ };
593
+ var rangeQueryPublicEntries = (state, startKey, endKey, options) => {
594
+ const cursor = initRangeCursor(state, startKey, endKey, options);
595
+ if (cursor === null) return [];
596
+ const output = allocateRangeOutput(state, cursor, startKey, endKey, options);
597
+ collectPublicEntries(state, cursor, endKey, output);
545
598
  return output;
546
599
  };
600
+ var forEachRangeEntries = (state, startKey, endKey, callback, options) => {
601
+ const cursor = initRangeCursor(state, startKey, endKey, options);
602
+ if (cursor === null) return;
603
+ let cursorLeaf = cursor.leaf;
604
+ let cursorIndex = cursor.index;
605
+ const { compare, upperExclusive } = cursor;
606
+ while (cursorLeaf !== null) {
607
+ const leafCount = leafEntryCount(cursorLeaf);
608
+ if (cursorIndex >= leafCount) {
609
+ cursorLeaf = cursorLeaf.next;
610
+ cursorIndex = 0;
611
+ continue;
612
+ }
613
+ const lastKey = leafEntryAt(cursorLeaf, leafCount - 1).key;
614
+ if (isLastEntryInRange(lastKey, endKey, compare, upperExclusive)) {
615
+ for (let i = cursorIndex; i < leafCount; i += 1) {
616
+ callback(freezeEntry(leafEntryAt(cursorLeaf, i)));
617
+ }
618
+ cursorLeaf = cursorLeaf.next;
619
+ cursorIndex = 0;
620
+ continue;
621
+ }
622
+ const limit = findBoundaryEnd(
623
+ state,
624
+ cursorLeaf,
625
+ endKey,
626
+ upperExclusive,
627
+ leafCount
628
+ );
629
+ for (let i = cursorIndex; i < limit; i += 1) {
630
+ callback(freezeEntry(leafEntryAt(cursorLeaf, i)));
631
+ }
632
+ return;
633
+ }
634
+ };
547
635
 
548
- // src/btree/rebalance.ts
636
+ // src/btree/rebalance-branch.ts
549
637
  var updateMinKeyInAncestors = (node) => {
550
638
  let current = node;
551
639
  while (current.parent !== null) {
@@ -561,12 +649,9 @@ var requireParent = (node) => {
561
649
  }
562
650
  return node.parent;
563
651
  };
564
- var requireLeafNode = (node) => {
565
- if (!isLeafNode(node)) throw new BTreeInvariantError("expected leaf, got branch");
566
- return node;
567
- };
568
652
  var requireBranchNode = (node) => {
569
- if (isLeafNode(node)) throw new BTreeInvariantError("expected branch, got leaf");
653
+ if (isLeafNode(node))
654
+ throw new BTreeInvariantError("expected branch, got leaf");
570
655
  return node;
571
656
  };
572
657
  var removeChildFromBranch = (branch, childIndex) => {
@@ -575,27 +660,18 @@ var removeChildFromBranch = (branch, childIndex) => {
575
660
  }
576
661
  branchRemoveAt(branch, childIndex);
577
662
  };
578
- var detachLeafFromChain = (state, leaf) => {
579
- if (leaf.prev !== null) {
580
- leaf.prev.next = leaf.next;
581
- } else if (leaf.next !== null) {
582
- state.leftmostLeaf = leaf.next;
583
- }
584
- if (leaf.next !== null) {
585
- leaf.next.prev = leaf.prev;
586
- } else if (leaf.prev !== null) {
587
- state.rightmostLeaf = leaf.prev;
588
- }
589
- leaf.prev = null;
590
- leaf.next = null;
591
- };
592
663
  var borrowFromLeftBranch = (branch, leftSibling, branchIndex) => {
593
664
  const borrowedChild = leftSibling.children.pop();
594
- if (borrowedChild === void 0) throw new BTreeInvariantError("left branch borrow failed");
665
+ if (borrowedChild === void 0)
666
+ throw new BTreeInvariantError("left branch borrow failed");
595
667
  leftSibling.keys.pop();
596
668
  borrowedChild.parent = branch;
597
- const borrowedMinKey = { key: void 0, sequence: 0 };
598
- if (!writeMinKeyTo(borrowedChild, borrowedMinKey)) throw new BTreeInvariantError("borrowed child has no min key");
669
+ const borrowedMinKey = {
670
+ key: void 0,
671
+ sequence: 0
672
+ };
673
+ if (!writeMinKeyTo(borrowedChild, borrowedMinKey))
674
+ throw new BTreeInvariantError("borrowed child has no min key");
599
675
  if (branch.childOffset > 0) {
600
676
  branch.childOffset -= 1;
601
677
  branch.children[branch.childOffset] = borrowedChild;
@@ -604,15 +680,20 @@ var borrowFromLeftBranch = (branch, leftSibling, branchIndex) => {
604
680
  } else {
605
681
  branch.children.unshift(borrowedChild);
606
682
  branch.keys.unshift(borrowedMinKey);
607
- for (let i = 0; i < branch.children.length; i += 1) branch.children[i].indexInParent = i;
683
+ for (let i = 0; i < branch.children.length; i += 1)
684
+ branch.children[i].indexInParent = i;
608
685
  }
609
686
  const parent = requireParent(branch);
610
- parent.keys[branchIndex] = { key: borrowedMinKey.key, sequence: borrowedMinKey.sequence };
687
+ parent.keys[branchIndex] = {
688
+ key: borrowedMinKey.key,
689
+ sequence: borrowedMinKey.sequence
690
+ };
611
691
  updateMinKeyInAncestors(branch);
612
692
  };
613
693
  var borrowFromRightBranch = (branch, rightSibling, branchIndex) => {
614
694
  const shiftIdx = rightSibling.childOffset;
615
- if (shiftIdx >= rightSibling.children.length) throw new BTreeInvariantError("right branch borrow failed");
695
+ if (shiftIdx >= rightSibling.children.length)
696
+ throw new BTreeInvariantError("right branch borrow failed");
616
697
  const borrowedChild = rightSibling.children[shiftIdx];
617
698
  rightSibling.childOffset += 1;
618
699
  if (rightSibling.childOffset >= rightSibling.children.length >>> 1) {
@@ -620,8 +701,12 @@ var borrowFromRightBranch = (branch, rightSibling, branchIndex) => {
620
701
  }
621
702
  branch.children.push(borrowedChild);
622
703
  borrowedChild.parent = branch;
623
- const borrowedMinKey = { key: void 0, sequence: 0 };
624
- if (!writeMinKeyTo(borrowedChild, borrowedMinKey)) throw new BTreeInvariantError("borrowed child has no min key");
704
+ const borrowedMinKey = {
705
+ key: void 0,
706
+ sequence: 0
707
+ };
708
+ if (!writeMinKeyTo(borrowedChild, borrowedMinKey))
709
+ throw new BTreeInvariantError("borrowed child has no min key");
625
710
  branch.keys.push(borrowedMinKey);
626
711
  borrowedChild.indexInParent = branch.children.length - 1;
627
712
  const parent = requireParent(branch);
@@ -674,7 +759,10 @@ var rebalanceAfterBranchRemoval = (state, branch) => {
674
759
  const parent = branch.parent;
675
760
  if (parent === null) throw new BTreeInvariantError("branch has no parent");
676
761
  const branchIndex = branch.indexInParent;
677
- const { left: leftSibling, right: rightSibling } = findBranchSiblings(parent, branchIndex);
762
+ const { left: leftSibling, right: rightSibling } = findBranchSiblings(
763
+ parent,
764
+ branchIndex
765
+ );
678
766
  if (rightSibling !== null && branchChildCount(rightSibling) > state.minBranchChildren) {
679
767
  borrowFromRightBranch(branch, rightSibling, branchIndex);
680
768
  return;
@@ -693,44 +781,68 @@ var rebalanceAfterBranchRemoval = (state, branch) => {
693
781
  }
694
782
  throw new BTreeInvariantError("no branch siblings to rebalance");
695
783
  };
784
+
785
+ // src/btree/rebalance.ts
786
+ var requireLeafNode = (node) => {
787
+ if (!isLeafNode(node))
788
+ throw new BTreeInvariantError("expected leaf, got branch");
789
+ return node;
790
+ };
791
+ var detachLeafFromChain = (state, leaf) => {
792
+ if (leaf.prev !== null) {
793
+ leaf.prev.next = leaf.next;
794
+ } else if (leaf.next !== null) {
795
+ state.leftmostLeaf = leaf.next;
796
+ }
797
+ if (leaf.next !== null) {
798
+ leaf.next.prev = leaf.prev;
799
+ } else if (leaf.prev !== null) {
800
+ state.rightmostLeaf = leaf.prev;
801
+ }
802
+ leaf.prev = null;
803
+ leaf.next = null;
804
+ };
696
805
  var mergeLeafEntries = (target, source) => {
697
806
  if (target.entryOffset > 0) {
698
807
  target.entries.copyWithin(0, target.entryOffset);
699
808
  target.entries.length = target.entries.length - target.entryOffset;
700
809
  target.entryOffset = 0;
701
810
  }
702
- const src = source.entries;
703
- for (let i = source.entryOffset; i < src.length; i += 1) target.entries.push(src[i]);
811
+ target.entries.push(...source.entries.slice(source.entryOffset));
704
812
  };
705
- var rebalanceAfterLeafRemoval = (state, leaf) => {
706
- if (leaf === state.root) {
707
- if (state.entryCount === 0) {
708
- state.leftmostLeaf = leaf;
709
- state.rightmostLeaf = leaf;
710
- }
711
- return;
813
+ var applyLazyThreshold = (min) => Math.max(1, Math.ceil(min / 4));
814
+ var leafRebalanceThreshold = (state) => {
815
+ if (state.deleteRebalancePolicy === "lazy") {
816
+ return applyLazyThreshold(state.minLeafEntries);
712
817
  }
713
- if (leafEntryCount(leaf) >= state.minLeafEntries) return;
714
- const parent = leaf.parent;
715
- if (parent === null) throw new BTreeInvariantError("Leaf node has no parent during rebalance.");
716
- const leafIndex = leaf.indexInParent;
717
- const leftSibling = leafIndex > parent.childOffset ? requireLeafNode(parent.children[leafIndex - 1]) : null;
718
- const rightSibling = leafIndex + 1 < parent.children.length ? requireLeafNode(parent.children[leafIndex + 1]) : null;
818
+ return state.minLeafEntries;
819
+ };
820
+ var findLeafSiblings = (parent, leafIndex) => {
821
+ const left = leafIndex > parent.childOffset ? requireLeafNode(parent.children[leafIndex - 1]) : null;
822
+ const right = leafIndex + 1 < parent.children.length ? requireLeafNode(parent.children[leafIndex + 1]) : null;
823
+ return { left, right };
824
+ };
825
+ var tryBorrowFromLeafSibling = (state, leaf, parent, leafIndex, leftSibling, rightSibling) => {
719
826
  if (rightSibling !== null && leafEntryCount(rightSibling) > state.minLeafEntries) {
720
827
  const borrowed = leafShiftEntry(rightSibling);
721
- if (borrowed === void 0) throw new BTreeInvariantError("right leaf borrow failed");
828
+ if (borrowed === void 0)
829
+ throw new BTreeInvariantError("right leaf borrow failed");
722
830
  leaf.entries.push(borrowed);
723
831
  writeMinKeyTo(rightSibling, parent.keys[leafIndex + 1]);
724
- return;
832
+ return true;
725
833
  }
726
834
  if (leftSibling !== null && leafEntryCount(leftSibling) > state.minLeafEntries) {
727
835
  const borrowed = leftSibling.entries.pop();
728
- if (borrowed === void 0) throw new BTreeInvariantError("left leaf borrow failed");
836
+ if (borrowed === void 0)
837
+ throw new BTreeInvariantError("left leaf borrow failed");
729
838
  leafUnshiftEntry(leaf, borrowed);
730
839
  parent.keys[leafIndex] = { key: borrowed.key, sequence: borrowed.entryId };
731
840
  updateMinKeyInAncestors(leaf);
732
- return;
841
+ return true;
733
842
  }
843
+ return false;
844
+ };
845
+ var mergeLeafWithSibling = (state, leaf, parent, leafIndex, leftSibling, rightSibling) => {
734
846
  if (leftSibling !== null) {
735
847
  mergeLeafEntries(leftSibling, leaf);
736
848
  detachLeafFromChain(state, leaf);
@@ -747,6 +859,24 @@ var rebalanceAfterLeafRemoval = (state, leaf) => {
747
859
  }
748
860
  throw new BTreeInvariantError("no leaf siblings to rebalance");
749
861
  };
862
+ var rebalanceAfterLeafRemoval = (state, leaf) => {
863
+ if (leaf === state.root) {
864
+ if (state.entryCount === 0) {
865
+ state.leftmostLeaf = leaf;
866
+ state.rightmostLeaf = leaf;
867
+ }
868
+ return;
869
+ }
870
+ if (leafEntryCount(leaf) >= leafRebalanceThreshold(state)) return;
871
+ const parent = leaf.parent;
872
+ if (parent === null)
873
+ throw new BTreeInvariantError("Leaf node has no parent during rebalance.");
874
+ const leafIndex = leaf.indexInParent;
875
+ const { left, right } = findLeafSiblings(parent, leafIndex);
876
+ if (tryBorrowFromLeafSibling(state, leaf, parent, leafIndex, left, right))
877
+ return;
878
+ mergeLeafWithSibling(state, leaf, parent, leafIndex, left, right);
879
+ };
750
880
 
751
881
  // src/btree/deleteRange.ts
752
882
  var navigateToStart = (state, startKey, lowerExclusive) => {
@@ -759,16 +889,16 @@ var navigateToStart = (state, startKey, lowerExclusive) => {
759
889
  }
760
890
  return { leaf, idx };
761
891
  };
762
- var findRemoveEnd = (state, leaf, idx, endKey, upperExclusive) => {
892
+ var findRemoveEnd = (state, leaf, endKey, upperExclusive) => {
763
893
  const count = leafEntryCount(leaf);
764
- let removeEnd = idx;
765
- while (removeEnd < count) {
766
- const e = leafEntryAt(leaf, removeEnd);
767
- const cmpEnd = state.compareKeys(e.key, endKey);
768
- if (upperExclusive ? cmpEnd >= 0 : cmpEnd > 0) break;
769
- removeEnd += 1;
894
+ const lastEntry = leafEntryAt(leaf, count - 1);
895
+ const cmpLast = state.compareKeys(lastEntry.key, endKey);
896
+ if (upperExclusive ? cmpLast < 0 : cmpLast <= 0) {
897
+ return count;
770
898
  }
771
- return removeEnd;
899
+ const endSeq = upperExclusive ? 0 : Number.MAX_SAFE_INTEGER;
900
+ const endBound = upperExclusive ? lowerBoundInLeaf(state, leaf, endKey, endSeq) : upperBoundInLeaf(state, leaf, endKey, endSeq);
901
+ return endBound < count ? endBound : count;
772
902
  };
773
903
  var spliceLeafAndRebalance = (state, leaf, idx, removeCount) => {
774
904
  if (state.entryKeys !== null) {
@@ -785,10 +915,12 @@ var spliceLeafAndRebalance = (state, leaf, idx, removeCount) => {
785
915
  updateMinKeyInAncestors(leaf);
786
916
  }
787
917
  const countAfterSplice = leafEntryCount(leaf);
918
+ const rebalThreshold = leafRebalanceThreshold(state);
788
919
  let safetyGuard = state.minLeafEntries + 4;
789
- while (safetyGuard > 0 && leaf !== state.root && leafEntryCount(leaf) < state.minLeafEntries) {
920
+ while (safetyGuard > 0 && leaf !== state.root && leafEntryCount(leaf) < rebalThreshold) {
790
921
  rebalanceAfterLeafRemoval(state, leaf);
791
- if (leaf.parent !== null && leaf.parent.children[leaf.indexInParent] !== leaf) break;
922
+ if (leaf.parent !== null && leaf.parent.children[leaf.indexInParent] !== leaf)
923
+ break;
792
924
  safetyGuard -= 1;
793
925
  }
794
926
  if (leafEmptied && leafEntryCount(leaf) > 0 && leaf.parent !== null && leaf.parent.children[leaf.indexInParent] === leaf) {
@@ -816,10 +948,15 @@ var deleteRangeEntries = (state, startKey, endKey, options) => {
816
948
  }
817
949
  if (idx >= leafEntryCount(leaf)) break;
818
950
  const count = leafEntryCount(leaf);
819
- const removeEnd = findRemoveEnd(state, leaf, idx, endKey, upperExclusive);
951
+ const removeEnd = findRemoveEnd(state, leaf, endKey, upperExclusive);
820
952
  const removeCount = removeEnd - idx;
821
953
  if (removeCount === 0) break;
822
- const countAfterSplice = spliceLeafAndRebalance(state, leaf, idx, removeCount);
954
+ const countAfterSplice = spliceLeafAndRebalance(
955
+ state,
956
+ leaf,
957
+ idx,
958
+ removeCount
959
+ );
823
960
  deleted += removeCount;
824
961
  if (removeEnd < count) break;
825
962
  if (!isLeafStillValid(state, leaf)) {
@@ -865,25 +1002,42 @@ var computeNextAutoScaleThreshold = (entryCount) => {
865
1002
  }
866
1003
  return Number.MAX_SAFE_INTEGER;
867
1004
  };
868
- var createInitialState = (config) => {
869
- if (typeof config.compareKeys !== "function") {
870
- throw new BTreeValidationError("compareKeys must be a function.");
871
- }
872
- const autoScale = config.autoScale === true;
1005
+ var resolveInitialCapacity = (config, autoScale) => {
873
1006
  if (autoScale && (config.maxLeafEntries !== void 0 || config.maxBranchChildren !== void 0)) {
874
- throw new BTreeValidationError("autoScale conflicts with explicit capacity.");
1007
+ throw new BTreeValidationError(
1008
+ "autoScale conflicts with explicit capacity."
1009
+ );
875
1010
  }
876
- let maxLeafEntries;
877
- let maxBranchChildren;
878
1011
  if (autoScale) {
879
1012
  const tier = computeAutoScaleTier(0);
880
- maxLeafEntries = tier.maxLeaf;
881
- maxBranchChildren = tier.maxBranch;
882
- } else {
883
- maxLeafEntries = normalizeNodeCapacity(config.maxLeafEntries, "maxLeafEntries", DEFAULT_MAX_LEAF_ENTRIES);
884
- maxBranchChildren = normalizeNodeCapacity(config.maxBranchChildren, "maxBranchChildren", DEFAULT_MAX_BRANCH_CHILDREN);
1013
+ return { maxLeafEntries: tier.maxLeaf, maxBranchChildren: tier.maxBranch };
885
1014
  }
1015
+ return {
1016
+ maxLeafEntries: normalizeNodeCapacity(
1017
+ config.maxLeafEntries,
1018
+ "maxLeafEntries",
1019
+ DEFAULT_MAX_LEAF_ENTRIES
1020
+ ),
1021
+ maxBranchChildren: normalizeNodeCapacity(
1022
+ config.maxBranchChildren,
1023
+ "maxBranchChildren",
1024
+ DEFAULT_MAX_BRANCH_CHILDREN
1025
+ )
1026
+ };
1027
+ };
1028
+ var createInitialState = (config) => {
1029
+ if (typeof config.compareKeys !== "function") {
1030
+ throw new BTreeValidationError("compareKeys must be a function.");
1031
+ }
1032
+ const autoScale = config.autoScale === true;
1033
+ const { maxLeafEntries, maxBranchChildren } = resolveInitialCapacity(
1034
+ config,
1035
+ autoScale
1036
+ );
886
1037
  const duplicateKeys = normalizeDuplicateKeyPolicy(config.duplicateKeys);
1038
+ const deleteRebalancePolicy = normalizeDeleteRebalancePolicy(
1039
+ config.deleteRebalancePolicy
1040
+ );
887
1041
  const emptyLeaf = createLeafNode([], null);
888
1042
  return {
889
1043
  compareKeys: config.compareKeys,
@@ -899,6 +1053,7 @@ var createInitialState = (config) => {
899
1053
  nextSequence: 0,
900
1054
  entryKeys: config.enableEntryIdLookup === true ? /* @__PURE__ */ new Map() : null,
901
1055
  autoScale,
1056
+ deleteRebalancePolicy,
902
1057
  _nextAutoScaleThreshold: autoScale ? computeNextAutoScaleThreshold(0) : Number.MAX_SAFE_INTEGER,
903
1058
  _cursor: { leaf: emptyLeaf, index: 0 }
904
1059
  };
@@ -914,7 +1069,9 @@ var maybeAutoScale = (state) => {
914
1069
  state.maxBranchChildren = maxBranch;
915
1070
  state.minBranchChildren = minOccupancy(maxBranch);
916
1071
  }
917
- state._nextAutoScaleThreshold = computeNextAutoScaleThreshold(state.entryCount);
1072
+ state._nextAutoScaleThreshold = computeNextAutoScaleThreshold(
1073
+ state.entryCount
1074
+ );
918
1075
  };
919
1076
  var applyAutoScaleCapacitySnapshot = (state, maxLeafEntries, maxBranchChildren) => {
920
1077
  if (!state.autoScale) {
@@ -941,6 +1098,14 @@ var applyAutoScaleCapacitySnapshot = (state, maxLeafEntries, maxBranchChildren)
941
1098
  state.minLeafEntries = minOccupancy(normalizedLeaf);
942
1099
  state.minBranchChildren = minOccupancy(normalizedBranch);
943
1100
  };
1101
+ var resetAutoScaleToTier0 = (state) => {
1102
+ const tier = computeAutoScaleTier(0);
1103
+ state.maxLeafEntries = tier.maxLeaf;
1104
+ state.maxBranchChildren = tier.maxBranch;
1105
+ state.minLeafEntries = minOccupancy(tier.maxLeaf);
1106
+ state.minBranchChildren = minOccupancy(tier.maxBranch);
1107
+ state._nextAutoScaleThreshold = computeNextAutoScaleThreshold(0);
1108
+ };
944
1109
 
945
1110
  // src/btree/bulkLoad.ts
946
1111
  var computeChunkBoundaries = (total, max, min) => {
@@ -961,7 +1126,11 @@ var computeChunkBoundaries = (total, max, min) => {
961
1126
  return boundaries;
962
1127
  };
963
1128
  var buildLeaves = (state, entries, ids, baseSequence) => {
964
- const boundaries = computeChunkBoundaries(entries.length, state.maxLeafEntries, state.minLeafEntries);
1129
+ const boundaries = computeChunkBoundaries(
1130
+ entries.length,
1131
+ state.maxLeafEntries,
1132
+ state.minLeafEntries
1133
+ );
965
1134
  const leaves = new Array(boundaries.length);
966
1135
  let chunkStart = 0;
967
1136
  for (let c = 0; c < boundaries.length; c += 1) {
@@ -969,7 +1138,11 @@ var buildLeaves = (state, entries, ids, baseSequence) => {
969
1138
  const chunk = new Array(chunkEnd - chunkStart);
970
1139
  for (let i = chunkStart; i < chunkEnd; i += 1) {
971
1140
  const seq = baseSequence + i;
972
- chunk[i - chunkStart] = { key: entries[i].key, entryId: seq, value: entries[i].value };
1141
+ chunk[i - chunkStart] = createEntry(
1142
+ entries[i].key,
1143
+ seq,
1144
+ entries[i].value
1145
+ );
973
1146
  ids[i] = seq;
974
1147
  if (state.entryKeys !== null) {
975
1148
  state.entryKeys.set(seq, entries[i].key);
@@ -1003,11 +1176,18 @@ var bulkLoadEntries = (state, entries) => {
1003
1176
  } else {
1004
1177
  let currentLevel = leaves;
1005
1178
  while (currentLevel.length > 1) {
1006
- const bounds = computeChunkBoundaries(currentLevel.length, state.maxBranchChildren, state.minBranchChildren);
1179
+ const bounds = computeChunkBoundaries(
1180
+ currentLevel.length,
1181
+ state.maxBranchChildren,
1182
+ state.minBranchChildren
1183
+ );
1007
1184
  const nextLevel = new Array(bounds.length);
1008
1185
  let start = 0;
1009
1186
  for (let b = 0; b < bounds.length; b += 1) {
1010
- nextLevel[b] = createBranchNode(currentLevel.slice(start, bounds[b]), null);
1187
+ nextLevel[b] = createBranchNode(
1188
+ currentLevel.slice(start, bounds[b]),
1189
+ null
1190
+ );
1011
1191
  start = bounds[b];
1012
1192
  }
1013
1193
  currentLevel = nextLevel;
@@ -1018,9 +1198,12 @@ var bulkLoadEntries = (state, entries) => {
1018
1198
  return ids;
1019
1199
  };
1020
1200
 
1021
- // src/btree/mutations.ts
1201
+ // src/btree/split.ts
1022
1202
  var insertChildAfter = (state, parent, existingChild, childToInsert) => {
1023
- const newChildMinKey = { key: void 0, sequence: 0 };
1203
+ const newChildMinKey = {
1204
+ key: void 0,
1205
+ sequence: 0
1206
+ };
1024
1207
  if (!writeMinKeyTo(childToInsert, newChildMinKey)) {
1025
1208
  throw new BTreeInvariantError("inserted child has no min key");
1026
1209
  }
@@ -1058,7 +1241,10 @@ var splitLeaf = (state, leaf) => {
1058
1241
  var splitBranch = (state, branch) => {
1059
1242
  branchCompact(branch);
1060
1243
  const splitAt = Math.ceil(branch.children.length / 2);
1061
- const sibling = createBranchNode(branch.children.splice(splitAt), branch.parent);
1244
+ const sibling = createBranchNode(
1245
+ branch.children.splice(splitAt),
1246
+ branch.parent
1247
+ );
1062
1248
  branch.keys.splice(splitAt);
1063
1249
  if (branch.parent === null) {
1064
1250
  state.root = createBranchNode([branch, sibling], null);
@@ -1066,42 +1252,125 @@ var splitBranch = (state, branch) => {
1066
1252
  }
1067
1253
  insertChildAfter(state, branch.parent, branch, sibling);
1068
1254
  };
1255
+
1256
+ // src/btree/entry-lookup.ts
1257
+ var findLeafEntryBySequence = (state, userKey, sequence) => {
1258
+ const targetLeaf = findLeafForKey(state, userKey, sequence);
1259
+ const index = lowerBoundInLeaf(state, targetLeaf, userKey, sequence);
1260
+ if (index >= leafEntryCount(targetLeaf)) return null;
1261
+ const entry = leafEntryAt(targetLeaf, index);
1262
+ if (entry.entryId !== sequence) return null;
1263
+ return { leaf: targetLeaf, index };
1264
+ };
1265
+ var peekEntryById = (state, entryId) => {
1266
+ if (state.entryKeys === null) {
1267
+ throw new BTreeInvariantError(
1268
+ "entryKeys lookup map is not enabled on this tree."
1269
+ );
1270
+ }
1271
+ const userKey = state.entryKeys.get(entryId);
1272
+ if (userKey === void 0) return null;
1273
+ const found = findLeafEntryBySequence(state, userKey, entryId);
1274
+ if (found === null) return null;
1275
+ const entry = leafEntryAt(found.leaf, found.index);
1276
+ return entry;
1277
+ };
1278
+ var updateEntryById = (state, entryId, newValue) => {
1279
+ if (state.entryKeys === null) {
1280
+ throw new BTreeInvariantError(
1281
+ "entryKeys lookup map is not enabled on this tree."
1282
+ );
1283
+ }
1284
+ const userKey = state.entryKeys.get(entryId);
1285
+ if (userKey === void 0) return null;
1286
+ const found = findLeafEntryBySequence(state, userKey, entryId);
1287
+ if (found === null) return null;
1288
+ const entry = leafEntryAt(found.leaf, found.index);
1289
+ const updated = createEntry(entry.key, entry.entryId, newValue);
1290
+ found.leaf.entries[found.leaf.entryOffset + found.index] = updated;
1291
+ return updated;
1292
+ };
1293
+ var removeEntryById = (state, entryId) => {
1294
+ if (state.entryKeys === null) {
1295
+ throw new BTreeInvariantError(
1296
+ "entryKeys lookup map is not enabled on this tree."
1297
+ );
1298
+ }
1299
+ const userKey = state.entryKeys.get(entryId);
1300
+ if (userKey === void 0) return null;
1301
+ const found = findLeafEntryBySequence(state, userKey, entryId);
1302
+ if (found === null) return null;
1303
+ const entry = leafEntryAt(found.leaf, found.index);
1304
+ leafRemoveAt(found.leaf, found.index);
1305
+ state.entryCount -= 1;
1306
+ state.entryKeys.delete(entryId);
1307
+ if (found.index === 0 && leafEntryCount(found.leaf) > 0 && found.leaf.parent !== null) {
1308
+ updateMinKeyInAncestors(found.leaf);
1309
+ }
1310
+ if (found.leaf !== state.root && leafEntryCount(found.leaf) < state.minLeafEntries) {
1311
+ rebalanceAfterLeafRemoval(state, found.leaf);
1312
+ }
1313
+ return entry;
1314
+ };
1315
+
1316
+ // src/btree/mutations.ts
1317
+ var findDuplicateEntry = (state, targetLeaf, key, insertAt) => {
1318
+ if (state.duplicateKeys === "allow") return null;
1319
+ if (insertAt > 0) {
1320
+ const candidate = leafEntryAt(targetLeaf, insertAt - 1);
1321
+ if (state.compareKeys(candidate.key, key) === 0) {
1322
+ return {
1323
+ leaf: targetLeaf,
1324
+ physIndex: targetLeaf.entryOffset + insertAt - 1,
1325
+ entry: candidate
1326
+ };
1327
+ }
1328
+ } else if (targetLeaf.prev !== null && leafEntryCount(targetLeaf.prev) > 0) {
1329
+ const prevLeaf = targetLeaf.prev;
1330
+ const prevCount = leafEntryCount(prevLeaf);
1331
+ const candidate = leafEntryAt(prevLeaf, prevCount - 1);
1332
+ if (state.compareKeys(candidate.key, key) === 0) {
1333
+ return {
1334
+ leaf: prevLeaf,
1335
+ physIndex: prevLeaf.entryOffset + prevCount - 1,
1336
+ entry: candidate
1337
+ };
1338
+ }
1339
+ }
1340
+ return null;
1341
+ };
1069
1342
  var putEntryIntoLeaf = (state, targetLeaf, key, value) => {
1070
1343
  const sequence = state.nextSequence;
1071
1344
  const insertAt = upperBoundInLeaf(state, targetLeaf, key, sequence);
1072
- if (state.duplicateKeys !== "allow") {
1073
- let existingEntry = null;
1074
- if (insertAt > 0) {
1075
- const candidate = leafEntryAt(targetLeaf, insertAt - 1);
1076
- if (state.compareKeys(candidate.key, key) === 0) {
1077
- existingEntry = candidate;
1078
- }
1079
- } else if (targetLeaf.prev !== null && leafEntryCount(targetLeaf.prev) > 0) {
1080
- const prevLeaf = targetLeaf.prev;
1081
- const candidate = leafEntryAt(prevLeaf, leafEntryCount(prevLeaf) - 1);
1082
- if (state.compareKeys(candidate.key, key) === 0) {
1083
- existingEntry = candidate;
1084
- }
1085
- }
1086
- if (existingEntry !== null) {
1087
- if (state.duplicateKeys === "reject") {
1088
- throw new BTreeValidationError("Duplicate key rejected.");
1089
- }
1090
- existingEntry.value = value;
1091
- return existingEntry.entryId;
1092
- }
1345
+ const dup = findDuplicateEntry(state, targetLeaf, key, insertAt);
1346
+ if (dup !== null) {
1347
+ if (state.duplicateKeys === "reject") {
1348
+ throw new BTreeValidationError("Duplicate key rejected.");
1349
+ }
1350
+ dup.leaf.entries[dup.physIndex] = createEntry(
1351
+ dup.entry.key,
1352
+ dup.entry.entryId,
1353
+ value
1354
+ );
1355
+ return dup.entry.entryId;
1093
1356
  }
1094
1357
  if (state.nextSequence >= Number.MAX_SAFE_INTEGER) {
1095
1358
  throw new BTreeValidationError("Sequence overflow.");
1096
1359
  }
1097
1360
  state.nextSequence += 1;
1098
- leafInsertAt(targetLeaf, insertAt, { key, entryId: sequence, value });
1361
+ leafInsertAt(
1362
+ targetLeaf,
1363
+ insertAt,
1364
+ createEntry(key, sequence, value)
1365
+ );
1099
1366
  state.entryCount += 1;
1100
1367
  if (state.entryKeys !== null) {
1101
1368
  state.entryKeys.set(sequence, key);
1102
1369
  }
1103
- if (insertAt === 0 && targetLeaf.parent !== null) updateMinKeyInAncestors(targetLeaf);
1104
- if (leafEntryCount(targetLeaf) > state.maxLeafEntries) splitLeaf(state, targetLeaf);
1370
+ if (insertAt === 0 && targetLeaf.parent !== null)
1371
+ updateMinKeyInAncestors(targetLeaf);
1372
+ if (leafEntryCount(targetLeaf) > state.maxLeafEntries)
1373
+ splitLeaf(state, targetLeaf);
1105
1374
  maybeAutoScale(state);
1106
1375
  return sequence;
1107
1376
  };
@@ -1112,7 +1381,8 @@ var putEntry = (state, key, value) => {
1112
1381
  var popFirstEntry = (state) => {
1113
1382
  if (state.entryCount === 0) return null;
1114
1383
  const firstEntry = leafShiftEntry(state.leftmostLeaf);
1115
- if (firstEntry === void 0) throw new BTreeInvariantError("leftmost leaf empty but count > 0");
1384
+ if (firstEntry === void 0)
1385
+ throw new BTreeInvariantError("leftmost leaf empty but count > 0");
1116
1386
  state.entryCount -= 1;
1117
1387
  if (state.entryKeys !== null) {
1118
1388
  state.entryKeys.delete(firstEntry.entryId);
@@ -1128,7 +1398,8 @@ var popFirstEntry = (state) => {
1128
1398
  var popLastEntry = (state) => {
1129
1399
  if (state.entryCount === 0) return null;
1130
1400
  const lastEntry = leafPopEntry(state.rightmostLeaf);
1131
- if (lastEntry === void 0) throw new BTreeInvariantError("rightmost leaf empty but count > 0");
1401
+ if (lastEntry === void 0)
1402
+ throw new BTreeInvariantError("rightmost leaf empty but count > 0");
1132
1403
  state.entryCount -= 1;
1133
1404
  if (state.entryKeys !== null) {
1134
1405
  state.entryKeys.delete(lastEntry.entryId);
@@ -1149,70 +1420,22 @@ var removeFirstMatchingEntry = (state, key) => {
1149
1420
  if (state.entryKeys !== null) {
1150
1421
  state.entryKeys.delete(targetEntry.entryId);
1151
1422
  }
1152
- if (removeAt === 0 && leafEntryCount(targetLeaf) > 0 && targetLeaf.parent !== null) updateMinKeyInAncestors(targetLeaf);
1423
+ if (removeAt === 0 && leafEntryCount(targetLeaf) > 0 && targetLeaf.parent !== null)
1424
+ updateMinKeyInAncestors(targetLeaf);
1153
1425
  if (targetLeaf !== state.root && leafEntryCount(targetLeaf) < state.minLeafEntries) {
1154
1426
  rebalanceAfterLeafRemoval(state, targetLeaf);
1155
1427
  }
1156
1428
  return targetEntry;
1157
1429
  };
1158
- var findLeafEntryBySequence = (state, userKey, sequence) => {
1159
- const targetLeaf = findLeafForKey(state, userKey, sequence);
1160
- const index = lowerBoundInLeaf(state, targetLeaf, userKey, sequence);
1161
- if (index >= leafEntryCount(targetLeaf)) return null;
1162
- const entry = leafEntryAt(targetLeaf, index);
1163
- if (entry.entryId !== sequence) return null;
1164
- return { leaf: targetLeaf, index };
1165
- };
1166
- var removeEntryById = (state, entryId) => {
1167
- if (state.entryKeys === null) {
1168
- throw new BTreeInvariantError("entryKeys lookup map is not enabled on this tree.");
1169
- }
1170
- const userKey = state.entryKeys.get(entryId);
1171
- if (userKey === void 0) return null;
1172
- const found = findLeafEntryBySequence(state, userKey, entryId);
1173
- if (found === null) return null;
1174
- const entry = leafEntryAt(found.leaf, found.index);
1175
- leafRemoveAt(found.leaf, found.index);
1176
- state.entryCount -= 1;
1177
- state.entryKeys.delete(entryId);
1178
- if (found.index === 0 && leafEntryCount(found.leaf) > 0 && found.leaf.parent !== null) {
1179
- updateMinKeyInAncestors(found.leaf);
1180
- }
1181
- if (found.leaf !== state.root && leafEntryCount(found.leaf) < state.minLeafEntries) {
1182
- rebalanceAfterLeafRemoval(state, found.leaf);
1183
- }
1184
- return entry;
1185
- };
1186
- var peekEntryById = (state, entryId) => {
1187
- if (state.entryKeys === null) {
1188
- throw new BTreeInvariantError("entryKeys lookup map is not enabled on this tree.");
1189
- }
1190
- const userKey = state.entryKeys.get(entryId);
1191
- if (userKey === void 0) return null;
1192
- const found = findLeafEntryBySequence(state, userKey, entryId);
1193
- if (found === null) return null;
1194
- const entry = leafEntryAt(found.leaf, found.index);
1195
- return entry;
1196
- };
1197
- var updateEntryById = (state, entryId, newValue) => {
1198
- if (state.entryKeys === null) {
1199
- throw new BTreeInvariantError("entryKeys lookup map is not enabled on this tree.");
1200
- }
1201
- const userKey = state.entryKeys.get(entryId);
1202
- if (userKey === void 0) return null;
1203
- const found = findLeafEntryBySequence(state, userKey, entryId);
1204
- if (found === null) return null;
1205
- const entry = leafEntryAt(found.leaf, found.index);
1206
- entry.value = newValue;
1207
- return entry;
1208
- };
1209
1430
  var putManyEntries = (state, entries) => {
1210
1431
  if (entries.length === 0) return [];
1211
1432
  const strictlyAscending = state.duplicateKeys !== "allow";
1212
1433
  for (let i = 1; i < entries.length; i += 1) {
1213
1434
  const cmp = state.compareKeys(entries[i - 1].key, entries[i].key);
1214
1435
  if (cmp > 0) {
1215
- throw new BTreeValidationError("putMany: entries not in ascending order.");
1436
+ throw new BTreeValidationError(
1437
+ "putMany: entries not in ascending order."
1438
+ );
1216
1439
  }
1217
1440
  if (strictlyAscending && cmp === 0) {
1218
1441
  throw new BTreeValidationError(
@@ -1225,7 +1448,12 @@ var putManyEntries = (state, entries) => {
1225
1448
  let hintLeaf = findLeafForKey(state, entries[0].key, state.nextSequence);
1226
1449
  for (let i = 0; i < entries.length; i += 1) {
1227
1450
  const entry = entries[i];
1228
- const targetLeaf = findLeafFromHint(state, hintLeaf, entry.key, state.nextSequence);
1451
+ const targetLeaf = findLeafFromHint(
1452
+ state,
1453
+ hintLeaf,
1454
+ entry.key,
1455
+ state.nextSequence
1456
+ );
1229
1457
  ids[i] = putEntryIntoLeaf(state, targetLeaf, entry.key, entry.value);
1230
1458
  hintLeaf = targetLeaf;
1231
1459
  }
@@ -1240,7 +1468,8 @@ var buildConfigFromState = (state) => {
1240
1468
  compareKeys: state.compareKeys,
1241
1469
  duplicateKeys: state.duplicateKeys,
1242
1470
  enableEntryIdLookup: state.entryKeys !== null,
1243
- autoScale: state.autoScale
1471
+ autoScale: state.autoScale,
1472
+ deleteRebalancePolicy: state.deleteRebalancePolicy
1244
1473
  };
1245
1474
  if (!state.autoScale) {
1246
1475
  config.maxLeafEntries = state.maxLeafEntries;
@@ -1260,17 +1489,17 @@ var serializeToJSON = (state) => {
1260
1489
  }
1261
1490
  leaf = leaf.next;
1262
1491
  }
1263
- return {
1264
- version: 1,
1265
- config: {
1266
- maxLeafEntries: state.maxLeafEntries,
1267
- maxBranchChildren: state.maxBranchChildren,
1268
- duplicateKeys: state.duplicateKeys,
1269
- enableEntryIdLookup: state.entryKeys !== null,
1270
- autoScale: state.autoScale
1271
- },
1272
- entries
1492
+ const config = {
1493
+ maxLeafEntries: state.maxLeafEntries,
1494
+ maxBranchChildren: state.maxBranchChildren,
1495
+ duplicateKeys: state.duplicateKeys,
1496
+ enableEntryIdLookup: state.entryKeys !== null,
1497
+ autoScale: state.autoScale
1273
1498
  };
1499
+ if (state.deleteRebalancePolicy !== "standard") {
1500
+ config.deleteRebalancePolicy = state.deleteRebalancePolicy;
1501
+ }
1502
+ return { version: 1, config, entries };
1274
1503
  };
1275
1504
  var MAX_SERIALIZED_ENTRIES = 1e6;
1276
1505
  var validateStructure = (json) => {
@@ -1333,13 +1562,28 @@ var validateBTreeJSON = (json) => {
1333
1562
  validateStructure(json);
1334
1563
  validateConfig(json.config);
1335
1564
  };
1565
+ var validateBTreeJSONSortOrder = (json, compareKeys) => {
1566
+ const strict = json.config.duplicateKeys !== "allow";
1567
+ for (let i = 1; i < json.entries.length; i += 1) {
1568
+ const cmp = compareKeys(json.entries[i - 1][0], json.entries[i][0]);
1569
+ if (cmp > 0) {
1570
+ throw new BTreeValidationError("fromJSON: entries not sorted.");
1571
+ }
1572
+ if (strict && cmp === 0) {
1573
+ throw new BTreeValidationError(
1574
+ 'fromJSON: duplicate keys require duplicateKeys "allow".'
1575
+ );
1576
+ }
1577
+ }
1578
+ };
1336
1579
  var buildConfigFromJSON = (json, compareKeys) => {
1337
1580
  const cfg = json.config;
1338
1581
  const config = {
1339
1582
  compareKeys,
1340
1583
  duplicateKeys: cfg.duplicateKeys,
1341
1584
  enableEntryIdLookup: cfg.enableEntryIdLookup,
1342
- autoScale: cfg.autoScale
1585
+ autoScale: cfg.autoScale,
1586
+ deleteRebalancePolicy: cfg.deleteRebalancePolicy
1343
1587
  };
1344
1588
  if (!cfg.autoScale) {
1345
1589
  config.maxLeafEntries = cfg.maxLeafEntries;
@@ -1348,6 +1592,44 @@ var buildConfigFromJSON = (json, compareKeys) => {
1348
1592
  return config;
1349
1593
  };
1350
1594
 
1595
+ // src/btree/traversal.ts
1596
+ var snapshotEntries = (state) => {
1597
+ const result = new Array(state.entryCount);
1598
+ let leaf = state.leftmostLeaf;
1599
+ let writeIdx = 0;
1600
+ while (leaf !== null) {
1601
+ const count = leafEntryCount(leaf);
1602
+ for (let i = 0; i < count; i += 1) {
1603
+ result[writeIdx++] = freezeEntry(leafEntryAt(leaf, i));
1604
+ }
1605
+ leaf = leaf.next;
1606
+ }
1607
+ return result;
1608
+ };
1609
+ var collectInternalEntries = (state) => {
1610
+ const result = new Array(state.entryCount);
1611
+ let leaf = state.leftmostLeaf;
1612
+ let writeIdx = 0;
1613
+ while (leaf !== null) {
1614
+ const count = leafEntryCount(leaf);
1615
+ for (let i = 0; i < count; i += 1) {
1616
+ result[writeIdx++] = leafEntryAt(leaf, i);
1617
+ }
1618
+ leaf = leaf.next;
1619
+ }
1620
+ return result;
1621
+ };
1622
+ var forEachEntry = (state, callback, thisArg) => {
1623
+ let leaf = state.leftmostLeaf;
1624
+ while (leaf !== null) {
1625
+ const count = leafEntryCount(leaf);
1626
+ for (let i = 0; i < count; i += 1) {
1627
+ callback.call(thisArg, freezeEntry(leafEntryAt(leaf, i)));
1628
+ }
1629
+ leaf = leaf.next;
1630
+ }
1631
+ };
1632
+
1351
1633
  // src/btree/integrity-helpers.ts
1352
1634
  var nodeMinKey = (node) => {
1353
1635
  if (isLeafNode(node)) {
@@ -1356,7 +1638,10 @@ var nodeMinKey = (node) => {
1356
1638
  return { key: e.key, sequence: e.entryId };
1357
1639
  }
1358
1640
  if (node.childOffset >= node.keys.length) return null;
1359
- return { key: node.keys[node.childOffset].key, sequence: node.keys[node.childOffset].sequence };
1641
+ return {
1642
+ key: node.keys[node.childOffset].key,
1643
+ sequence: node.keys[node.childOffset].sequence
1644
+ };
1360
1645
  };
1361
1646
  var compareNodeKeys = (comparator, leftKey, leftSeq, rightKey, rightSeq) => {
1362
1647
  const cmp = comparator(leftKey, rightKey);
@@ -1378,9 +1663,7 @@ var getNodeMaxKey = (node) => {
1378
1663
  };
1379
1664
  var validateComparatorResult = (result) => {
1380
1665
  if (!Number.isFinite(result)) {
1381
- throw new BTreeValidationError(
1382
- "compareKeys must return a finite number."
1383
- );
1666
+ throw new BTreeValidationError("compareKeys must return a finite number.");
1384
1667
  }
1385
1668
  return result;
1386
1669
  };
@@ -1440,6 +1723,34 @@ var assertTransitivityAsInvariant = (state, first, second, third) => {
1440
1723
  throw error;
1441
1724
  }
1442
1725
  };
1726
+ var validateAdjacentLeafOrdering = (state, previous, cursor) => {
1727
+ const prevMax = getNodeMaxKey(previous);
1728
+ const currentMin = nodeMinKey(cursor);
1729
+ if (prevMax === null || currentMin === null) {
1730
+ throw new BTreeInvariantError(
1731
+ "Non-empty tree leaf chain contains empty leaf node."
1732
+ );
1733
+ }
1734
+ if (compareNodeKeys(
1735
+ state.compareKeys,
1736
+ prevMax.key,
1737
+ prevMax.sequence,
1738
+ currentMin.key,
1739
+ currentMin.sequence
1740
+ ) > 0) {
1741
+ throw new BTreeInvariantError("Adjacent leaf key ranges are out of order.");
1742
+ }
1743
+ const prevCount = leafEntryCount(previous);
1744
+ const curCount = leafEntryCount(cursor);
1745
+ if (state.duplicateKeys !== "allow" && prevCount > 0 && curCount > 0 && state.compareKeys(
1746
+ leafEntryAt(previous, prevCount - 1).key,
1747
+ leafEntryAt(cursor, 0).key
1748
+ ) === 0) {
1749
+ throw new BTreeInvariantError(
1750
+ "Duplicate user key detected across adjacent leaves with uniqueness policy."
1751
+ );
1752
+ }
1753
+ };
1443
1754
  var validateLeafChainStep = (state, cursor, previous, visited) => {
1444
1755
  if (!isLeafNode(cursor)) {
1445
1756
  throw new BTreeInvariantError("Leaf linkage cursor reached non-leaf node.");
@@ -1451,22 +1762,7 @@ var validateLeafChainStep = (state, cursor, previous, visited) => {
1451
1762
  throw new BTreeInvariantError("Leaf prev pointer mismatch.");
1452
1763
  }
1453
1764
  if (previous !== null && isLeafNode(previous)) {
1454
- const prevMax = getNodeMaxKey(previous);
1455
- const currentMin = nodeMinKey(cursor);
1456
- if (prevMax === null || currentMin === null) {
1457
- throw new BTreeInvariantError("Non-empty tree leaf chain contains empty leaf node.");
1458
- }
1459
- if (compareNodeKeys(state.compareKeys, prevMax.key, prevMax.sequence, currentMin.key, currentMin.sequence) > 0) {
1460
- throw new BTreeInvariantError("Adjacent leaf key ranges are out of order.");
1461
- }
1462
- const prevCount = leafEntryCount(previous);
1463
- const curCount = leafEntryCount(cursor);
1464
- if (state.duplicateKeys !== "allow" && prevCount > 0 && curCount > 0 && state.compareKeys(
1465
- leafEntryAt(previous, prevCount - 1).key,
1466
- leafEntryAt(cursor, 0).key
1467
- ) === 0) {
1468
- throw new BTreeInvariantError("Duplicate user key detected across adjacent leaves with uniqueness policy.");
1469
- }
1765
+ validateAdjacentLeafOrdering(state, previous, cursor);
1470
1766
  }
1471
1767
  };
1472
1768
  var validateLeafLinks = (state, expectedLeafCount) => {
@@ -1475,7 +1771,9 @@ var validateLeafLinks = (state, expectedLeafCount) => {
1475
1771
  throw new BTreeInvariantError("Empty tree root must be a leaf node.");
1476
1772
  }
1477
1773
  if (state.leftmostLeaf !== state.root || state.rightmostLeaf !== state.root) {
1478
- throw new BTreeInvariantError("Empty tree leaf pointers must reference root leaf.");
1774
+ throw new BTreeInvariantError(
1775
+ "Empty tree leaf pointers must reference root leaf."
1776
+ );
1479
1777
  }
1480
1778
  return;
1481
1779
  }
@@ -1500,7 +1798,9 @@ var validateLeafLinks = (state, expectedLeafCount) => {
1500
1798
  throw new BTreeInvariantError("Rightmost leaf pointer mismatch.");
1501
1799
  }
1502
1800
  if (leafCount !== expectedLeafCount) {
1503
- throw new BTreeInvariantError("Leaf chain count mismatch with tree traversal count.");
1801
+ throw new BTreeInvariantError(
1802
+ "Leaf chain count mismatch with tree traversal count."
1803
+ );
1504
1804
  }
1505
1805
  };
1506
1806
 
@@ -1527,7 +1827,9 @@ var validateLeafNodeOrdering = (state, node) => {
1527
1827
  leafEntryAt(node, index - 1).key,
1528
1828
  leafEntryAt(node, index).key
1529
1829
  ) === 0) {
1530
- throw new BTreeInvariantError("Duplicate user key detected in tree with uniqueness policy.");
1830
+ throw new BTreeInvariantError(
1831
+ "Duplicate user key detected in tree with uniqueness policy."
1832
+ );
1531
1833
  }
1532
1834
  }
1533
1835
  }
@@ -1535,12 +1837,7 @@ var validateLeafNodeOrdering = (state, node) => {
1535
1837
  const first = leafEntryAt(node, index - 2);
1536
1838
  const second = leafEntryAt(node, index - 1);
1537
1839
  const third = leafEntryAt(node, index);
1538
- assertTransitivityAsInvariant(
1539
- state,
1540
- first.key,
1541
- second.key,
1542
- third.key
1543
- );
1840
+ assertTransitivityAsInvariant(state, first.key, second.key, third.key);
1544
1841
  }
1545
1842
  if (count > state.maxLeafEntries) {
1546
1843
  throw new BTreeInvariantError("Leaf node exceeds maximum occupancy.");
@@ -1549,9 +1846,14 @@ var validateLeafNodeOrdering = (state, node) => {
1549
1846
  var validateLeafNode = (state, node, depth) => {
1550
1847
  validateLeafNodeOrdering(state, node);
1551
1848
  const count = leafEntryCount(node);
1552
- const baseMinLeaf = state.autoScale ? Math.ceil(computeAutoScaleTier(0).maxLeaf / 2) : state.minLeafEntries;
1849
+ let baseMinLeaf = state.autoScale ? Math.ceil(computeAutoScaleTier(0).maxLeaf / 2) : state.minLeafEntries;
1850
+ if (state.deleteRebalancePolicy === "lazy") {
1851
+ baseMinLeaf = applyLazyThreshold(baseMinLeaf);
1852
+ }
1553
1853
  if (node !== state.root && count < baseMinLeaf) {
1554
- throw new BTreeInvariantError("Non-root leaf node violates minimum occupancy.");
1854
+ throw new BTreeInvariantError(
1855
+ "Non-root leaf node violates minimum occupancy."
1856
+ );
1555
1857
  }
1556
1858
  const first = count === 0 ? null : leafEntryAt(node, 0);
1557
1859
  const last = count === 0 ? null : leafEntryAt(node, count - 1);
@@ -1573,76 +1875,110 @@ var validateBranchStructure = (state, node) => {
1573
1875
  }
1574
1876
  const baseMinBranch = state.autoScale ? Math.ceil(computeAutoScaleTier(0).maxBranch / 2) : state.minBranchChildren;
1575
1877
  if (node !== state.root && liveCount < baseMinBranch) {
1576
- throw new BTreeInvariantError("Non-root branch node violates minimum occupancy.");
1878
+ throw new BTreeInvariantError(
1879
+ "Non-root branch node violates minimum occupancy."
1880
+ );
1577
1881
  }
1578
1882
  if (liveCount > state.maxBranchChildren) {
1579
1883
  throw new BTreeInvariantError("Branch node exceeds maximum occupancy.");
1580
1884
  }
1581
1885
  if (node.keys.length !== node.children.length) {
1582
- throw new BTreeInvariantError("Branch keys array length does not match children array length.");
1886
+ throw new BTreeInvariantError(
1887
+ "Branch keys array length does not match children array length."
1888
+ );
1583
1889
  }
1584
1890
  };
1585
1891
  var validateBranchChild = (state, node, childIndex, depth) => {
1586
1892
  const child = node.children[childIndex];
1587
1893
  if (child.parent !== node) {
1588
- throw new BTreeInvariantError("Child-parent pointer mismatch in branch node.");
1894
+ throw new BTreeInvariantError(
1895
+ "Child-parent pointer mismatch in branch node."
1896
+ );
1589
1897
  }
1590
1898
  if (child.indexInParent !== childIndex) {
1591
- throw new BTreeInvariantError("Child indexInParent does not match actual position in parent.");
1899
+ throw new BTreeInvariantError(
1900
+ "Child indexInParent does not match actual position in parent."
1901
+ );
1592
1902
  }
1593
1903
  const childValidation = validateNode(state, child, depth + 1);
1594
1904
  if (childValidation.minKey === null || childValidation.maxKey === null) {
1595
- throw new BTreeInvariantError("Branch child must not be empty in non-root branch tree.");
1905
+ throw new BTreeInvariantError(
1906
+ "Branch child must not be empty in non-root branch tree."
1907
+ );
1596
1908
  }
1597
1909
  const cachedMinKey = node.keys[childIndex];
1598
1910
  const actualMinKey = nodeMinKey(child);
1599
- if (actualMinKey === null || compareNodeKeys(state.compareKeys, cachedMinKey.key, cachedMinKey.sequence, actualMinKey.key, actualMinKey.sequence) !== 0) {
1600
- throw new BTreeInvariantError("Branch cached key does not match actual child minimum key.");
1911
+ if (actualMinKey === null || compareNodeKeys(
1912
+ state.compareKeys,
1913
+ cachedMinKey.key,
1914
+ cachedMinKey.sequence,
1915
+ actualMinKey.key,
1916
+ actualMinKey.sequence
1917
+ ) !== 0) {
1918
+ throw new BTreeInvariantError(
1919
+ "Branch cached key does not match actual child minimum key."
1920
+ );
1601
1921
  }
1602
1922
  return childValidation;
1603
1923
  };
1924
+ var mergeChildValidation = (state, accumulated, childValidation) => {
1925
+ if (accumulated.leafDepth !== null && childValidation.leafDepth !== null && childValidation.leafDepth !== accumulated.leafDepth) {
1926
+ throw new BTreeInvariantError("Leaf depth mismatch detected in tree.");
1927
+ }
1928
+ if (accumulated.leafDepth === null && childValidation.leafDepth !== null) {
1929
+ accumulated.leafDepth = childValidation.leafDepth;
1930
+ }
1931
+ if (accumulated.previousChildMax !== null && compareNodeKeys(
1932
+ state.compareKeys,
1933
+ accumulated.previousChildMax.key,
1934
+ accumulated.previousChildMax.sequence,
1935
+ childValidation.minKey.key,
1936
+ childValidation.minKey.sequence
1937
+ ) >= 0) {
1938
+ throw new BTreeInvariantError(
1939
+ "Branch child key ranges are not strictly ordered."
1940
+ );
1941
+ }
1942
+ if (accumulated.minKey === null) accumulated.minKey = childValidation.minKey;
1943
+ accumulated.maxKey = childValidation.maxKey;
1944
+ accumulated.previousChildMax = childValidation.maxKey;
1945
+ accumulated.leafCount += childValidation.leafCount;
1946
+ accumulated.branchCount += childValidation.branchCount;
1947
+ accumulated.entryCount += childValidation.entryCount;
1948
+ };
1604
1949
  var validateNode = (state, node, depth) => {
1605
1950
  if (isLeafNode(node)) {
1606
1951
  return validateLeafNode(state, node, depth);
1607
1952
  }
1608
1953
  validateBranchStructure(state, node);
1609
- let leafDepth = null;
1610
- let leafCount = 0;
1611
- let branchCount = 1;
1612
- let entryCount = 0;
1613
- let minKey = null;
1614
- let maxKey = null;
1615
- let previousChildMax = null;
1954
+ const acc = {
1955
+ leafDepth: null,
1956
+ leafCount: 0,
1957
+ branchCount: 1,
1958
+ entryCount: 0,
1959
+ minKey: null,
1960
+ maxKey: null,
1961
+ previousChildMax: null
1962
+ };
1616
1963
  for (let childIndex = node.childOffset; childIndex < node.children.length; childIndex += 1) {
1617
1964
  const childValidation = validateBranchChild(state, node, childIndex, depth);
1618
- if (leafDepth !== null && childValidation.leafDepth !== null && childValidation.leafDepth !== leafDepth) {
1619
- throw new BTreeInvariantError("Leaf depth mismatch detected in tree.");
1620
- }
1621
- if (leafDepth === null && childValidation.leafDepth !== null) {
1622
- leafDepth = childValidation.leafDepth;
1623
- }
1624
- if (previousChildMax !== null && compareNodeKeys(
1625
- state.compareKeys,
1626
- previousChildMax.key,
1627
- previousChildMax.sequence,
1628
- childValidation.minKey.key,
1629
- childValidation.minKey.sequence
1630
- ) >= 0) {
1631
- throw new BTreeInvariantError("Branch child key ranges are not strictly ordered.");
1632
- }
1633
- if (minKey === null) minKey = childValidation.minKey;
1634
- maxKey = childValidation.maxKey;
1635
- previousChildMax = childValidation.maxKey;
1636
- leafCount += childValidation.leafCount;
1637
- branchCount += childValidation.branchCount;
1638
- entryCount += childValidation.entryCount;
1965
+ mergeChildValidation(state, acc, childValidation);
1639
1966
  }
1640
- return { minKey, maxKey, leafDepth, leafCount, branchCount, entryCount };
1967
+ return {
1968
+ minKey: acc.minKey,
1969
+ maxKey: acc.maxKey,
1970
+ leafDepth: acc.leafDepth,
1971
+ leafCount: acc.leafCount,
1972
+ branchCount: acc.branchCount,
1973
+ entryCount: acc.entryCount
1974
+ };
1641
1975
  };
1642
1976
  var assertInvariants = (state) => {
1643
1977
  const validation = validateNode(state, state.root, 0);
1644
1978
  if (validation.entryCount !== state.entryCount) {
1645
- throw new BTreeInvariantError("Index entry count mismatch between tree traversal and tracked state.");
1979
+ throw new BTreeInvariantError(
1980
+ "Index entry count mismatch between tree traversal and tracked state."
1981
+ );
1646
1982
  }
1647
1983
  validateLeafLinks(state, validation.leafCount);
1648
1984
  };
@@ -1698,7 +2034,7 @@ var InMemoryBTree = class _InMemoryBTree {
1698
2034
  remove(key) {
1699
2035
  const entry = removeFirstMatchingEntry(this.state, key);
1700
2036
  if (entry === null) return null;
1701
- return toPublicEntry(entry);
2037
+ return freezeEntry(entry);
1702
2038
  }
1703
2039
  removeById(entryId) {
1704
2040
  if (this.state.entryKeys === null) {
@@ -1706,7 +2042,7 @@ var InMemoryBTree = class _InMemoryBTree {
1706
2042
  }
1707
2043
  const entry = removeEntryById(this.state, entryId);
1708
2044
  if (entry === null) return null;
1709
- return toPublicEntry(entry);
2045
+ return freezeEntry(entry);
1710
2046
  }
1711
2047
  peekById(entryId) {
1712
2048
  if (this.state.entryKeys === null) {
@@ -1714,7 +2050,7 @@ var InMemoryBTree = class _InMemoryBTree {
1714
2050
  }
1715
2051
  const entry = peekEntryById(this.state, entryId);
1716
2052
  if (entry === null) return null;
1717
- return toPublicEntry(entry);
2053
+ return freezeEntry(entry);
1718
2054
  }
1719
2055
  updateById(entryId, value) {
1720
2056
  if (this.state.entryKeys === null) {
@@ -1722,30 +2058,30 @@ var InMemoryBTree = class _InMemoryBTree {
1722
2058
  }
1723
2059
  const entry = updateEntryById(this.state, entryId, value);
1724
2060
  if (entry === null) return null;
1725
- return toPublicEntry(entry);
2061
+ return freezeEntry(entry);
1726
2062
  }
1727
2063
  popFirst() {
1728
2064
  const entry = popFirstEntry(this.state);
1729
2065
  if (entry === null) return null;
1730
- return toPublicEntry(entry);
2066
+ return freezeEntry(entry);
1731
2067
  }
1732
2068
  peekFirst() {
1733
2069
  if (this.state.entryCount === 0) {
1734
2070
  return null;
1735
2071
  }
1736
- return toPublicEntry(leafEntryAt(this.state.leftmostLeaf, 0));
2072
+ return freezeEntry(leafEntryAt(this.state.leftmostLeaf, 0));
1737
2073
  }
1738
2074
  peekLast() {
1739
2075
  if (this.state.entryCount === 0) {
1740
2076
  return null;
1741
2077
  }
1742
2078
  const leaf = this.state.rightmostLeaf;
1743
- return toPublicEntry(leafEntryAt(leaf, leafEntryCount(leaf) - 1));
2079
+ return freezeEntry(leafEntryAt(leaf, leafEntryCount(leaf) - 1));
1744
2080
  }
1745
2081
  popLast() {
1746
2082
  const entry = popLastEntry(this.state);
1747
2083
  if (entry === null) return null;
1748
- return toPublicEntry(entry);
2084
+ return freezeEntry(entry);
1749
2085
  }
1750
2086
  clear() {
1751
2087
  const emptyLeaf = createLeafNode([], null);
@@ -1755,16 +2091,9 @@ var InMemoryBTree = class _InMemoryBTree {
1755
2091
  this.state.entryCount = 0;
1756
2092
  this.state._cursor.leaf = emptyLeaf;
1757
2093
  this.state._cursor.index = 0;
1758
- if (this.state.entryKeys !== null) {
1759
- this.state.entryKeys.clear();
1760
- }
2094
+ this.state.entryKeys?.clear();
1761
2095
  if (this.state.autoScale) {
1762
- const tier = computeAutoScaleTier(0);
1763
- this.state.maxLeafEntries = tier.maxLeaf;
1764
- this.state.maxBranchChildren = tier.maxBranch;
1765
- this.state.minLeafEntries = minOccupancy(tier.maxLeaf);
1766
- this.state.minBranchChildren = minOccupancy(tier.maxBranch);
1767
- this.state._nextAutoScaleThreshold = computeNextAutoScaleThreshold(0);
2096
+ resetAutoScaleToTier0(this.state);
1768
2097
  }
1769
2098
  }
1770
2099
  get(key) {
@@ -1778,65 +2107,39 @@ var InMemoryBTree = class _InMemoryBTree {
1778
2107
  findFirst(key) {
1779
2108
  const found = findFirstMatchingUserKey(this.state, key);
1780
2109
  if (found === null) return null;
1781
- return toPublicEntry(leafEntryAt(found.leaf, found.index));
2110
+ return freezeEntry(leafEntryAt(found.leaf, found.index));
1782
2111
  }
1783
- /**
1784
- * Returns the last entry whose key matches `key`, or `null` if not found.
1785
- * Useful when `duplicateKeys` is `'allow'` and multiple entries share the same key.
1786
- */
1787
2112
  findLast(key) {
1788
2113
  const found = findLastMatchingUserKey(this.state, key);
1789
2114
  if (found === null) return null;
1790
- return toPublicEntry(leafEntryAt(found.leaf, found.index));
2115
+ return freezeEntry(leafEntryAt(found.leaf, found.index));
1791
2116
  }
1792
- /**
1793
- * Returns the smallest key in the tree that is strictly greater than `key`,
1794
- * or `null` if no such key exists.
1795
- */
1796
2117
  nextHigherKey(key) {
1797
2118
  return findNextHigherKey(this.state, key);
1798
2119
  }
1799
- /**
1800
- * Returns the largest key in the tree that is strictly less than `key`,
1801
- * or `null` if no such key exists.
1802
- */
1803
2120
  nextLowerKey(key) {
1804
2121
  return findNextLowerKey(this.state, key);
1805
2122
  }
1806
- /**
1807
- * Returns the entry for `key` if it exists; otherwise returns the entry with
1808
- * the largest key strictly less than `key`. Returns `null` when the tree is
1809
- * empty or every key is greater than `key`.
1810
- */
1811
2123
  getPairOrNextLower(key) {
1812
2124
  const found = findPairOrNextLower(this.state, key);
1813
2125
  if (found === null) return null;
1814
- return toPublicEntry(leafEntryAt(found.leaf, found.index));
2126
+ return freezeEntry(leafEntryAt(found.leaf, found.index));
1815
2127
  }
1816
- /**
1817
- * Returns the number of entries whose keys fall within [`startKey`, `endKey`].
1818
- * Pass `options` to make either bound exclusive.
1819
- */
1820
2128
  count(startKey, endKey, options) {
1821
2129
  return countRangeEntries(this.state, startKey, endKey, options);
1822
2130
  }
1823
- /**
1824
- * Deletes all entries whose keys fall within [`startKey`, `endKey`].
1825
- * Pass `options` to make either bound exclusive.
1826
- * @returns The number of entries deleted.
1827
- */
1828
2131
  deleteRange(startKey, endKey, options) {
1829
2132
  return deleteRangeEntries(this.state, startKey, endKey, options);
1830
2133
  }
1831
2134
  range(startKey, endKey, options) {
1832
- return rangeQueryEntries(this.state, startKey, endKey, options).map(toPublicEntry);
2135
+ return rangeQueryPublicEntries(this.state, startKey, endKey, options);
1833
2136
  }
1834
2137
  *entries() {
1835
2138
  let leaf = this.state.leftmostLeaf;
1836
2139
  while (leaf !== null) {
1837
2140
  const count = leafEntryCount(leaf);
1838
2141
  for (let i = 0; i < count; i += 1) {
1839
- yield toPublicEntry(leafEntryAt(leaf, i));
2142
+ yield freezeEntry(leafEntryAt(leaf, i));
1840
2143
  }
1841
2144
  leaf = leaf.next;
1842
2145
  }
@@ -1846,7 +2149,7 @@ var InMemoryBTree = class _InMemoryBTree {
1846
2149
  while (leaf !== null) {
1847
2150
  const count = leafEntryCount(leaf);
1848
2151
  for (let i = count - 1; i >= 0; i -= 1) {
1849
- yield toPublicEntry(leafEntryAt(leaf, i));
2152
+ yield freezeEntry(leafEntryAt(leaf, i));
1850
2153
  }
1851
2154
  leaf = leaf.prev;
1852
2155
  }
@@ -1864,55 +2167,26 @@ var InMemoryBTree = class _InMemoryBTree {
1864
2167
  [Symbol.iterator]() {
1865
2168
  return this.entries();
1866
2169
  }
2170
+ forEachRange(startKey, endKey, callback, options) {
2171
+ forEachRangeEntries(this.state, startKey, endKey, callback, options);
2172
+ }
1867
2173
  forEach(callback, thisArg) {
1868
- let leaf = this.state.leftmostLeaf;
1869
- while (leaf !== null) {
1870
- const count = leafEntryCount(leaf);
1871
- for (let i = 0; i < count; i += 1) {
1872
- callback.call(thisArg, toPublicEntry(leafEntryAt(leaf, i)));
1873
- }
1874
- leaf = leaf.next;
1875
- }
2174
+ forEachEntry(this.state, callback, thisArg);
1876
2175
  }
1877
2176
  snapshot() {
1878
- const result = new Array(this.state.entryCount);
1879
- let leaf = this.state.leftmostLeaf;
1880
- let writeIdx = 0;
1881
- while (leaf !== null) {
1882
- const count = leafEntryCount(leaf);
1883
- for (let i = 0; i < count; i += 1) {
1884
- result[writeIdx++] = toPublicEntry(leafEntryAt(leaf, i));
1885
- }
1886
- leaf = leaf.next;
1887
- }
1888
- return result;
2177
+ return snapshotEntries(this.state);
1889
2178
  }
1890
- /**
1891
- * Returns a structurally independent `InMemoryBTree` with identical
1892
- * configuration and entries. The tree structure (nodes, links, entry IDs)
1893
- * is fully independent, but stored key and value references are shared
1894
- * with the source tree.
1895
- * Note: `EntryId` values are reassigned in the clone — IDs from the source tree are not valid for the clone.
1896
- */
1897
2179
  clone() {
1898
- const cloned = new _InMemoryBTree(buildConfigFromState(this.state));
2180
+ const cloned = new _InMemoryBTree(
2181
+ buildConfigFromState(this.state)
2182
+ );
1899
2183
  applyAutoScaleCapacitySnapshot(
1900
2184
  cloned.state,
1901
2185
  this.state.maxLeafEntries,
1902
2186
  this.state.maxBranchChildren
1903
2187
  );
1904
2188
  if (this.state.entryCount > 0) {
1905
- const pairs = new Array(this.state.entryCount);
1906
- let leaf = this.state.leftmostLeaf;
1907
- let writeIdx = 0;
1908
- while (leaf !== null) {
1909
- const count = leafEntryCount(leaf);
1910
- for (let i = 0; i < count; i += 1) {
1911
- pairs[writeIdx++] = leafEntryAt(leaf, i);
1912
- }
1913
- leaf = leaf.next;
1914
- }
1915
- cloned.putMany(pairs);
2189
+ cloned.putMany(collectInternalEntries(this.state));
1916
2190
  }
1917
2191
  return cloned;
1918
2192
  }
@@ -1921,26 +2195,19 @@ var InMemoryBTree = class _InMemoryBTree {
1921
2195
  }
1922
2196
  static fromJSON(json, compareKeys) {
1923
2197
  validateBTreeJSON(json);
1924
- const strict = json.config.duplicateKeys !== "allow";
1925
- for (let i = 1; i < json.entries.length; i += 1) {
1926
- const cmp = compareKeys(json.entries[i - 1][0], json.entries[i][0]);
1927
- if (cmp > 0) {
1928
- throw new BTreeValidationError("fromJSON: entries not sorted.");
1929
- }
1930
- if (strict && cmp === 0) {
1931
- throw new BTreeValidationError(
1932
- 'fromJSON: duplicate keys require duplicateKeys "allow".'
1933
- );
1934
- }
1935
- }
1936
- const tree = new _InMemoryBTree(buildConfigFromJSON(json, compareKeys));
2198
+ validateBTreeJSONSortOrder(json, compareKeys);
2199
+ const tree = new _InMemoryBTree(
2200
+ buildConfigFromJSON(json, compareKeys)
2201
+ );
1937
2202
  applyAutoScaleCapacitySnapshot(
1938
2203
  tree.state,
1939
2204
  json.config.maxLeafEntries,
1940
2205
  json.config.maxBranchChildren
1941
2206
  );
1942
2207
  if (json.entries.length > 0) {
1943
- const pairs = new Array(json.entries.length);
2208
+ const pairs = new Array(
2209
+ json.entries.length
2210
+ );
1944
2211
  for (let i = 0; i < json.entries.length; i += 1) {
1945
2212
  pairs[i] = { key: json.entries[i][0], value: json.entries[i][1] };
1946
2213
  }