@frostpillar/frostpillar-btree 0.2.0

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 ADDED
@@ -0,0 +1,1919 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/core.ts
21
+ var core_exports = {};
22
+ __export(core_exports, {
23
+ BTreeInvariantError: () => BTreeInvariantError,
24
+ BTreeValidationError: () => BTreeValidationError,
25
+ InMemoryBTree: () => InMemoryBTree
26
+ });
27
+ module.exports = __toCommonJS(core_exports);
28
+
29
+ // src/errors.ts
30
+ var BTreeValidationError = class extends Error {
31
+ constructor(message) {
32
+ super(message);
33
+ this.name = "BTreeValidationError";
34
+ Object.setPrototypeOf(this, new.target.prototype);
35
+ }
36
+ };
37
+ var BTreeInvariantError = class extends Error {
38
+ constructor(message) {
39
+ super(message);
40
+ this.name = "BTreeInvariantError";
41
+ Object.setPrototypeOf(this, new.target.prototype);
42
+ }
43
+ };
44
+
45
+ // src/btree/types.ts
46
+ var DEFAULT_MAX_LEAF_ENTRIES = 64;
47
+ var DEFAULT_MAX_BRANCH_CHILDREN = 64;
48
+ var MIN_NODE_CAPACITY = 3;
49
+ var MAX_NODE_CAPACITY = 16384;
50
+ var NODE_LEAF = 0;
51
+ var NODE_BRANCH = 1;
52
+ var normalizeDuplicateKeyPolicy = (value) => {
53
+ if (value === void 0) {
54
+ return "replace";
55
+ }
56
+ if (value !== "allow" && value !== "reject" && value !== "replace") {
57
+ throw new BTreeValidationError(
58
+ `Invalid duplicateKeys option.`
59
+ );
60
+ }
61
+ return value;
62
+ };
63
+ var isLeafNode = (node) => {
64
+ return node.kind === NODE_LEAF;
65
+ };
66
+ var writeMinKeyTo = (node, target) => {
67
+ if (node.kind === NODE_LEAF) {
68
+ if (node.entryOffset >= node.entries.length) return false;
69
+ const e = node.entries[node.entryOffset];
70
+ target.key = e.key;
71
+ target.sequence = e.entryId;
72
+ return true;
73
+ }
74
+ if (node.childOffset >= node.keys.length) return false;
75
+ target.key = node.keys[node.childOffset].key;
76
+ target.sequence = node.keys[node.childOffset].sequence;
77
+ return true;
78
+ };
79
+ var normalizeNodeCapacity = (value, field, defaultValue) => {
80
+ if (value === void 0) {
81
+ return defaultValue;
82
+ }
83
+ if (!Number.isInteger(value) || value < MIN_NODE_CAPACITY || value > MAX_NODE_CAPACITY) {
84
+ throw new BTreeValidationError(
85
+ `${field}: integer ${MIN_NODE_CAPACITY}\u2013${MAX_NODE_CAPACITY} required.`
86
+ );
87
+ }
88
+ return value;
89
+ };
90
+ var createLeafNode = (entries, parent) => {
91
+ return {
92
+ kind: NODE_LEAF,
93
+ entries,
94
+ entryOffset: 0,
95
+ parent,
96
+ indexInParent: 0,
97
+ prev: null,
98
+ next: null
99
+ };
100
+ };
101
+ var createBranchNode = (children, parent) => {
102
+ const keys = [];
103
+ const branch = {
104
+ kind: NODE_BRANCH,
105
+ children,
106
+ keys,
107
+ childOffset: 0,
108
+ parent,
109
+ indexInParent: 0
110
+ };
111
+ for (let i = 0; i < children.length; i += 1) {
112
+ const child = children[i];
113
+ child.parent = branch;
114
+ child.indexInParent = i;
115
+ const target = { key: void 0, sequence: 0 };
116
+ if (!writeMinKeyTo(child, target)) {
117
+ throw new BTreeInvariantError(
118
+ "branch child has no min key"
119
+ );
120
+ }
121
+ keys.push(target);
122
+ }
123
+ return branch;
124
+ };
125
+ var leafEntryCount = (leaf) => leaf.entries.length - leaf.entryOffset;
126
+ var leafEntryAt = (leaf, i) => leaf.entries[leaf.entryOffset + i];
127
+ var leafShiftEntry = (leaf) => {
128
+ if (leaf.entryOffset >= leaf.entries.length) return void 0;
129
+ const entry = leaf.entries[leaf.entryOffset];
130
+ leaf.entryOffset += 1;
131
+ if (leaf.entryOffset >= leaf.entries.length >>> 1) {
132
+ leaf.entries.copyWithin(0, leaf.entryOffset);
133
+ leaf.entries.length = leaf.entries.length - leaf.entryOffset;
134
+ leaf.entryOffset = 0;
135
+ }
136
+ return entry;
137
+ };
138
+ var leafPopEntry = (leaf) => {
139
+ if (leaf.entryOffset >= leaf.entries.length) return void 0;
140
+ return leaf.entries.pop();
141
+ };
142
+ var leafUnshiftEntry = (leaf, entry) => {
143
+ if (leaf.entryOffset > 0) {
144
+ leaf.entryOffset -= 1;
145
+ leaf.entries[leaf.entryOffset] = entry;
146
+ } else {
147
+ leaf.entries.unshift(entry);
148
+ }
149
+ };
150
+ var leafRemoveAt = (leaf, logicalIndex) => {
151
+ const count = leaf.entries.length - leaf.entryOffset;
152
+ const phys = leaf.entryOffset + logicalIndex;
153
+ if (logicalIndex < count - 1 - logicalIndex) {
154
+ leaf.entries.copyWithin(leaf.entryOffset + 1, leaf.entryOffset, phys);
155
+ leaf.entryOffset += 1;
156
+ if (leaf.entryOffset >= leaf.entries.length >>> 1) {
157
+ leaf.entries.copyWithin(0, leaf.entryOffset);
158
+ leaf.entries.length -= leaf.entryOffset;
159
+ leaf.entryOffset = 0;
160
+ }
161
+ } else {
162
+ leaf.entries.copyWithin(phys, phys + 1);
163
+ leaf.entries.length -= 1;
164
+ }
165
+ };
166
+ var leafInsertAt = (leaf, logicalIndex, entry) => {
167
+ const phys = leaf.entryOffset + logicalIndex;
168
+ if (leaf.entryOffset > 0 && logicalIndex < leaf.entries.length - leaf.entryOffset >>> 1) {
169
+ leaf.entries.copyWithin(leaf.entryOffset - 1, leaf.entryOffset, phys);
170
+ leaf.entryOffset -= 1;
171
+ leaf.entries[phys - 1] = entry;
172
+ } else {
173
+ leaf.entries.splice(phys, 0, entry);
174
+ }
175
+ };
176
+ var leafCompact = (leaf) => {
177
+ if (leaf.entryOffset > 0) {
178
+ leaf.entries.copyWithin(0, leaf.entryOffset);
179
+ leaf.entries.length = leaf.entries.length - leaf.entryOffset;
180
+ leaf.entryOffset = 0;
181
+ }
182
+ };
183
+ var BRANCH_COMPACT_GAP = 1;
184
+ var branchCompact = (branch) => {
185
+ if (branch.childOffset > 0) {
186
+ const gap = branch.childOffset <= BRANCH_COMPACT_GAP ? 0 : BRANCH_COMPACT_GAP;
187
+ branch.children.copyWithin(gap, branch.childOffset);
188
+ branch.children.length -= branch.childOffset - gap;
189
+ branch.keys.copyWithin(gap, branch.childOffset);
190
+ branch.keys.length -= branch.childOffset - gap;
191
+ branch.childOffset = gap;
192
+ for (let i = gap; i < branch.children.length; i += 1) {
193
+ branch.children[i].indexInParent = i;
194
+ }
195
+ }
196
+ };
197
+ var branchChildCount = (branch) => branch.children.length - branch.childOffset;
198
+ var branchInsertAt = (branch, logicalIndex, child, key) => {
199
+ const phys = branch.childOffset + logicalIndex;
200
+ const count = branch.children.length - branch.childOffset;
201
+ if (branch.childOffset > 0 && logicalIndex < count >>> 1) {
202
+ branch.children.copyWithin(branch.childOffset - 1, branch.childOffset, phys);
203
+ branch.keys.copyWithin(branch.childOffset - 1, branch.childOffset, phys);
204
+ branch.childOffset -= 1;
205
+ branch.children[phys - 1] = child;
206
+ branch.keys[phys - 1] = key;
207
+ for (let i = branch.childOffset; i < phys; i += 1) {
208
+ branch.children[i].indexInParent = i;
209
+ }
210
+ child.indexInParent = phys - 1;
211
+ } else {
212
+ branch.children.splice(phys, 0, child);
213
+ branch.keys.splice(phys, 0, key);
214
+ for (let i = phys; i < branch.children.length; i += 1) {
215
+ branch.children[i].indexInParent = i;
216
+ }
217
+ }
218
+ };
219
+ var branchRemoveAt = (branch, physIndex) => {
220
+ const logicalIndex = physIndex - branch.childOffset;
221
+ const count = branch.children.length - branch.childOffset;
222
+ if (logicalIndex < count - 1 - logicalIndex) {
223
+ branch.children.copyWithin(branch.childOffset + 1, branch.childOffset, physIndex);
224
+ branch.keys.copyWithin(branch.childOffset + 1, branch.childOffset, physIndex);
225
+ branch.childOffset += 1;
226
+ for (let i = branch.childOffset; i <= physIndex; i += 1) {
227
+ branch.children[i].indexInParent = i;
228
+ }
229
+ if (branch.childOffset >= branch.children.length >>> 1) {
230
+ branchCompact(branch);
231
+ }
232
+ } else {
233
+ branch.children.copyWithin(physIndex, physIndex + 1);
234
+ branch.keys.copyWithin(physIndex, physIndex + 1);
235
+ branch.children.length -= 1;
236
+ branch.keys.length -= 1;
237
+ for (let i = physIndex; i < branch.children.length; i += 1) {
238
+ branch.children[i].indexInParent = i;
239
+ }
240
+ }
241
+ };
242
+
243
+ // src/btree/navigation.ts
244
+ var selectBranchChild = (compare, branch, userKey, sequence) => {
245
+ const off = branch.childOffset;
246
+ if (off >= branch.children.length) {
247
+ throw new BTreeInvariantError("branch has no children");
248
+ }
249
+ let selectedIndex = off;
250
+ let lower = off;
251
+ let upper = branch.keys.length - 1;
252
+ while (lower <= upper) {
253
+ const mid = lower + upper >>> 1;
254
+ const k = branch.keys[mid];
255
+ const cmp = compare(k.key, userKey);
256
+ if ((cmp !== 0 ? cmp : k.sequence - sequence) <= 0) {
257
+ selectedIndex = mid;
258
+ lower = mid + 1;
259
+ } else {
260
+ upper = mid - 1;
261
+ }
262
+ }
263
+ return branch.children[selectedIndex];
264
+ };
265
+ var findLeafForKey = (state, userKey, sequence) => {
266
+ const compare = state.compareKeys;
267
+ let cursor = state.root;
268
+ while (cursor.kind !== NODE_LEAF) {
269
+ cursor = selectBranchChild(compare, cursor, userKey, sequence);
270
+ }
271
+ return cursor;
272
+ };
273
+ var lowerBoundInLeaf = (state, leaf, userKey, sequence) => {
274
+ const compare = state.compareKeys;
275
+ let lower = leaf.entryOffset;
276
+ let upper = leaf.entries.length;
277
+ while (lower < upper) {
278
+ const mid = lower + upper >>> 1;
279
+ const e = leaf.entries[mid];
280
+ const cmp = compare(e.key, userKey);
281
+ if ((cmp !== 0 ? cmp : e.entryId - sequence) < 0) {
282
+ lower = mid + 1;
283
+ } else {
284
+ upper = mid;
285
+ }
286
+ }
287
+ return lower - leaf.entryOffset;
288
+ };
289
+ var upperBoundInLeaf = (state, leaf, userKey, sequence) => {
290
+ const compare = state.compareKeys;
291
+ let lower = leaf.entryOffset;
292
+ let upper = leaf.entries.length;
293
+ while (lower < upper) {
294
+ const mid = lower + upper >>> 1;
295
+ const e = leaf.entries[mid];
296
+ const cmp = compare(e.key, userKey);
297
+ if ((cmp !== 0 ? cmp : e.entryId - sequence) <= 0) {
298
+ lower = mid + 1;
299
+ } else {
300
+ upper = mid;
301
+ }
302
+ }
303
+ return lower - leaf.entryOffset;
304
+ };
305
+ var findLeafFromHint = (state, hint, userKey, sequence) => {
306
+ const compare = state.compareKeys;
307
+ let leaf = hint;
308
+ let budget = 32 - Math.clz32(state.entryCount + 1);
309
+ while (budget > 0 && leaf.next !== null && leafEntryCount(leaf.next) > 0) {
310
+ const first = leafEntryAt(leaf.next, 0);
311
+ const cmp = compare(first.key, userKey);
312
+ if (cmp > 0 || cmp === 0 && first.entryId > sequence) break;
313
+ leaf = leaf.next;
314
+ budget -= 1;
315
+ }
316
+ if (budget === 0 && leaf.next !== null && leafEntryCount(leaf.next) > 0) {
317
+ const first = leafEntryAt(leaf.next, 0);
318
+ const cmp = compare(first.key, userKey);
319
+ if (cmp < 0 || cmp === 0 && first.entryId <= sequence) {
320
+ return findLeafForKey(state, userKey, sequence);
321
+ }
322
+ }
323
+ return leaf;
324
+ };
325
+ var findFirstMatchingUserKey = (state, key) => {
326
+ if (state.entryCount === 0) return null;
327
+ let leaf = findLeafForKey(state, key, 0);
328
+ let idx = lowerBoundInLeaf(state, leaf, key, 0);
329
+ if (idx >= leafEntryCount(leaf)) {
330
+ if (leaf.next === null) return null;
331
+ leaf = leaf.next;
332
+ idx = lowerBoundInLeaf(state, leaf, key, 0);
333
+ if (idx >= leafEntryCount(leaf)) return null;
334
+ }
335
+ if (state.compareKeys(leafEntryAt(leaf, idx).key, key) !== 0) return null;
336
+ const cursor = state._cursor;
337
+ cursor.leaf = leaf;
338
+ cursor.index = idx;
339
+ return cursor;
340
+ };
341
+ var findLastMatchingUserKey = (state, key) => {
342
+ if (state.entryCount === 0) return null;
343
+ let leaf = findLeafForKey(state, key, Number.MAX_SAFE_INTEGER);
344
+ let idx = upperBoundInLeaf(state, leaf, key, Number.MAX_SAFE_INTEGER);
345
+ if (idx === 0) {
346
+ if (leaf.prev === null) return null;
347
+ leaf = leaf.prev;
348
+ idx = leafEntryCount(leaf);
349
+ if (idx === 0) return null;
350
+ }
351
+ idx -= 1;
352
+ if (state.compareKeys(leafEntryAt(leaf, idx).key, key) !== 0) return null;
353
+ const cursor = state._cursor;
354
+ cursor.leaf = leaf;
355
+ cursor.index = idx;
356
+ return cursor;
357
+ };
358
+ var hasKeyEntry = (state, key) => {
359
+ return findFirstMatchingUserKey(state, key) !== null;
360
+ };
361
+ var findNextHigherKey = (state, key) => {
362
+ if (state.entryCount === 0) return null;
363
+ const compare = state.compareKeys;
364
+ let leaf = findLeafForKey(state, key, Number.MAX_SAFE_INTEGER);
365
+ let idx = upperBoundInLeaf(state, leaf, key, Number.MAX_SAFE_INTEGER);
366
+ while (leaf !== null) {
367
+ if (idx < leafEntryCount(leaf)) {
368
+ const e = leafEntryAt(leaf, idx);
369
+ if (compare(e.key, key) > 0) return e.key;
370
+ idx += 1;
371
+ } else {
372
+ leaf = leaf.next;
373
+ idx = 0;
374
+ }
375
+ }
376
+ return null;
377
+ };
378
+ var findNextLowerKey = (state, key) => {
379
+ if (state.entryCount === 0) return null;
380
+ const compare = state.compareKeys;
381
+ const leaf = findLeafForKey(state, key, 0);
382
+ const idx = lowerBoundInLeaf(state, leaf, key, 0);
383
+ let scanLeaf = leaf;
384
+ let scanIdx = idx - 1;
385
+ while (scanLeaf !== null) {
386
+ while (scanIdx >= 0) {
387
+ const e = leafEntryAt(scanLeaf, scanIdx);
388
+ if (compare(e.key, key) < 0) return e.key;
389
+ scanIdx -= 1;
390
+ }
391
+ scanLeaf = scanLeaf.prev;
392
+ if (scanLeaf !== null) {
393
+ scanIdx = leafEntryCount(scanLeaf) - 1;
394
+ }
395
+ }
396
+ return null;
397
+ };
398
+ var findPairOrNextLower = (state, key) => {
399
+ if (state.entryCount === 0) return null;
400
+ const compare = state.compareKeys;
401
+ const leaf = findLeafForKey(state, key, 0);
402
+ const idx = lowerBoundInLeaf(state, leaf, key, 0);
403
+ const cursor = state._cursor;
404
+ if (idx < leafEntryCount(leaf)) {
405
+ if (compare(leafEntryAt(leaf, idx).key, key) === 0) {
406
+ cursor.leaf = leaf;
407
+ cursor.index = idx;
408
+ return cursor;
409
+ }
410
+ } else if (leaf.next !== null) {
411
+ const nextIdx = lowerBoundInLeaf(state, leaf.next, key, 0);
412
+ if (nextIdx < leafEntryCount(leaf.next) && compare(leafEntryAt(leaf.next, nextIdx).key, key) === 0) {
413
+ cursor.leaf = leaf.next;
414
+ cursor.index = nextIdx;
415
+ return cursor;
416
+ }
417
+ }
418
+ if (idx > 0) {
419
+ cursor.leaf = leaf;
420
+ cursor.index = idx - 1;
421
+ return cursor;
422
+ }
423
+ if (leaf.prev !== null) {
424
+ const prevCount = leafEntryCount(leaf.prev);
425
+ if (prevCount > 0) {
426
+ cursor.leaf = leaf.prev;
427
+ cursor.index = prevCount - 1;
428
+ return cursor;
429
+ }
430
+ }
431
+ return null;
432
+ };
433
+
434
+ // src/btree/rebalance.ts
435
+ var updateMinKeyInAncestors = (node) => {
436
+ let current = node;
437
+ while (current.parent !== null) {
438
+ const idx = current.indexInParent;
439
+ if (!writeMinKeyTo(current, current.parent.keys[idx])) return;
440
+ if (idx !== current.parent.childOffset) return;
441
+ current = current.parent;
442
+ }
443
+ };
444
+ var requireParent = (node) => {
445
+ if (node.parent === null) {
446
+ throw new BTreeInvariantError("no parent during rebalance");
447
+ }
448
+ return node.parent;
449
+ };
450
+ var requireLeafNode = (node) => {
451
+ if (!isLeafNode(node)) throw new BTreeInvariantError("expected leaf, got branch");
452
+ return node;
453
+ };
454
+ var requireBranchNode = (node) => {
455
+ if (isLeafNode(node)) throw new BTreeInvariantError("expected branch, got leaf");
456
+ return node;
457
+ };
458
+ var removeChildFromBranch = (branch, childIndex) => {
459
+ if (childIndex < branch.childOffset || childIndex >= branch.children.length) {
460
+ throw new BTreeInvariantError("child index out of range");
461
+ }
462
+ branchRemoveAt(branch, childIndex);
463
+ };
464
+ var detachLeafFromChain = (state, leaf) => {
465
+ if (leaf.prev !== null) {
466
+ leaf.prev.next = leaf.next;
467
+ } else if (leaf.next !== null) {
468
+ state.leftmostLeaf = leaf.next;
469
+ }
470
+ if (leaf.next !== null) {
471
+ leaf.next.prev = leaf.prev;
472
+ } else if (leaf.prev !== null) {
473
+ state.rightmostLeaf = leaf.prev;
474
+ }
475
+ leaf.prev = null;
476
+ leaf.next = null;
477
+ };
478
+ var borrowFromLeftBranch = (branch, leftSibling, branchIndex) => {
479
+ const borrowedChild = leftSibling.children.pop();
480
+ if (borrowedChild === void 0) throw new BTreeInvariantError("left branch borrow failed");
481
+ leftSibling.keys.pop();
482
+ borrowedChild.parent = branch;
483
+ const borrowedMinKey = { key: void 0, sequence: 0 };
484
+ if (!writeMinKeyTo(borrowedChild, borrowedMinKey)) throw new BTreeInvariantError("borrowed child has no min key");
485
+ if (branch.childOffset > 0) {
486
+ branch.childOffset -= 1;
487
+ branch.children[branch.childOffset] = borrowedChild;
488
+ branch.keys[branch.childOffset] = borrowedMinKey;
489
+ borrowedChild.indexInParent = branch.childOffset;
490
+ } else {
491
+ branch.children.unshift(borrowedChild);
492
+ branch.keys.unshift(borrowedMinKey);
493
+ for (let i = 0; i < branch.children.length; i += 1) branch.children[i].indexInParent = i;
494
+ }
495
+ const parent = requireParent(branch);
496
+ parent.keys[branchIndex] = { key: borrowedMinKey.key, sequence: borrowedMinKey.sequence };
497
+ updateMinKeyInAncestors(branch);
498
+ };
499
+ var borrowFromRightBranch = (branch, rightSibling, branchIndex) => {
500
+ const shiftIdx = rightSibling.childOffset;
501
+ if (shiftIdx >= rightSibling.children.length) throw new BTreeInvariantError("right branch borrow failed");
502
+ const borrowedChild = rightSibling.children[shiftIdx];
503
+ rightSibling.childOffset += 1;
504
+ if (rightSibling.childOffset >= rightSibling.children.length >>> 1) {
505
+ branchCompact(rightSibling);
506
+ }
507
+ branch.children.push(borrowedChild);
508
+ borrowedChild.parent = branch;
509
+ const borrowedMinKey = { key: void 0, sequence: 0 };
510
+ if (!writeMinKeyTo(borrowedChild, borrowedMinKey)) throw new BTreeInvariantError("borrowed child has no min key");
511
+ branch.keys.push(borrowedMinKey);
512
+ borrowedChild.indexInParent = branch.children.length - 1;
513
+ const parent = requireParent(branch);
514
+ writeMinKeyTo(rightSibling, parent.keys[branchIndex + 1]);
515
+ };
516
+ var mergeBranchIntoLeft = (state, branch, leftSibling, branchIndex) => {
517
+ for (let i = branch.childOffset; i < branch.children.length; i += 1) {
518
+ const child = branch.children[i];
519
+ child.parent = leftSibling;
520
+ child.indexInParent = leftSibling.children.length;
521
+ leftSibling.children.push(child);
522
+ leftSibling.keys.push(branch.keys[i]);
523
+ }
524
+ const parent = requireParent(branch);
525
+ removeChildFromBranch(parent, branchIndex);
526
+ rebalanceAfterBranchRemoval(state, parent);
527
+ };
528
+ var mergeBranchIntoRight = (state, branch, rightSibling, branchIndex) => {
529
+ for (let i = rightSibling.childOffset; i < rightSibling.children.length; i += 1) {
530
+ const child = rightSibling.children[i];
531
+ child.parent = branch;
532
+ child.indexInParent = branch.children.length;
533
+ branch.children.push(child);
534
+ branch.keys.push(rightSibling.keys[i]);
535
+ }
536
+ const parent = requireParent(branch);
537
+ removeChildFromBranch(parent, branchIndex + 1);
538
+ rebalanceAfterBranchRemoval(state, parent);
539
+ };
540
+ var findBranchSiblings = (parent, branchIndex) => {
541
+ const left = branchIndex > parent.childOffset ? requireBranchNode(parent.children[branchIndex - 1]) : null;
542
+ const right = branchIndex + 1 < parent.children.length ? requireBranchNode(parent.children[branchIndex + 1]) : null;
543
+ return { left, right };
544
+ };
545
+ var rebalanceAfterBranchRemoval = (state, branch) => {
546
+ const liveCount = branchChildCount(branch);
547
+ if (branch === state.root) {
548
+ if (liveCount === 1) {
549
+ const onlyChild = branch.children[branch.childOffset];
550
+ onlyChild.parent = null;
551
+ state.root = onlyChild;
552
+ if (isLeafNode(onlyChild)) {
553
+ state.leftmostLeaf = onlyChild;
554
+ state.rightmostLeaf = onlyChild;
555
+ }
556
+ }
557
+ return;
558
+ }
559
+ if (liveCount >= state.minBranchChildren) return;
560
+ const parent = branch.parent;
561
+ if (parent === null) throw new BTreeInvariantError("branch has no parent");
562
+ const branchIndex = branch.indexInParent;
563
+ const { left: leftSibling, right: rightSibling } = findBranchSiblings(parent, branchIndex);
564
+ if (rightSibling !== null && branchChildCount(rightSibling) > state.minBranchChildren) {
565
+ borrowFromRightBranch(branch, rightSibling, branchIndex);
566
+ return;
567
+ }
568
+ if (leftSibling !== null && branchChildCount(leftSibling) > state.minBranchChildren) {
569
+ borrowFromLeftBranch(branch, leftSibling, branchIndex);
570
+ return;
571
+ }
572
+ if (leftSibling !== null) {
573
+ mergeBranchIntoLeft(state, branch, leftSibling, branchIndex);
574
+ return;
575
+ }
576
+ if (rightSibling !== null) {
577
+ mergeBranchIntoRight(state, branch, rightSibling, branchIndex);
578
+ return;
579
+ }
580
+ throw new BTreeInvariantError("no branch siblings to rebalance");
581
+ };
582
+ var mergeLeafEntries = (target, source) => {
583
+ if (target.entryOffset > 0) {
584
+ target.entries.copyWithin(0, target.entryOffset);
585
+ target.entries.length = target.entries.length - target.entryOffset;
586
+ target.entryOffset = 0;
587
+ }
588
+ const src = source.entries;
589
+ for (let i = source.entryOffset; i < src.length; i += 1) target.entries.push(src[i]);
590
+ };
591
+ var rebalanceAfterLeafRemoval = (state, leaf) => {
592
+ if (leaf === state.root) {
593
+ if (state.entryCount === 0) {
594
+ state.leftmostLeaf = leaf;
595
+ state.rightmostLeaf = leaf;
596
+ }
597
+ return;
598
+ }
599
+ if (leafEntryCount(leaf) >= state.minLeafEntries) return;
600
+ const parent = leaf.parent;
601
+ if (parent === null) throw new BTreeInvariantError("Leaf node has no parent during rebalance.");
602
+ const leafIndex = leaf.indexInParent;
603
+ const leftSibling = leafIndex > parent.childOffset ? requireLeafNode(parent.children[leafIndex - 1]) : null;
604
+ const rightSibling = leafIndex + 1 < parent.children.length ? requireLeafNode(parent.children[leafIndex + 1]) : null;
605
+ if (rightSibling !== null && leafEntryCount(rightSibling) > state.minLeafEntries) {
606
+ const borrowed = leafShiftEntry(rightSibling);
607
+ if (borrowed === void 0) throw new BTreeInvariantError("right leaf borrow failed");
608
+ leaf.entries.push(borrowed);
609
+ writeMinKeyTo(rightSibling, parent.keys[leafIndex + 1]);
610
+ return;
611
+ }
612
+ if (leftSibling !== null && leafEntryCount(leftSibling) > state.minLeafEntries) {
613
+ const borrowed = leftSibling.entries.pop();
614
+ if (borrowed === void 0) throw new BTreeInvariantError("left leaf borrow failed");
615
+ leafUnshiftEntry(leaf, borrowed);
616
+ parent.keys[leafIndex] = { key: borrowed.key, sequence: borrowed.entryId };
617
+ updateMinKeyInAncestors(leaf);
618
+ return;
619
+ }
620
+ if (leftSibling !== null) {
621
+ mergeLeafEntries(leftSibling, leaf);
622
+ detachLeafFromChain(state, leaf);
623
+ removeChildFromBranch(parent, leafIndex);
624
+ rebalanceAfterBranchRemoval(state, parent);
625
+ return;
626
+ }
627
+ if (rightSibling !== null) {
628
+ mergeLeafEntries(leaf, rightSibling);
629
+ detachLeafFromChain(state, rightSibling);
630
+ removeChildFromBranch(parent, leafIndex + 1);
631
+ rebalanceAfterBranchRemoval(state, parent);
632
+ return;
633
+ }
634
+ throw new BTreeInvariantError("no leaf siblings to rebalance");
635
+ };
636
+
637
+ // src/btree/deleteRange.ts
638
+ var navigateToStart = (state, startKey, lowerExclusive) => {
639
+ const startSeq = lowerExclusive ? Number.MAX_SAFE_INTEGER : 0;
640
+ const leaf = findLeafForKey(state, startKey, startSeq);
641
+ const idx = lowerExclusive ? upperBoundInLeaf(state, leaf, startKey, Number.MAX_SAFE_INTEGER) : lowerBoundInLeaf(state, leaf, startKey, 0);
642
+ if (idx >= leafEntryCount(leaf)) {
643
+ if (leaf.next === null) return null;
644
+ return { leaf: leaf.next, idx: 0 };
645
+ }
646
+ return { leaf, idx };
647
+ };
648
+ var findRemoveEnd = (state, leaf, idx, endKey, upperExclusive) => {
649
+ const count = leafEntryCount(leaf);
650
+ let removeEnd = idx;
651
+ while (removeEnd < count) {
652
+ const e = leafEntryAt(leaf, removeEnd);
653
+ const cmpEnd = state.compareKeys(e.key, endKey);
654
+ if (upperExclusive ? cmpEnd >= 0 : cmpEnd > 0) break;
655
+ removeEnd += 1;
656
+ }
657
+ return removeEnd;
658
+ };
659
+ var computeTreeHeight = (state) => {
660
+ let h = 0;
661
+ let n = state.root;
662
+ while (!isLeafNode(n)) {
663
+ n = n.children[n.childOffset];
664
+ h += 1;
665
+ }
666
+ return h;
667
+ };
668
+ var spliceLeafAndRebalance = (state, leaf, idx, removeCount, maxRebalanceDepth) => {
669
+ if (state.entryKeys !== null) {
670
+ for (let i = idx; i < idx + removeCount; i += 1) {
671
+ state.entryKeys.delete(leafEntryAt(leaf, i).entryId);
672
+ }
673
+ }
674
+ const phys = leaf.entryOffset + idx;
675
+ leaf.entries.copyWithin(phys, phys + removeCount);
676
+ leaf.entries.length -= removeCount;
677
+ state.entryCount -= removeCount;
678
+ const leafEmptied = leafEntryCount(leaf) === 0;
679
+ if (idx === 0 && !leafEmptied && leaf.parent !== null) {
680
+ updateMinKeyInAncestors(leaf);
681
+ }
682
+ const countAfterSplice = leafEntryCount(leaf);
683
+ let maxIter = maxRebalanceDepth;
684
+ while (maxIter > 0 && leaf !== state.root && leafEntryCount(leaf) < state.minLeafEntries) {
685
+ rebalanceAfterLeafRemoval(state, leaf);
686
+ if (leaf.parent !== null && leaf.parent.children[leaf.indexInParent] !== leaf) break;
687
+ maxIter -= 1;
688
+ }
689
+ if (leafEmptied && leafEntryCount(leaf) > 0 && leaf.parent !== null && leaf.parent.children[leaf.indexInParent] === leaf) {
690
+ updateMinKeyInAncestors(leaf);
691
+ }
692
+ return countAfterSplice;
693
+ };
694
+ var isLeafStillValid = (state, leaf) => leaf.parent === null ? leaf === state.root : leaf.parent.children[leaf.indexInParent] === leaf;
695
+ var deleteRangeEntries = (state, startKey, endKey, options) => {
696
+ if (state.entryCount === 0) return 0;
697
+ const boundCompared = state.compareKeys(startKey, endKey);
698
+ if (boundCompared > 0) return 0;
699
+ const lowerExclusive = options?.lowerBound === "exclusive";
700
+ const upperExclusive = options?.upperBound === "exclusive";
701
+ if (lowerExclusive && upperExclusive && boundCompared === 0) return 0;
702
+ const treeHeight = computeTreeHeight(state);
703
+ let deleted = 0;
704
+ let needsNavigate = true;
705
+ let leaf = null;
706
+ let idx = 0;
707
+ while (state.entryCount > 0) {
708
+ if (needsNavigate) {
709
+ const cursor = navigateToStart(state, startKey, lowerExclusive);
710
+ if (cursor === null) break;
711
+ leaf = cursor.leaf;
712
+ idx = cursor.idx;
713
+ needsNavigate = false;
714
+ }
715
+ if (idx >= leafEntryCount(leaf)) break;
716
+ const count = leafEntryCount(leaf);
717
+ const removeEnd = findRemoveEnd(state, leaf, idx, endKey, upperExclusive);
718
+ const removeCount = removeEnd - idx;
719
+ if (removeCount === 0) break;
720
+ const countAfterSplice = spliceLeafAndRebalance(state, leaf, idx, removeCount, treeHeight);
721
+ deleted += removeCount;
722
+ if (removeEnd < count) break;
723
+ if (!isLeafStillValid(state, leaf)) {
724
+ needsNavigate = true;
725
+ continue;
726
+ }
727
+ if (leafEntryCount(leaf) > countAfterSplice) {
728
+ needsNavigate = true;
729
+ continue;
730
+ }
731
+ if (leaf.next === null) break;
732
+ leaf = leaf.next;
733
+ idx = 0;
734
+ }
735
+ return deleted;
736
+ };
737
+
738
+ // src/btree/autoScale.ts
739
+ var AUTO_SCALE_TIERS = [
740
+ { threshold: 0, maxLeaf: 32, maxBranch: 32 },
741
+ { threshold: 1e3, maxLeaf: 64, maxBranch: 64 },
742
+ { threshold: 1e4, maxLeaf: 128, maxBranch: 128 },
743
+ { threshold: 1e5, maxLeaf: 256, maxBranch: 128 },
744
+ { threshold: 1e6, maxLeaf: 512, maxBranch: 256 }
745
+ ];
746
+ var computeAutoScaleTier = (entryCount) => {
747
+ let tier = AUTO_SCALE_TIERS[0];
748
+ for (let i = 1; i < AUTO_SCALE_TIERS.length; i += 1) {
749
+ if (entryCount >= AUTO_SCALE_TIERS[i].threshold) {
750
+ tier = AUTO_SCALE_TIERS[i];
751
+ } else {
752
+ break;
753
+ }
754
+ }
755
+ return tier;
756
+ };
757
+ var computeNextAutoScaleThreshold = (entryCount) => {
758
+ for (let i = 1; i < AUTO_SCALE_TIERS.length; i += 1) {
759
+ if (entryCount < AUTO_SCALE_TIERS[i].threshold) {
760
+ return AUTO_SCALE_TIERS[i].threshold;
761
+ }
762
+ }
763
+ return Number.MAX_SAFE_INTEGER;
764
+ };
765
+ var createInitialState = (config) => {
766
+ if (typeof config.compareKeys !== "function") {
767
+ throw new BTreeValidationError("compareKeys must be a function.");
768
+ }
769
+ const autoScale = config.autoScale === true;
770
+ if (autoScale && (config.maxLeafEntries !== void 0 || config.maxBranchChildren !== void 0)) {
771
+ throw new BTreeValidationError("autoScale conflicts with explicit capacity.");
772
+ }
773
+ let maxLeafEntries;
774
+ let maxBranchChildren;
775
+ if (autoScale) {
776
+ const tier = computeAutoScaleTier(0);
777
+ maxLeafEntries = tier.maxLeaf;
778
+ maxBranchChildren = tier.maxBranch;
779
+ } else {
780
+ maxLeafEntries = normalizeNodeCapacity(config.maxLeafEntries, "maxLeafEntries", DEFAULT_MAX_LEAF_ENTRIES);
781
+ maxBranchChildren = normalizeNodeCapacity(config.maxBranchChildren, "maxBranchChildren", DEFAULT_MAX_BRANCH_CHILDREN);
782
+ }
783
+ const duplicateKeys = normalizeDuplicateKeyPolicy(config.duplicateKeys);
784
+ const emptyLeaf = createLeafNode([], null);
785
+ return {
786
+ compareKeys: config.compareKeys,
787
+ maxLeafEntries,
788
+ maxBranchChildren,
789
+ duplicateKeys,
790
+ minLeafEntries: Math.ceil(maxLeafEntries / 2),
791
+ minBranchChildren: Math.ceil(maxBranchChildren / 2),
792
+ root: emptyLeaf,
793
+ leftmostLeaf: emptyLeaf,
794
+ rightmostLeaf: emptyLeaf,
795
+ entryCount: 0,
796
+ nextSequence: 0,
797
+ entryKeys: config.enableEntryIdLookup === true ? /* @__PURE__ */ new Map() : null,
798
+ autoScale,
799
+ _nextAutoScaleThreshold: autoScale ? computeNextAutoScaleThreshold(0) : Number.MAX_SAFE_INTEGER,
800
+ _cursor: { leaf: emptyLeaf, index: 0 }
801
+ };
802
+ };
803
+ var maybeAutoScale = (state) => {
804
+ if (state.entryCount < state._nextAutoScaleThreshold) return;
805
+ const { maxLeaf, maxBranch } = computeAutoScaleTier(state.entryCount);
806
+ if (maxLeaf > state.maxLeafEntries) {
807
+ state.maxLeafEntries = maxLeaf;
808
+ state.minLeafEntries = Math.ceil(maxLeaf / 2);
809
+ }
810
+ if (maxBranch > state.maxBranchChildren) {
811
+ state.maxBranchChildren = maxBranch;
812
+ state.minBranchChildren = Math.ceil(maxBranch / 2);
813
+ }
814
+ state._nextAutoScaleThreshold = computeNextAutoScaleThreshold(state.entryCount);
815
+ };
816
+ var applyAutoScaleCapacitySnapshot = (state, maxLeafEntries, maxBranchChildren) => {
817
+ if (!state.autoScale) {
818
+ return;
819
+ }
820
+ const baseTier = computeAutoScaleTier(0);
821
+ const normalizedLeaf = normalizeNodeCapacity(
822
+ maxLeafEntries,
823
+ "maxLeafEntries",
824
+ DEFAULT_MAX_LEAF_ENTRIES
825
+ );
826
+ const normalizedBranch = normalizeNodeCapacity(
827
+ maxBranchChildren,
828
+ "maxBranchChildren",
829
+ DEFAULT_MAX_BRANCH_CHILDREN
830
+ );
831
+ if (normalizedLeaf < baseTier.maxLeaf || normalizedBranch < baseTier.maxBranch) {
832
+ throw new BTreeValidationError(
833
+ "autoScale capacity snapshot must be >= tier-0 capacities."
834
+ );
835
+ }
836
+ state.maxLeafEntries = normalizedLeaf;
837
+ state.maxBranchChildren = normalizedBranch;
838
+ state.minLeafEntries = Math.ceil(normalizedLeaf / 2);
839
+ state.minBranchChildren = Math.ceil(normalizedBranch / 2);
840
+ };
841
+
842
+ // src/btree/bulkLoad.ts
843
+ var computeChunkBoundaries = (total, max, min) => {
844
+ const boundaries = [];
845
+ let offset = 0;
846
+ while (offset < total) {
847
+ const remaining = total - offset;
848
+ if (remaining > max && remaining - max < min) {
849
+ const half = Math.ceil(remaining / 2);
850
+ boundaries.push(offset + half);
851
+ boundaries.push(total);
852
+ break;
853
+ }
854
+ const end = offset + max < total ? offset + max : total;
855
+ boundaries.push(end);
856
+ offset = end;
857
+ }
858
+ return boundaries;
859
+ };
860
+ var buildLeaves = (state, entries, ids, baseSequence) => {
861
+ const boundaries = computeChunkBoundaries(entries.length, state.maxLeafEntries, state.minLeafEntries);
862
+ const leaves = new Array(boundaries.length);
863
+ let chunkStart = 0;
864
+ for (let c = 0; c < boundaries.length; c += 1) {
865
+ const chunkEnd = boundaries[c];
866
+ const chunk = new Array(chunkEnd - chunkStart);
867
+ for (let i = chunkStart; i < chunkEnd; i += 1) {
868
+ const seq = baseSequence + i;
869
+ chunk[i - chunkStart] = { key: entries[i].key, entryId: seq, value: entries[i].value };
870
+ ids[i] = seq;
871
+ if (state.entryKeys !== null) {
872
+ state.entryKeys.set(seq, entries[i].key);
873
+ }
874
+ }
875
+ leaves[c] = createLeafNode(chunk, null);
876
+ chunkStart = chunkEnd;
877
+ }
878
+ return leaves;
879
+ };
880
+ var bulkLoadEntries = (state, entries) => {
881
+ if (state.entryCount !== 0) {
882
+ throw new BTreeInvariantError("bulk load requires empty tree");
883
+ }
884
+ const baseSequence = state.nextSequence;
885
+ if (baseSequence + entries.length > Number.MAX_SAFE_INTEGER) {
886
+ throw new BTreeValidationError("Sequence overflow.");
887
+ }
888
+ const ids = new Array(entries.length);
889
+ const leaves = buildLeaves(state, entries, ids, baseSequence);
890
+ state.nextSequence = baseSequence + entries.length;
891
+ state.entryCount = entries.length;
892
+ for (let i = 0; i < leaves.length; i += 1) {
893
+ if (i > 0) leaves[i].prev = leaves[i - 1];
894
+ if (i < leaves.length - 1) leaves[i].next = leaves[i + 1];
895
+ }
896
+ state.leftmostLeaf = leaves[0];
897
+ state.rightmostLeaf = leaves[leaves.length - 1];
898
+ if (leaves.length === 1) {
899
+ state.root = leaves[0];
900
+ } else {
901
+ let currentLevel = leaves;
902
+ while (currentLevel.length > 1) {
903
+ const bounds = computeChunkBoundaries(currentLevel.length, state.maxBranchChildren, state.minBranchChildren);
904
+ const nextLevel = new Array(bounds.length);
905
+ let start = 0;
906
+ for (let b = 0; b < bounds.length; b += 1) {
907
+ nextLevel[b] = createBranchNode(currentLevel.slice(start, bounds[b]), null);
908
+ start = bounds[b];
909
+ }
910
+ currentLevel = nextLevel;
911
+ }
912
+ state.root = currentLevel[0];
913
+ }
914
+ maybeAutoScale(state);
915
+ return ids;
916
+ };
917
+
918
+ // src/btree/mutations.ts
919
+ var insertChildAfter = (state, parent, existingChild, childToInsert) => {
920
+ const newChildMinKey = { key: void 0, sequence: 0 };
921
+ if (!writeMinKeyTo(childToInsert, newChildMinKey)) {
922
+ throw new BTreeInvariantError("inserted child has no min key");
923
+ }
924
+ childToInsert.parent = parent;
925
+ const logicalIndex = existingChild.indexInParent - parent.childOffset + 1;
926
+ branchInsertAt(parent, logicalIndex, childToInsert, newChildMinKey);
927
+ if (branchChildCount(parent) > state.maxBranchChildren) {
928
+ splitBranch(state, parent);
929
+ }
930
+ };
931
+ var splitLeaf = (state, leaf) => {
932
+ leafCompact(leaf);
933
+ const splitAt = Math.ceil(leaf.entries.length / 2);
934
+ const sibling = {
935
+ kind: NODE_LEAF,
936
+ entries: leaf.entries.splice(splitAt),
937
+ entryOffset: 0,
938
+ parent: leaf.parent,
939
+ indexInParent: 0,
940
+ prev: leaf,
941
+ next: leaf.next
942
+ };
943
+ if (leaf.next !== null) {
944
+ leaf.next.prev = sibling;
945
+ } else {
946
+ state.rightmostLeaf = sibling;
947
+ }
948
+ leaf.next = sibling;
949
+ if (leaf.parent === null) {
950
+ state.root = createBranchNode([leaf, sibling], null);
951
+ return;
952
+ }
953
+ insertChildAfter(state, leaf.parent, leaf, sibling);
954
+ };
955
+ var splitBranch = (state, branch) => {
956
+ branchCompact(branch);
957
+ const splitAt = Math.ceil(branch.children.length / 2);
958
+ const sibling = createBranchNode(branch.children.splice(splitAt), branch.parent);
959
+ branch.keys.splice(splitAt);
960
+ if (branch.parent === null) {
961
+ state.root = createBranchNode([branch, sibling], null);
962
+ return;
963
+ }
964
+ insertChildAfter(state, branch.parent, branch, sibling);
965
+ };
966
+ var putEntryIntoLeaf = (state, targetLeaf, key, value) => {
967
+ const sequence = state.nextSequence;
968
+ const insertAt = upperBoundInLeaf(state, targetLeaf, key, sequence);
969
+ if (state.duplicateKeys !== "allow") {
970
+ let existingEntry = null;
971
+ if (insertAt > 0) {
972
+ const candidate = leafEntryAt(targetLeaf, insertAt - 1);
973
+ if (state.compareKeys(candidate.key, key) === 0) {
974
+ existingEntry = candidate;
975
+ }
976
+ } else if (targetLeaf.prev !== null && leafEntryCount(targetLeaf.prev) > 0) {
977
+ const prevLeaf = targetLeaf.prev;
978
+ const candidate = leafEntryAt(prevLeaf, leafEntryCount(prevLeaf) - 1);
979
+ if (state.compareKeys(candidate.key, key) === 0) {
980
+ existingEntry = candidate;
981
+ }
982
+ }
983
+ if (existingEntry !== null) {
984
+ if (state.duplicateKeys === "reject") {
985
+ throw new BTreeValidationError("Duplicate key rejected.");
986
+ }
987
+ existingEntry.value = value;
988
+ return existingEntry.entryId;
989
+ }
990
+ }
991
+ if (state.nextSequence >= Number.MAX_SAFE_INTEGER) {
992
+ throw new BTreeValidationError("Sequence overflow.");
993
+ }
994
+ state.nextSequence += 1;
995
+ leafInsertAt(targetLeaf, insertAt, { key, entryId: sequence, value });
996
+ state.entryCount += 1;
997
+ if (state.entryKeys !== null) {
998
+ state.entryKeys.set(sequence, key);
999
+ }
1000
+ if (insertAt === 0 && targetLeaf.parent !== null) updateMinKeyInAncestors(targetLeaf);
1001
+ if (leafEntryCount(targetLeaf) > state.maxLeafEntries) splitLeaf(state, targetLeaf);
1002
+ maybeAutoScale(state);
1003
+ return sequence;
1004
+ };
1005
+ var putEntry = (state, key, value) => {
1006
+ const targetLeaf = findLeafForKey(state, key, state.nextSequence);
1007
+ return putEntryIntoLeaf(state, targetLeaf, key, value);
1008
+ };
1009
+ var popFirstEntry = (state) => {
1010
+ if (state.entryCount === 0) return null;
1011
+ const firstEntry = leafShiftEntry(state.leftmostLeaf);
1012
+ if (firstEntry === void 0) throw new BTreeInvariantError("leftmost leaf empty but count > 0");
1013
+ state.entryCount -= 1;
1014
+ if (state.entryKeys !== null) {
1015
+ state.entryKeys.delete(firstEntry.entryId);
1016
+ }
1017
+ if (leafEntryCount(state.leftmostLeaf) > 0 && state.leftmostLeaf.parent !== null) {
1018
+ updateMinKeyInAncestors(state.leftmostLeaf);
1019
+ }
1020
+ if (state.leftmostLeaf !== state.root && leafEntryCount(state.leftmostLeaf) < state.minLeafEntries) {
1021
+ rebalanceAfterLeafRemoval(state, state.leftmostLeaf);
1022
+ }
1023
+ return firstEntry;
1024
+ };
1025
+ var popLastEntry = (state) => {
1026
+ if (state.entryCount === 0) return null;
1027
+ const lastEntry = leafPopEntry(state.rightmostLeaf);
1028
+ if (lastEntry === void 0) throw new BTreeInvariantError("rightmost leaf empty but count > 0");
1029
+ state.entryCount -= 1;
1030
+ if (state.entryKeys !== null) {
1031
+ state.entryKeys.delete(lastEntry.entryId);
1032
+ }
1033
+ if (state.rightmostLeaf !== state.root && leafEntryCount(state.rightmostLeaf) < state.minLeafEntries) {
1034
+ rebalanceAfterLeafRemoval(state, state.rightmostLeaf);
1035
+ }
1036
+ return lastEntry;
1037
+ };
1038
+ var removeFirstMatchingEntry = (state, key) => {
1039
+ const found = findFirstMatchingUserKey(state, key);
1040
+ if (found === null) return null;
1041
+ const targetLeaf = found.leaf;
1042
+ const removeAt = found.index;
1043
+ const targetEntry = leafEntryAt(targetLeaf, removeAt);
1044
+ leafRemoveAt(targetLeaf, removeAt);
1045
+ state.entryCount -= 1;
1046
+ if (state.entryKeys !== null) {
1047
+ state.entryKeys.delete(targetEntry.entryId);
1048
+ }
1049
+ if (removeAt === 0 && leafEntryCount(targetLeaf) > 0 && targetLeaf.parent !== null) updateMinKeyInAncestors(targetLeaf);
1050
+ if (targetLeaf !== state.root && leafEntryCount(targetLeaf) < state.minLeafEntries) {
1051
+ rebalanceAfterLeafRemoval(state, targetLeaf);
1052
+ }
1053
+ return targetEntry;
1054
+ };
1055
+ var findLeafEntryBySequence = (state, userKey, sequence) => {
1056
+ const targetLeaf = findLeafForKey(state, userKey, sequence);
1057
+ const index = lowerBoundInLeaf(state, targetLeaf, userKey, sequence);
1058
+ if (index >= leafEntryCount(targetLeaf)) return null;
1059
+ const entry = leafEntryAt(targetLeaf, index);
1060
+ if (entry.entryId !== sequence) return null;
1061
+ return { leaf: targetLeaf, index };
1062
+ };
1063
+ var removeEntryById = (state, entryId) => {
1064
+ const userKey = state.entryKeys.get(entryId);
1065
+ if (userKey === void 0) return null;
1066
+ const found = findLeafEntryBySequence(state, userKey, entryId);
1067
+ if (found === null) return null;
1068
+ const entry = leafEntryAt(found.leaf, found.index);
1069
+ leafRemoveAt(found.leaf, found.index);
1070
+ state.entryCount -= 1;
1071
+ state.entryKeys.delete(entryId);
1072
+ if (found.index === 0 && leafEntryCount(found.leaf) > 0 && found.leaf.parent !== null) {
1073
+ updateMinKeyInAncestors(found.leaf);
1074
+ }
1075
+ if (found.leaf !== state.root && leafEntryCount(found.leaf) < state.minLeafEntries) {
1076
+ rebalanceAfterLeafRemoval(state, found.leaf);
1077
+ }
1078
+ return entry;
1079
+ };
1080
+ var peekEntryById = (state, entryId) => {
1081
+ const userKey = state.entryKeys.get(entryId);
1082
+ if (userKey === void 0) return null;
1083
+ const found = findLeafEntryBySequence(state, userKey, entryId);
1084
+ if (found === null) return null;
1085
+ const entry = leafEntryAt(found.leaf, found.index);
1086
+ return entry;
1087
+ };
1088
+ var updateEntryById = (state, entryId, newValue) => {
1089
+ const userKey = state.entryKeys.get(entryId);
1090
+ if (userKey === void 0) return null;
1091
+ const found = findLeafEntryBySequence(state, userKey, entryId);
1092
+ if (found === null) return null;
1093
+ const entry = leafEntryAt(found.leaf, found.index);
1094
+ entry.value = newValue;
1095
+ return entry;
1096
+ };
1097
+ var putManyEntries = (state, entries) => {
1098
+ if (entries.length === 0) return [];
1099
+ const strictlyAscending = state.duplicateKeys !== "allow";
1100
+ for (let i = 1; i < entries.length; i += 1) {
1101
+ const cmp = state.compareKeys(entries[i - 1].key, entries[i].key);
1102
+ if (strictlyAscending ? cmp >= 0 : cmp > 0) {
1103
+ throw new BTreeValidationError(
1104
+ strictlyAscending ? "putMany: not sorted in strict ascending order." : "putMany: not sorted in non-descending order."
1105
+ );
1106
+ }
1107
+ }
1108
+ if (state.entryCount > 0) {
1109
+ const ids = new Array(entries.length);
1110
+ let hintLeaf = findLeafForKey(state, entries[0].key, state.nextSequence);
1111
+ for (let i = 0; i < entries.length; i += 1) {
1112
+ const entry = entries[i];
1113
+ const targetLeaf = findLeafFromHint(state, hintLeaf, entry.key, state.nextSequence);
1114
+ ids[i] = putEntryIntoLeaf(state, targetLeaf, entry.key, entry.value);
1115
+ hintLeaf = targetLeaf;
1116
+ }
1117
+ return ids;
1118
+ }
1119
+ return bulkLoadEntries(state, entries);
1120
+ };
1121
+
1122
+ // src/btree/rangeQuery.ts
1123
+ var initRangeCursor = (state, startKey, endKey, options) => {
1124
+ if (state.entryCount === 0) return null;
1125
+ const compare = state.compareKeys;
1126
+ const boundCompared = compare(startKey, endKey);
1127
+ if (boundCompared > 0) return null;
1128
+ const lowerExclusive = options?.lowerBound === "exclusive";
1129
+ const upperExclusive = options?.upperBound === "exclusive";
1130
+ if (lowerExclusive && upperExclusive && boundCompared === 0) return null;
1131
+ const startSeq = lowerExclusive ? Number.MAX_SAFE_INTEGER : 0;
1132
+ const leaf = findLeafForKey(state, startKey, startSeq);
1133
+ const index = lowerExclusive ? upperBoundInLeaf(state, leaf, startKey, Number.MAX_SAFE_INTEGER) : lowerBoundInLeaf(state, leaf, startKey, 0);
1134
+ return { leaf, index, compare, upperExclusive };
1135
+ };
1136
+ var countRangeEntries = (state, startKey, endKey, options) => {
1137
+ const cursor = initRangeCursor(state, startKey, endKey, options);
1138
+ if (cursor === null) return 0;
1139
+ let cursorLeaf = cursor.leaf;
1140
+ let cursorIndex = cursor.index;
1141
+ const { compare, upperExclusive } = cursor;
1142
+ let count = 0;
1143
+ while (cursorLeaf !== null) {
1144
+ const leafCount = leafEntryCount(cursorLeaf);
1145
+ if (cursorIndex >= leafCount) {
1146
+ cursorLeaf = cursorLeaf.next;
1147
+ cursorIndex = 0;
1148
+ continue;
1149
+ }
1150
+ const lastEntry = leafEntryAt(cursorLeaf, leafCount - 1);
1151
+ const cmpLast = compare(lastEntry.key, endKey);
1152
+ if (upperExclusive ? cmpLast < 0 : cmpLast <= 0) {
1153
+ count += leafCount - cursorIndex;
1154
+ cursorLeaf = cursorLeaf.next;
1155
+ cursorIndex = 0;
1156
+ continue;
1157
+ }
1158
+ const endSeq = upperExclusive ? 0 : Number.MAX_SAFE_INTEGER;
1159
+ const endBound = upperExclusive ? lowerBoundInLeaf(state, cursorLeaf, endKey, endSeq) : upperBoundInLeaf(state, cursorLeaf, endKey, endSeq);
1160
+ const limit = endBound < leafCount ? endBound : leafCount;
1161
+ count += limit - cursorIndex;
1162
+ return count;
1163
+ }
1164
+ return count;
1165
+ };
1166
+ var RANGE_PREALLOC_THRESHOLD = 200;
1167
+ var allocateRangeOutput = (state, cursorLeaf, cursorIndex, compare, upperExclusive, startKey, endKey, options) => {
1168
+ const firstLeafCount = leafEntryCount(cursorLeaf);
1169
+ const firstLeafRemainder = firstLeafCount - cursorIndex;
1170
+ if (firstLeafRemainder >= RANGE_PREALLOC_THRESHOLD && cursorLeaf.next !== null) {
1171
+ const lastEntry = leafEntryAt(cursorLeaf, firstLeafCount - 1);
1172
+ const cmpLast = compare(lastEntry.key, endKey);
1173
+ if (upperExclusive ? cmpLast < 0 : cmpLast <= 0) {
1174
+ const total = countRangeEntries(state, startKey, endKey, options);
1175
+ return new Array(total);
1176
+ }
1177
+ }
1178
+ return [];
1179
+ };
1180
+ var appendLeafSlice = (leaf, from, to, output, useIndexed, writeIdx) => {
1181
+ if (useIndexed) {
1182
+ for (let i = from; i < to; i += 1) {
1183
+ output[writeIdx++] = leafEntryAt(leaf, i);
1184
+ }
1185
+ } else {
1186
+ for (let i = from; i < to; i += 1) {
1187
+ output.push(leafEntryAt(leaf, i));
1188
+ }
1189
+ }
1190
+ return writeIdx;
1191
+ };
1192
+ var rangeQueryEntries = (state, startKey, endKey, options) => {
1193
+ const cursor = initRangeCursor(state, startKey, endKey, options);
1194
+ if (cursor === null) return [];
1195
+ let cursorLeaf = cursor.leaf;
1196
+ let cursorIndex = cursor.index;
1197
+ const { compare, upperExclusive } = cursor;
1198
+ const output = allocateRangeOutput(state, cursorLeaf, cursorIndex, compare, upperExclusive, startKey, endKey, options);
1199
+ let writeIdx = 0;
1200
+ const useIndexed = output.length > 0;
1201
+ while (cursorLeaf !== null) {
1202
+ const leafCount = leafEntryCount(cursorLeaf);
1203
+ if (cursorIndex >= leafCount) {
1204
+ cursorLeaf = cursorLeaf.next;
1205
+ cursorIndex = 0;
1206
+ continue;
1207
+ }
1208
+ const lastEntry = leafEntryAt(cursorLeaf, leafCount - 1);
1209
+ const cmpLast = compare(lastEntry.key, endKey);
1210
+ if (upperExclusive ? cmpLast < 0 : cmpLast <= 0) {
1211
+ writeIdx = appendLeafSlice(cursorLeaf, cursorIndex, leafCount, output, useIndexed, writeIdx);
1212
+ cursorLeaf = cursorLeaf.next;
1213
+ cursorIndex = 0;
1214
+ continue;
1215
+ }
1216
+ const endSeq = upperExclusive ? 0 : Number.MAX_SAFE_INTEGER;
1217
+ const endBound = upperExclusive ? lowerBoundInLeaf(state, cursorLeaf, endKey, endSeq) : upperBoundInLeaf(state, cursorLeaf, endKey, endSeq);
1218
+ const limit = endBound < leafCount ? endBound : leafCount;
1219
+ appendLeafSlice(cursorLeaf, cursorIndex, limit, output, useIndexed, writeIdx);
1220
+ return output;
1221
+ }
1222
+ return output;
1223
+ };
1224
+
1225
+ // src/btree/serialization.ts
1226
+ var buildConfigFromState = (state) => {
1227
+ const config = {
1228
+ compareKeys: state.compareKeys,
1229
+ duplicateKeys: state.duplicateKeys,
1230
+ enableEntryIdLookup: state.entryKeys !== null,
1231
+ autoScale: state.autoScale
1232
+ };
1233
+ if (!state.autoScale) {
1234
+ config.maxLeafEntries = state.maxLeafEntries;
1235
+ config.maxBranchChildren = state.maxBranchChildren;
1236
+ }
1237
+ return config;
1238
+ };
1239
+ var serializeToJSON = (state) => {
1240
+ const entries = new Array(state.entryCount);
1241
+ let leaf = state.leftmostLeaf;
1242
+ let writeIdx = 0;
1243
+ while (leaf !== null) {
1244
+ const count = leafEntryCount(leaf);
1245
+ for (let i = 0; i < count; i += 1) {
1246
+ const e = leafEntryAt(leaf, i);
1247
+ entries[writeIdx++] = [e.key, e.value];
1248
+ }
1249
+ leaf = leaf.next;
1250
+ }
1251
+ return {
1252
+ version: 1,
1253
+ config: {
1254
+ maxLeafEntries: state.maxLeafEntries,
1255
+ maxBranchChildren: state.maxBranchChildren,
1256
+ duplicateKeys: state.duplicateKeys,
1257
+ enableEntryIdLookup: state.entryKeys !== null,
1258
+ autoScale: state.autoScale
1259
+ },
1260
+ entries
1261
+ };
1262
+ };
1263
+ var MAX_SERIALIZED_ENTRIES = 1e6;
1264
+ var validateStructure = (json) => {
1265
+ if (typeof json !== "object" || json === null || json.version !== 1) {
1266
+ throw new BTreeValidationError(
1267
+ `BTreeJSON: expected version 1, got ${String(json?.version)}.`
1268
+ );
1269
+ }
1270
+ if (typeof json.config !== "object" || json.config === null) {
1271
+ throw new BTreeValidationError("BTreeJSON: invalid config.");
1272
+ }
1273
+ if (!Array.isArray(json.entries)) {
1274
+ throw new BTreeValidationError("BTreeJSON: entries must be array.");
1275
+ }
1276
+ if (json.entries.length > MAX_SERIALIZED_ENTRIES) {
1277
+ throw new BTreeValidationError("BTreeJSON: entry count exceeds maximum.");
1278
+ }
1279
+ for (let i = 0; i < json.entries.length; i += 1) {
1280
+ const entry = json.entries[i];
1281
+ if (!Array.isArray(entry) || entry.length !== 2) {
1282
+ throw new BTreeValidationError(`BTreeJSON: bad entries[${i}].`);
1283
+ }
1284
+ }
1285
+ };
1286
+ var validateConfig = (cfg) => {
1287
+ const validateCapacity = (field, value) => {
1288
+ if (!Number.isInteger(value) || value < MIN_NODE_CAPACITY || value > MAX_NODE_CAPACITY) {
1289
+ throw new BTreeValidationError(`BTreeJSON: invalid ${field}.`);
1290
+ }
1291
+ };
1292
+ if (cfg.duplicateKeys !== "allow" && cfg.duplicateKeys !== "reject" && cfg.duplicateKeys !== "replace") {
1293
+ throw new BTreeValidationError(
1294
+ `BTreeJSON: invalid duplicateKeys: ${String(cfg.duplicateKeys)}.`
1295
+ );
1296
+ }
1297
+ if (typeof cfg.enableEntryIdLookup !== "boolean") {
1298
+ throw new BTreeValidationError("BTreeJSON: invalid enableEntryIdLookup.");
1299
+ }
1300
+ if (typeof cfg.autoScale !== "boolean") {
1301
+ throw new BTreeValidationError("BTreeJSON: invalid autoScale.");
1302
+ }
1303
+ if (typeof cfg.maxLeafEntries !== "number") {
1304
+ throw new BTreeValidationError("BTreeJSON: invalid maxLeafEntries.");
1305
+ }
1306
+ if (typeof cfg.maxBranchChildren !== "number") {
1307
+ throw new BTreeValidationError("BTreeJSON: invalid maxBranchChildren.");
1308
+ }
1309
+ validateCapacity("maxLeafEntries", cfg.maxLeafEntries);
1310
+ validateCapacity("maxBranchChildren", cfg.maxBranchChildren);
1311
+ if (cfg.autoScale) {
1312
+ const tier0 = computeAutoScaleTier(0);
1313
+ if (cfg.maxLeafEntries < tier0.maxLeaf || cfg.maxBranchChildren < tier0.maxBranch) {
1314
+ throw new BTreeValidationError(
1315
+ "BTreeJSON: autoScale capacity below tier-0."
1316
+ );
1317
+ }
1318
+ }
1319
+ };
1320
+ var validateBTreeJSON = (json) => {
1321
+ validateStructure(json);
1322
+ validateConfig(json.config);
1323
+ };
1324
+ var buildConfigFromJSON = (json, compareKeys) => {
1325
+ const cfg = json.config;
1326
+ const config = {
1327
+ compareKeys,
1328
+ duplicateKeys: cfg.duplicateKeys,
1329
+ enableEntryIdLookup: cfg.enableEntryIdLookup,
1330
+ autoScale: cfg.autoScale
1331
+ };
1332
+ if (!cfg.autoScale) {
1333
+ config.maxLeafEntries = cfg.maxLeafEntries;
1334
+ config.maxBranchChildren = cfg.maxBranchChildren;
1335
+ }
1336
+ return config;
1337
+ };
1338
+
1339
+ // src/btree/integrity-helpers.ts
1340
+ var nodeMinKey = (node) => {
1341
+ if (isLeafNode(node)) {
1342
+ if (node.entryOffset >= node.entries.length) return null;
1343
+ const e = node.entries[node.entryOffset];
1344
+ return { key: e.key, sequence: e.entryId };
1345
+ }
1346
+ if (node.childOffset >= node.keys.length) return null;
1347
+ return { key: node.keys[node.childOffset].key, sequence: node.keys[node.childOffset].sequence };
1348
+ };
1349
+ var compareNodeKeys = (comparator, leftKey, leftSeq, rightKey, rightSeq) => {
1350
+ const cmp = comparator(leftKey, rightKey);
1351
+ if (cmp !== 0) {
1352
+ return cmp;
1353
+ }
1354
+ return leftSeq - rightSeq;
1355
+ };
1356
+ var getNodeMaxKey = (node) => {
1357
+ if (isLeafNode(node)) {
1358
+ if (node.entryOffset >= node.entries.length) return null;
1359
+ const e = node.entries[node.entries.length - 1];
1360
+ return { key: e.key, sequence: e.entryId };
1361
+ }
1362
+ if (node.childOffset >= node.children.length) {
1363
+ return null;
1364
+ }
1365
+ return getNodeMaxKey(node.children[node.children.length - 1]);
1366
+ };
1367
+ var validateComparatorResult = (result) => {
1368
+ if (!Number.isFinite(result)) {
1369
+ throw new BTreeValidationError(
1370
+ "compareKeys must return a finite number."
1371
+ );
1372
+ }
1373
+ return result;
1374
+ };
1375
+ var assertComparatorReflexivity = (comparator, key) => {
1376
+ const selfCompared = validateComparatorResult(comparator(key, key));
1377
+ if (selfCompared !== 0) {
1378
+ throw new BTreeValidationError(
1379
+ "compareKeys must satisfy reflexivity: compare(x, x) must return 0."
1380
+ );
1381
+ }
1382
+ };
1383
+ var assertComparatorTransitivity = (comparator, first, second, third) => {
1384
+ const firstToSecond = Math.sign(
1385
+ validateComparatorResult(comparator(first, second))
1386
+ );
1387
+ const secondToThird = Math.sign(
1388
+ validateComparatorResult(comparator(second, third))
1389
+ );
1390
+ if (firstToSecond < 0 && secondToThird < 0) {
1391
+ const firstToThird = Math.sign(
1392
+ validateComparatorResult(comparator(first, third))
1393
+ );
1394
+ if (firstToThird >= 0) {
1395
+ throw new BTreeValidationError(
1396
+ "compareKeys must satisfy transitivity for observed key triples."
1397
+ );
1398
+ }
1399
+ }
1400
+ if (firstToSecond > 0 && secondToThird > 0) {
1401
+ const firstToThird = Math.sign(
1402
+ validateComparatorResult(comparator(first, third))
1403
+ );
1404
+ if (firstToThird <= 0) {
1405
+ throw new BTreeValidationError(
1406
+ "compareKeys must satisfy transitivity for observed key triples."
1407
+ );
1408
+ }
1409
+ }
1410
+ };
1411
+ var assertReflexivityAsInvariant = (state, key) => {
1412
+ try {
1413
+ assertComparatorReflexivity(state.compareKeys, key);
1414
+ } catch (error) {
1415
+ if (error instanceof BTreeValidationError) {
1416
+ throw new BTreeInvariantError(error.message);
1417
+ }
1418
+ throw error;
1419
+ }
1420
+ };
1421
+ var assertTransitivityAsInvariant = (state, first, second, third) => {
1422
+ try {
1423
+ assertComparatorTransitivity(state.compareKeys, first, second, third);
1424
+ } catch (error) {
1425
+ if (error instanceof BTreeValidationError) {
1426
+ throw new BTreeInvariantError(error.message);
1427
+ }
1428
+ throw error;
1429
+ }
1430
+ };
1431
+ var validateLeafChainStep = (state, cursor, previous, visited) => {
1432
+ if (!isLeafNode(cursor)) {
1433
+ throw new BTreeInvariantError("Leaf linkage cursor reached non-leaf node.");
1434
+ }
1435
+ if (visited.has(cursor)) {
1436
+ throw new BTreeInvariantError("Cycle detected in leaf linkage.");
1437
+ }
1438
+ if (cursor.prev !== previous) {
1439
+ throw new BTreeInvariantError("Leaf prev pointer mismatch.");
1440
+ }
1441
+ if (previous !== null && isLeafNode(previous)) {
1442
+ const prevMax = getNodeMaxKey(previous);
1443
+ const currentMin = nodeMinKey(cursor);
1444
+ if (prevMax === null || currentMin === null) {
1445
+ throw new BTreeInvariantError("Non-empty tree leaf chain contains empty leaf node.");
1446
+ }
1447
+ if (compareNodeKeys(state.compareKeys, prevMax.key, prevMax.sequence, currentMin.key, currentMin.sequence) > 0) {
1448
+ throw new BTreeInvariantError("Adjacent leaf key ranges are out of order.");
1449
+ }
1450
+ const prevCount = leafEntryCount(previous);
1451
+ const curCount = leafEntryCount(cursor);
1452
+ if (state.duplicateKeys !== "allow" && prevCount > 0 && curCount > 0 && state.compareKeys(
1453
+ leafEntryAt(previous, prevCount - 1).key,
1454
+ leafEntryAt(cursor, 0).key
1455
+ ) === 0) {
1456
+ throw new BTreeInvariantError("Duplicate user key detected across adjacent leaves with uniqueness policy.");
1457
+ }
1458
+ }
1459
+ };
1460
+ var validateLeafLinks = (state, expectedLeafCount) => {
1461
+ if (state.entryCount === 0) {
1462
+ if (!isLeafNode(state.root)) {
1463
+ throw new BTreeInvariantError("Empty tree root must be a leaf node.");
1464
+ }
1465
+ if (state.leftmostLeaf !== state.root || state.rightmostLeaf !== state.root) {
1466
+ throw new BTreeInvariantError("Empty tree leaf pointers must reference root leaf.");
1467
+ }
1468
+ return;
1469
+ }
1470
+ if (state.leftmostLeaf.prev !== null) {
1471
+ throw new BTreeInvariantError("Leftmost leaf prev pointer must be null.");
1472
+ }
1473
+ if (state.rightmostLeaf.next !== null) {
1474
+ throw new BTreeInvariantError("Rightmost leaf next pointer must be null.");
1475
+ }
1476
+ const visited = /* @__PURE__ */ new Set();
1477
+ let cursor = state.leftmostLeaf;
1478
+ let previous = null;
1479
+ let leafCount = 0;
1480
+ while (cursor !== null) {
1481
+ validateLeafChainStep(state, cursor, previous, visited);
1482
+ visited.add(cursor);
1483
+ previous = cursor;
1484
+ cursor = cursor.next;
1485
+ leafCount += 1;
1486
+ }
1487
+ if (previous !== state.rightmostLeaf) {
1488
+ throw new BTreeInvariantError("Rightmost leaf pointer mismatch.");
1489
+ }
1490
+ if (leafCount !== expectedLeafCount) {
1491
+ throw new BTreeInvariantError("Leaf chain count mismatch with tree traversal count.");
1492
+ }
1493
+ };
1494
+
1495
+ // src/btree/integrity.ts
1496
+ var validateLeafNodeOrdering = (state, node) => {
1497
+ const count = leafEntryCount(node);
1498
+ for (let i = 0; i < count; i += 1) {
1499
+ assertReflexivityAsInvariant(state, leafEntryAt(node, i).key);
1500
+ }
1501
+ for (let index = 1; index < count; index += 1) {
1502
+ if (compareNodeKeys(
1503
+ state.compareKeys,
1504
+ leafEntryAt(node, index - 1).key,
1505
+ leafEntryAt(node, index - 1).entryId,
1506
+ leafEntryAt(node, index).key,
1507
+ leafEntryAt(node, index).entryId
1508
+ ) >= 0) {
1509
+ throw new BTreeInvariantError("Leaf entries are not strictly ordered.");
1510
+ }
1511
+ }
1512
+ if (state.duplicateKeys !== "allow") {
1513
+ for (let index = 1; index < count; index += 1) {
1514
+ if (state.compareKeys(
1515
+ leafEntryAt(node, index - 1).key,
1516
+ leafEntryAt(node, index).key
1517
+ ) === 0) {
1518
+ throw new BTreeInvariantError("Duplicate user key detected in tree with uniqueness policy.");
1519
+ }
1520
+ }
1521
+ }
1522
+ for (let index = 2; index < count; index += 1) {
1523
+ const first = leafEntryAt(node, index - 2);
1524
+ const second = leafEntryAt(node, index - 1);
1525
+ const third = leafEntryAt(node, index);
1526
+ assertTransitivityAsInvariant(
1527
+ state,
1528
+ first.key,
1529
+ second.key,
1530
+ third.key
1531
+ );
1532
+ }
1533
+ if (count > state.maxLeafEntries) {
1534
+ throw new BTreeInvariantError("Leaf node exceeds maximum occupancy.");
1535
+ }
1536
+ };
1537
+ var validateLeafNode = (state, node, depth) => {
1538
+ validateLeafNodeOrdering(state, node);
1539
+ const count = leafEntryCount(node);
1540
+ const baseMinLeaf = state.autoScale ? Math.ceil(computeAutoScaleTier(0).maxLeaf / 2) : state.minLeafEntries;
1541
+ if (node !== state.root && count < baseMinLeaf) {
1542
+ throw new BTreeInvariantError("Non-root leaf node violates minimum occupancy.");
1543
+ }
1544
+ const first = count === 0 ? null : leafEntryAt(node, 0);
1545
+ const last = count === 0 ? null : leafEntryAt(node, count - 1);
1546
+ const minKey = first === null ? null : { key: first.key, sequence: first.entryId };
1547
+ const maxKey = last === null ? null : { key: last.key, sequence: last.entryId };
1548
+ return {
1549
+ minKey,
1550
+ maxKey,
1551
+ leafDepth: count === 0 ? null : depth,
1552
+ leafCount: 1,
1553
+ branchCount: 0,
1554
+ entryCount: count
1555
+ };
1556
+ };
1557
+ var validateBranchStructure = (state, node) => {
1558
+ const liveCount = node.children.length - node.childOffset;
1559
+ if (liveCount === 0) {
1560
+ throw new BTreeInvariantError("Branch node has zero children.");
1561
+ }
1562
+ const baseMinBranch = state.autoScale ? Math.ceil(computeAutoScaleTier(0).maxBranch / 2) : state.minBranchChildren;
1563
+ if (node !== state.root && liveCount < baseMinBranch) {
1564
+ throw new BTreeInvariantError("Non-root branch node violates minimum occupancy.");
1565
+ }
1566
+ if (liveCount > state.maxBranchChildren) {
1567
+ throw new BTreeInvariantError("Branch node exceeds maximum occupancy.");
1568
+ }
1569
+ if (node.keys.length !== node.children.length) {
1570
+ throw new BTreeInvariantError("Branch keys array length does not match children array length.");
1571
+ }
1572
+ };
1573
+ var validateBranchChild = (state, node, childIndex, depth) => {
1574
+ const child = node.children[childIndex];
1575
+ if (child.parent !== node) {
1576
+ throw new BTreeInvariantError("Child-parent pointer mismatch in branch node.");
1577
+ }
1578
+ if (child.indexInParent !== childIndex) {
1579
+ throw new BTreeInvariantError("Child indexInParent does not match actual position in parent.");
1580
+ }
1581
+ const childValidation = validateNode(state, child, depth + 1);
1582
+ if (childValidation.minKey === null || childValidation.maxKey === null) {
1583
+ throw new BTreeInvariantError("Branch child must not be empty in non-root branch tree.");
1584
+ }
1585
+ const cachedMinKey = node.keys[childIndex];
1586
+ const actualMinKey = nodeMinKey(child);
1587
+ if (actualMinKey === null || compareNodeKeys(state.compareKeys, cachedMinKey.key, cachedMinKey.sequence, actualMinKey.key, actualMinKey.sequence) !== 0) {
1588
+ throw new BTreeInvariantError("Branch cached key does not match actual child minimum key.");
1589
+ }
1590
+ return childValidation;
1591
+ };
1592
+ var validateNode = (state, node, depth) => {
1593
+ if (isLeafNode(node)) {
1594
+ return validateLeafNode(state, node, depth);
1595
+ }
1596
+ validateBranchStructure(state, node);
1597
+ let leafDepth = null;
1598
+ let leafCount = 0;
1599
+ let branchCount = 1;
1600
+ let entryCount = 0;
1601
+ let minKey = null;
1602
+ let maxKey = null;
1603
+ let previousChildMax = null;
1604
+ for (let childIndex = node.childOffset; childIndex < node.children.length; childIndex += 1) {
1605
+ const childValidation = validateBranchChild(state, node, childIndex, depth);
1606
+ if (leafDepth !== null && childValidation.leafDepth !== null && childValidation.leafDepth !== leafDepth) {
1607
+ throw new BTreeInvariantError("Leaf depth mismatch detected in tree.");
1608
+ }
1609
+ if (leafDepth === null && childValidation.leafDepth !== null) {
1610
+ leafDepth = childValidation.leafDepth;
1611
+ }
1612
+ if (previousChildMax !== null && compareNodeKeys(
1613
+ state.compareKeys,
1614
+ previousChildMax.key,
1615
+ previousChildMax.sequence,
1616
+ childValidation.minKey.key,
1617
+ childValidation.minKey.sequence
1618
+ ) >= 0) {
1619
+ throw new BTreeInvariantError("Branch child key ranges are not strictly ordered.");
1620
+ }
1621
+ if (minKey === null) minKey = childValidation.minKey;
1622
+ maxKey = childValidation.maxKey;
1623
+ previousChildMax = childValidation.maxKey;
1624
+ leafCount += childValidation.leafCount;
1625
+ branchCount += childValidation.branchCount;
1626
+ entryCount += childValidation.entryCount;
1627
+ }
1628
+ return { minKey, maxKey, leafDepth, leafCount, branchCount, entryCount };
1629
+ };
1630
+ var assertInvariants = (state) => {
1631
+ const validation = validateNode(state, state.root, 0);
1632
+ if (validation.entryCount !== state.entryCount) {
1633
+ throw new BTreeInvariantError("Index entry count mismatch between tree traversal and tracked state.");
1634
+ }
1635
+ validateLeafLinks(state, validation.leafCount);
1636
+ };
1637
+
1638
+ // src/btree/stats.ts
1639
+ var collectStats = (node) => {
1640
+ if (isLeafNode(node)) {
1641
+ return {
1642
+ height: 1,
1643
+ leafCount: 1,
1644
+ branchCount: 0
1645
+ };
1646
+ }
1647
+ let maxChildHeight = 0;
1648
+ let leafCount = 0;
1649
+ let branchCount = 1;
1650
+ for (let ci = node.childOffset; ci < node.children.length; ci += 1) {
1651
+ const child = node.children[ci];
1652
+ const childStats = collectStats(child);
1653
+ if (childStats.height > maxChildHeight) {
1654
+ maxChildHeight = childStats.height;
1655
+ }
1656
+ leafCount += childStats.leafCount;
1657
+ branchCount += childStats.branchCount;
1658
+ }
1659
+ return {
1660
+ height: maxChildHeight + 1,
1661
+ leafCount,
1662
+ branchCount
1663
+ };
1664
+ };
1665
+ var getStats = (state) => {
1666
+ const stats = collectStats(state.root);
1667
+ return {
1668
+ height: stats.height,
1669
+ leafCount: stats.leafCount,
1670
+ branchCount: stats.branchCount,
1671
+ entryCount: state.entryCount
1672
+ };
1673
+ };
1674
+
1675
+ // src/InMemoryBTree.ts
1676
+ var InMemoryBTree = class _InMemoryBTree {
1677
+ constructor(config) {
1678
+ this.state = createInitialState(config);
1679
+ }
1680
+ put(key, value) {
1681
+ return putEntry(this.state, key, value);
1682
+ }
1683
+ putMany(entries) {
1684
+ return putManyEntries(this.state, entries);
1685
+ }
1686
+ remove(key) {
1687
+ return removeFirstMatchingEntry(this.state, key);
1688
+ }
1689
+ removeById(entryId) {
1690
+ if (this.state.entryKeys === null) {
1691
+ throw new BTreeValidationError("Requires enableEntryIdLookup: true.");
1692
+ }
1693
+ return removeEntryById(this.state, entryId);
1694
+ }
1695
+ peekById(entryId) {
1696
+ if (this.state.entryKeys === null) {
1697
+ throw new BTreeValidationError("Requires enableEntryIdLookup: true.");
1698
+ }
1699
+ return peekEntryById(this.state, entryId);
1700
+ }
1701
+ updateById(entryId, value) {
1702
+ if (this.state.entryKeys === null) {
1703
+ throw new BTreeValidationError("Requires enableEntryIdLookup: true.");
1704
+ }
1705
+ return updateEntryById(this.state, entryId, value);
1706
+ }
1707
+ popFirst() {
1708
+ return popFirstEntry(this.state);
1709
+ }
1710
+ peekFirst() {
1711
+ if (this.state.entryCount === 0) {
1712
+ return null;
1713
+ }
1714
+ return leafEntryAt(this.state.leftmostLeaf, 0);
1715
+ }
1716
+ peekLast() {
1717
+ if (this.state.entryCount === 0) {
1718
+ return null;
1719
+ }
1720
+ const leaf = this.state.rightmostLeaf;
1721
+ return leafEntryAt(leaf, leafEntryCount(leaf) - 1);
1722
+ }
1723
+ popLast() {
1724
+ return popLastEntry(this.state);
1725
+ }
1726
+ clear() {
1727
+ const emptyLeaf = createLeafNode([], null);
1728
+ this.state.root = emptyLeaf;
1729
+ this.state.leftmostLeaf = emptyLeaf;
1730
+ this.state.rightmostLeaf = emptyLeaf;
1731
+ this.state.entryCount = 0;
1732
+ this.state._cursor.leaf = emptyLeaf;
1733
+ this.state._cursor.index = 0;
1734
+ if (this.state.entryKeys !== null) {
1735
+ this.state.entryKeys.clear();
1736
+ }
1737
+ if (this.state.autoScale) {
1738
+ const tier = computeAutoScaleTier(0);
1739
+ this.state.maxLeafEntries = tier.maxLeaf;
1740
+ this.state.maxBranchChildren = tier.maxBranch;
1741
+ this.state.minLeafEntries = Math.ceil(tier.maxLeaf / 2);
1742
+ this.state.minBranchChildren = Math.ceil(tier.maxBranch / 2);
1743
+ this.state._nextAutoScaleThreshold = computeNextAutoScaleThreshold(0);
1744
+ }
1745
+ }
1746
+ get(key) {
1747
+ const found = findFirstMatchingUserKey(this.state, key);
1748
+ if (found === null) return null;
1749
+ return leafEntryAt(found.leaf, found.index).value;
1750
+ }
1751
+ hasKey(key) {
1752
+ return hasKeyEntry(this.state, key);
1753
+ }
1754
+ findFirst(key) {
1755
+ const found = findFirstMatchingUserKey(this.state, key);
1756
+ if (found === null) return null;
1757
+ return leafEntryAt(found.leaf, found.index);
1758
+ }
1759
+ findLast(key) {
1760
+ const found = findLastMatchingUserKey(this.state, key);
1761
+ if (found === null) return null;
1762
+ return leafEntryAt(found.leaf, found.index);
1763
+ }
1764
+ nextHigherKey(key) {
1765
+ return findNextHigherKey(this.state, key);
1766
+ }
1767
+ nextLowerKey(key) {
1768
+ return findNextLowerKey(this.state, key);
1769
+ }
1770
+ getPairOrNextLower(key) {
1771
+ const found = findPairOrNextLower(this.state, key);
1772
+ if (found === null) return null;
1773
+ return leafEntryAt(found.leaf, found.index);
1774
+ }
1775
+ count(startKey, endKey, options) {
1776
+ return countRangeEntries(this.state, startKey, endKey, options);
1777
+ }
1778
+ deleteRange(startKey, endKey, options) {
1779
+ return deleteRangeEntries(this.state, startKey, endKey, options);
1780
+ }
1781
+ range(startKey, endKey, options) {
1782
+ return rangeQueryEntries(this.state, startKey, endKey, options);
1783
+ }
1784
+ *entries() {
1785
+ let leaf = this.state.leftmostLeaf;
1786
+ while (leaf !== null) {
1787
+ const count = leafEntryCount(leaf);
1788
+ for (let i = 0; i < count; i += 1) {
1789
+ yield leafEntryAt(leaf, i);
1790
+ }
1791
+ leaf = leaf.next;
1792
+ }
1793
+ }
1794
+ *entriesReversed() {
1795
+ let leaf = this.state.rightmostLeaf;
1796
+ while (leaf !== null) {
1797
+ const count = leafEntryCount(leaf);
1798
+ for (let i = count - 1; i >= 0; i -= 1) {
1799
+ yield leafEntryAt(leaf, i);
1800
+ }
1801
+ leaf = leaf.prev;
1802
+ }
1803
+ }
1804
+ *keys() {
1805
+ let leaf = this.state.leftmostLeaf;
1806
+ while (leaf !== null) {
1807
+ const count = leafEntryCount(leaf);
1808
+ for (let i = 0; i < count; i += 1) {
1809
+ yield leafEntryAt(leaf, i).key;
1810
+ }
1811
+ leaf = leaf.next;
1812
+ }
1813
+ }
1814
+ *values() {
1815
+ let leaf = this.state.leftmostLeaf;
1816
+ while (leaf !== null) {
1817
+ const count = leafEntryCount(leaf);
1818
+ for (let i = 0; i < count; i += 1) {
1819
+ yield leafEntryAt(leaf, i).value;
1820
+ }
1821
+ leaf = leaf.next;
1822
+ }
1823
+ }
1824
+ [Symbol.iterator]() {
1825
+ return this.entries();
1826
+ }
1827
+ forEach(callback, thisArg) {
1828
+ let leaf = this.state.leftmostLeaf;
1829
+ while (leaf !== null) {
1830
+ const count = leafEntryCount(leaf);
1831
+ for (let i = 0; i < count; i += 1) {
1832
+ callback.call(thisArg, leafEntryAt(leaf, i));
1833
+ }
1834
+ leaf = leaf.next;
1835
+ }
1836
+ }
1837
+ snapshot() {
1838
+ const result = new Array(this.state.entryCount);
1839
+ let leaf = this.state.leftmostLeaf;
1840
+ let writeIdx = 0;
1841
+ while (leaf !== null) {
1842
+ const count = leafEntryCount(leaf);
1843
+ for (let i = 0; i < count; i += 1) {
1844
+ result[writeIdx++] = leafEntryAt(leaf, i);
1845
+ }
1846
+ leaf = leaf.next;
1847
+ }
1848
+ return result;
1849
+ }
1850
+ clone() {
1851
+ const cloned = new _InMemoryBTree(buildConfigFromState(this.state));
1852
+ applyAutoScaleCapacitySnapshot(
1853
+ cloned.state,
1854
+ this.state.maxLeafEntries,
1855
+ this.state.maxBranchChildren
1856
+ );
1857
+ if (this.state.entryCount > 0) {
1858
+ const pairs = new Array(this.state.entryCount);
1859
+ let leaf = this.state.leftmostLeaf;
1860
+ let writeIdx = 0;
1861
+ while (leaf !== null) {
1862
+ const count = leafEntryCount(leaf);
1863
+ for (let i = 0; i < count; i += 1) {
1864
+ pairs[writeIdx++] = leafEntryAt(leaf, i);
1865
+ }
1866
+ leaf = leaf.next;
1867
+ }
1868
+ cloned.putMany(pairs);
1869
+ }
1870
+ return cloned;
1871
+ }
1872
+ toJSON() {
1873
+ return serializeToJSON(this.state);
1874
+ }
1875
+ static fromJSON(json, compareKeys) {
1876
+ validateBTreeJSON(json);
1877
+ const strict = json.config.duplicateKeys !== "allow";
1878
+ for (let i = 1; i < json.entries.length; i += 1) {
1879
+ const cmp = compareKeys(json.entries[i - 1][0], json.entries[i][0]);
1880
+ if (cmp > 0) {
1881
+ throw new BTreeValidationError("fromJSON: entries not sorted.");
1882
+ }
1883
+ if (strict && cmp === 0) {
1884
+ throw new BTreeValidationError(
1885
+ 'fromJSON: duplicate keys require duplicateKeys "allow".'
1886
+ );
1887
+ }
1888
+ }
1889
+ const tree = new _InMemoryBTree(buildConfigFromJSON(json, compareKeys));
1890
+ applyAutoScaleCapacitySnapshot(
1891
+ tree.state,
1892
+ json.config.maxLeafEntries,
1893
+ json.config.maxBranchChildren
1894
+ );
1895
+ if (json.entries.length > 0) {
1896
+ const pairs = new Array(json.entries.length);
1897
+ for (let i = 0; i < json.entries.length; i += 1) {
1898
+ pairs[i] = { key: json.entries[i][0], value: json.entries[i][1] };
1899
+ }
1900
+ tree.putMany(pairs);
1901
+ }
1902
+ return tree;
1903
+ }
1904
+ size() {
1905
+ return this.state.entryCount;
1906
+ }
1907
+ assertInvariants() {
1908
+ assertInvariants(this.state);
1909
+ }
1910
+ getStats() {
1911
+ return getStats(this.state);
1912
+ }
1913
+ };
1914
+ // Annotate the CommonJS export names for ESM import in node:
1915
+ 0 && (module.exports = {
1916
+ BTreeInvariantError,
1917
+ BTreeValidationError,
1918
+ InMemoryBTree
1919
+ });