@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/LICENSE +21 -0
- package/README-JA.md +912 -0
- package/README.md +912 -0
- package/dist/InMemoryBTree.d.ts +45 -0
- package/dist/btree/autoScale.d.ts +9 -0
- package/dist/btree/bulkLoad.d.ts +5 -0
- package/dist/btree/deleteRange.d.ts +3 -0
- package/dist/btree/integrity-helpers.d.ts +6 -0
- package/dist/btree/integrity.d.ts +2 -0
- package/dist/btree/mutations.d.ts +12 -0
- package/dist/btree/navigation.d.ts +23 -0
- package/dist/btree/rangeQuery.d.ts +3 -0
- package/dist/btree/rebalance.d.ts +4 -0
- package/dist/btree/serialization.d.ts +20 -0
- package/dist/btree/stats.d.ts +2 -0
- package/dist/btree/types.d.ts +113 -0
- package/dist/chunk-ZA3EQNDI.js +1902 -0
- package/dist/concurrency/ConcurrentInMemoryBTree.d.ts +56 -0
- package/dist/concurrency/helpers.d.ts +27 -0
- package/dist/concurrency/index.d.ts +2 -0
- package/dist/concurrency/types.d.ts +41 -0
- package/dist/core.cjs +1919 -0
- package/dist/core.d.ts +4 -0
- package/dist/core.js +10 -0
- package/dist/errors.d.ts +9 -0
- package/dist/frostpillar-btree-core.min.js +1 -0
- package/dist/frostpillar-btree.min.js +1 -0
- package/dist/index.cjs +2230 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +316 -0
- package/package.json +80 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type BTreeJSON } from './btree/serialization.js';
|
|
2
|
+
import { type BTreeEntry, type BTreeStats, type DuplicateKeyPolicy, type EntryId, type InMemoryBTreeConfig, type KeyComparator, type RangeBounds } from './btree/types.js';
|
|
3
|
+
export type { BTreeJSON };
|
|
4
|
+
export type { BTreeEntry, BTreeStats, DuplicateKeyPolicy, EntryId, InMemoryBTreeConfig, RangeBounds };
|
|
5
|
+
export declare class InMemoryBTree<TKey, TValue> {
|
|
6
|
+
private readonly state;
|
|
7
|
+
constructor(config: InMemoryBTreeConfig<TKey>);
|
|
8
|
+
put(key: TKey, value: TValue): EntryId;
|
|
9
|
+
putMany(entries: readonly {
|
|
10
|
+
key: TKey;
|
|
11
|
+
value: TValue;
|
|
12
|
+
}[]): EntryId[];
|
|
13
|
+
remove(key: TKey): BTreeEntry<TKey, TValue> | null;
|
|
14
|
+
removeById(entryId: EntryId): BTreeEntry<TKey, TValue> | null;
|
|
15
|
+
peekById(entryId: EntryId): BTreeEntry<TKey, TValue> | null;
|
|
16
|
+
updateById(entryId: EntryId, value: TValue): BTreeEntry<TKey, TValue> | null;
|
|
17
|
+
popFirst(): BTreeEntry<TKey, TValue> | null;
|
|
18
|
+
peekFirst(): BTreeEntry<TKey, TValue> | null;
|
|
19
|
+
peekLast(): BTreeEntry<TKey, TValue> | null;
|
|
20
|
+
popLast(): BTreeEntry<TKey, TValue> | null;
|
|
21
|
+
clear(): void;
|
|
22
|
+
get(key: TKey): TValue | null;
|
|
23
|
+
hasKey(key: TKey): boolean;
|
|
24
|
+
findFirst(key: TKey): BTreeEntry<TKey, TValue> | null;
|
|
25
|
+
findLast(key: TKey): BTreeEntry<TKey, TValue> | null;
|
|
26
|
+
nextHigherKey(key: TKey): TKey | null;
|
|
27
|
+
nextLowerKey(key: TKey): TKey | null;
|
|
28
|
+
getPairOrNextLower(key: TKey): BTreeEntry<TKey, TValue> | null;
|
|
29
|
+
count(startKey: TKey, endKey: TKey, options?: RangeBounds): number;
|
|
30
|
+
deleteRange(startKey: TKey, endKey: TKey, options?: RangeBounds): number;
|
|
31
|
+
range(startKey: TKey, endKey: TKey, options?: RangeBounds): BTreeEntry<TKey, TValue>[];
|
|
32
|
+
entries(): IterableIterator<BTreeEntry<TKey, TValue>>;
|
|
33
|
+
entriesReversed(): IterableIterator<BTreeEntry<TKey, TValue>>;
|
|
34
|
+
keys(): IterableIterator<TKey>;
|
|
35
|
+
values(): IterableIterator<TValue>;
|
|
36
|
+
[Symbol.iterator](): IterableIterator<BTreeEntry<TKey, TValue>>;
|
|
37
|
+
forEach(callback: (entry: BTreeEntry<TKey, TValue>) => void, thisArg?: unknown): void;
|
|
38
|
+
snapshot(): BTreeEntry<TKey, TValue>[];
|
|
39
|
+
clone(): InMemoryBTree<TKey, TValue>;
|
|
40
|
+
toJSON(): BTreeJSON<TKey, TValue>;
|
|
41
|
+
static fromJSON<TKey, TValue>(json: BTreeJSON<TKey, TValue>, compareKeys: KeyComparator<TKey>): InMemoryBTree<TKey, TValue>;
|
|
42
|
+
size(): number;
|
|
43
|
+
assertInvariants(): void;
|
|
44
|
+
getStats(): BTreeStats;
|
|
45
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type BTreeState, type InMemoryBTreeConfig } from './types.js';
|
|
2
|
+
export declare const computeAutoScaleTier: (entryCount: number) => {
|
|
3
|
+
readonly maxLeaf: number;
|
|
4
|
+
readonly maxBranch: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const computeNextAutoScaleThreshold: (entryCount: number) => number;
|
|
7
|
+
export declare const createInitialState: <TKey, TValue>(config: InMemoryBTreeConfig<TKey>) => BTreeState<TKey, TValue>;
|
|
8
|
+
export declare const maybeAutoScale: <TKey, TValue>(state: BTreeState<TKey, TValue>) => void;
|
|
9
|
+
export declare const applyAutoScaleCapacitySnapshot: <TKey, TValue>(state: BTreeState<TKey, TValue>, maxLeafEntries: number, maxBranchChildren: number) => void;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type BTreeNode, type BTreeState, type KeyComparator, type NodeKey } from './types.js';
|
|
2
|
+
export declare const nodeMinKey: <TKey, TValue>(node: BTreeNode<TKey, TValue>) => NodeKey<TKey> | null;
|
|
3
|
+
export declare const compareNodeKeys: <TKey>(comparator: KeyComparator<TKey>, leftKey: TKey, leftSeq: number, rightKey: TKey, rightSeq: number) => number;
|
|
4
|
+
export declare const assertReflexivityAsInvariant: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => void;
|
|
5
|
+
export declare const assertTransitivityAsInvariant: <TKey, TValue>(state: BTreeState<TKey, TValue>, first: TKey, second: TKey, third: TKey) => void;
|
|
6
|
+
export declare const validateLeafLinks: <TKey, TValue>(state: BTreeState<TKey, TValue>, expectedLeafCount: number) => void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type BTreeEntry, type BTreeState, type EntryId } from './types.js';
|
|
2
|
+
export declare const putEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey, value: TValue) => EntryId;
|
|
3
|
+
export declare const popFirstEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>) => BTreeEntry<TKey, TValue> | null;
|
|
4
|
+
export declare const popLastEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>) => BTreeEntry<TKey, TValue> | null;
|
|
5
|
+
export declare const removeFirstMatchingEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => BTreeEntry<TKey, TValue> | null;
|
|
6
|
+
export declare const removeEntryById: <TKey, TValue>(state: BTreeState<TKey, TValue>, entryId: EntryId) => BTreeEntry<TKey, TValue> | null;
|
|
7
|
+
export declare const peekEntryById: <TKey, TValue>(state: BTreeState<TKey, TValue>, entryId: EntryId) => BTreeEntry<TKey, TValue> | null;
|
|
8
|
+
export declare const updateEntryById: <TKey, TValue>(state: BTreeState<TKey, TValue>, entryId: EntryId, newValue: TValue) => BTreeEntry<TKey, TValue> | null;
|
|
9
|
+
export declare const putManyEntries: <TKey, TValue>(state: BTreeState<TKey, TValue>, entries: readonly {
|
|
10
|
+
key: TKey;
|
|
11
|
+
value: TValue;
|
|
12
|
+
}[]) => EntryId[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type BTreeState, type LeafNode } from './types.js';
|
|
2
|
+
export declare const findLeafForKey: <TKey, TValue>(state: BTreeState<TKey, TValue>, userKey: TKey, sequence: number) => LeafNode<TKey, TValue>;
|
|
3
|
+
export declare const lowerBoundInLeaf: <TKey, TValue>(state: BTreeState<TKey, TValue>, leaf: LeafNode<TKey, TValue>, userKey: TKey, sequence: number) => number;
|
|
4
|
+
export declare const upperBoundInLeaf: <TKey, TValue>(state: BTreeState<TKey, TValue>, leaf: LeafNode<TKey, TValue>, userKey: TKey, sequence: number) => number;
|
|
5
|
+
export declare const findLeafFromHint: <TKey, TValue>(state: BTreeState<TKey, TValue>, hint: LeafNode<TKey, TValue>, userKey: TKey, sequence: number) => LeafNode<TKey, TValue>;
|
|
6
|
+
/** Returns shared cursor — caller must consume result before the next navigation call. */
|
|
7
|
+
export declare const findFirstMatchingUserKey: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => {
|
|
8
|
+
leaf: LeafNode<TKey, TValue>;
|
|
9
|
+
index: number;
|
|
10
|
+
} | null;
|
|
11
|
+
/** Returns shared cursor — caller must consume result before the next navigation call. */
|
|
12
|
+
export declare const findLastMatchingUserKey: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => {
|
|
13
|
+
leaf: LeafNode<TKey, TValue>;
|
|
14
|
+
index: number;
|
|
15
|
+
} | null;
|
|
16
|
+
export declare const hasKeyEntry: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => boolean;
|
|
17
|
+
export declare const findNextHigherKey: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => TKey | null;
|
|
18
|
+
export declare const findNextLowerKey: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => TKey | null;
|
|
19
|
+
/** Returns shared cursor — caller must consume result before the next navigation call. */
|
|
20
|
+
export declare const findPairOrNextLower: <TKey, TValue>(state: BTreeState<TKey, TValue>, key: TKey) => {
|
|
21
|
+
leaf: LeafNode<TKey, TValue>;
|
|
22
|
+
index: number;
|
|
23
|
+
} | null;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type BTreeEntry, type BTreeState, type RangeBounds } from './types.js';
|
|
2
|
+
export declare const countRangeEntries: <TKey, TValue>(state: BTreeState<TKey, TValue>, startKey: TKey, endKey: TKey, options?: RangeBounds) => number;
|
|
3
|
+
export declare const rangeQueryEntries: <TKey, TValue>(state: BTreeState<TKey, TValue>, startKey: TKey, endKey: TKey, options?: RangeBounds) => BTreeEntry<TKey, TValue>[];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type BTreeNode, type BTreeState, type LeafNode } from './types.js';
|
|
2
|
+
declare const updateMinKeyInAncestors: <TKey, TValue>(node: BTreeNode<TKey, TValue>) => void;
|
|
3
|
+
export { updateMinKeyInAncestors };
|
|
4
|
+
export declare const rebalanceAfterLeafRemoval: <TKey, TValue>(state: BTreeState<TKey, TValue>, leaf: LeafNode<TKey, TValue>) => void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type BTreeState, type DuplicateKeyPolicy, type InMemoryBTreeConfig, type KeyComparator } from './types.js';
|
|
2
|
+
export interface BTreeJSON<TKey, TValue> {
|
|
3
|
+
version: number;
|
|
4
|
+
config: {
|
|
5
|
+
maxLeafEntries: number;
|
|
6
|
+
maxBranchChildren: number;
|
|
7
|
+
duplicateKeys: DuplicateKeyPolicy;
|
|
8
|
+
enableEntryIdLookup: boolean;
|
|
9
|
+
autoScale: boolean;
|
|
10
|
+
};
|
|
11
|
+
entries: [TKey, TValue][];
|
|
12
|
+
}
|
|
13
|
+
export declare const collectEntryPairs: <TKey, TValue>(state: BTreeState<TKey, TValue>) => {
|
|
14
|
+
key: TKey;
|
|
15
|
+
value: TValue;
|
|
16
|
+
}[];
|
|
17
|
+
export declare const buildConfigFromState: <TKey, TValue>(state: BTreeState<TKey, TValue>) => InMemoryBTreeConfig<TKey>;
|
|
18
|
+
export declare const serializeToJSON: <TKey, TValue>(state: BTreeState<TKey, TValue>) => BTreeJSON<TKey, TValue>;
|
|
19
|
+
export declare const validateBTreeJSON: <TKey, TValue>(json: BTreeJSON<TKey, TValue>) => void;
|
|
20
|
+
export declare const buildConfigFromJSON: <TKey>(json: BTreeJSON<TKey, unknown>, compareKeys: KeyComparator<TKey>) => InMemoryBTreeConfig<TKey>;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export declare const DEFAULT_MAX_LEAF_ENTRIES = 64;
|
|
2
|
+
export declare const DEFAULT_MAX_BRANCH_CHILDREN = 64;
|
|
3
|
+
export declare const MIN_NODE_CAPACITY = 3;
|
|
4
|
+
export declare const MAX_NODE_CAPACITY = 16384;
|
|
5
|
+
export declare const NODE_LEAF: 0;
|
|
6
|
+
export declare const NODE_BRANCH: 1;
|
|
7
|
+
export type KeyComparator<TKey> = (left: TKey, right: TKey) => number;
|
|
8
|
+
export type DuplicateKeyPolicy = 'allow' | 'reject' | 'replace';
|
|
9
|
+
export interface RangeBounds {
|
|
10
|
+
lowerBound?: 'inclusive' | 'exclusive';
|
|
11
|
+
upperBound?: 'inclusive' | 'exclusive';
|
|
12
|
+
}
|
|
13
|
+
export declare const normalizeDuplicateKeyPolicy: (value: DuplicateKeyPolicy | undefined) => DuplicateKeyPolicy;
|
|
14
|
+
export type EntryId = number & {
|
|
15
|
+
readonly __brand: 'EntryId';
|
|
16
|
+
};
|
|
17
|
+
export interface BTreeEntry<TKey, TValue> {
|
|
18
|
+
readonly entryId: EntryId;
|
|
19
|
+
readonly key: TKey;
|
|
20
|
+
readonly value: TValue;
|
|
21
|
+
}
|
|
22
|
+
export interface NodeKey<TKey> {
|
|
23
|
+
key: TKey;
|
|
24
|
+
sequence: number;
|
|
25
|
+
}
|
|
26
|
+
/** Internal mutable entry stored in leaf nodes. */
|
|
27
|
+
export interface LeafEntry<TKey, TValue> {
|
|
28
|
+
entryId: EntryId;
|
|
29
|
+
key: TKey;
|
|
30
|
+
value: TValue;
|
|
31
|
+
}
|
|
32
|
+
export interface LeafNode<TKey, TValue> {
|
|
33
|
+
kind: typeof NODE_LEAF;
|
|
34
|
+
entries: LeafEntry<TKey, TValue>[];
|
|
35
|
+
entryOffset: number;
|
|
36
|
+
parent: BranchNode<TKey, TValue> | null;
|
|
37
|
+
indexInParent: number;
|
|
38
|
+
prev: LeafNode<TKey, TValue> | null;
|
|
39
|
+
next: LeafNode<TKey, TValue> | null;
|
|
40
|
+
}
|
|
41
|
+
export interface BranchNode<TKey, TValue> {
|
|
42
|
+
kind: typeof NODE_BRANCH;
|
|
43
|
+
children: BTreeNode<TKey, TValue>[];
|
|
44
|
+
keys: NodeKey<TKey>[];
|
|
45
|
+
childOffset: number;
|
|
46
|
+
parent: BranchNode<TKey, TValue> | null;
|
|
47
|
+
indexInParent: number;
|
|
48
|
+
}
|
|
49
|
+
export type BTreeNode<TKey, TValue> = LeafNode<TKey, TValue> | BranchNode<TKey, TValue>;
|
|
50
|
+
export interface BTreeState<TKey, TValue> {
|
|
51
|
+
compareKeys: KeyComparator<TKey>;
|
|
52
|
+
maxLeafEntries: number;
|
|
53
|
+
maxBranchChildren: number;
|
|
54
|
+
duplicateKeys: DuplicateKeyPolicy;
|
|
55
|
+
root: BTreeNode<TKey, TValue>;
|
|
56
|
+
leftmostLeaf: LeafNode<TKey, TValue>;
|
|
57
|
+
rightmostLeaf: LeafNode<TKey, TValue>;
|
|
58
|
+
entryCount: number;
|
|
59
|
+
nextSequence: number;
|
|
60
|
+
minLeafEntries: number;
|
|
61
|
+
minBranchChildren: number;
|
|
62
|
+
entryKeys: Map<EntryId, TKey> | null;
|
|
63
|
+
autoScale: boolean;
|
|
64
|
+
_nextAutoScaleThreshold: number;
|
|
65
|
+
/** @internal Shared return object for navigation functions — never store a reference across calls. */
|
|
66
|
+
_cursor: {
|
|
67
|
+
leaf: LeafNode<TKey, TValue>;
|
|
68
|
+
index: number;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export interface InMemoryBTreeConfig<TKey> {
|
|
72
|
+
compareKeys: KeyComparator<TKey>;
|
|
73
|
+
maxLeafEntries?: number;
|
|
74
|
+
maxBranchChildren?: number;
|
|
75
|
+
duplicateKeys?: DuplicateKeyPolicy;
|
|
76
|
+
enableEntryIdLookup?: boolean;
|
|
77
|
+
autoScale?: boolean;
|
|
78
|
+
}
|
|
79
|
+
export interface BTreeStats {
|
|
80
|
+
height: number;
|
|
81
|
+
leafCount: number;
|
|
82
|
+
branchCount: number;
|
|
83
|
+
entryCount: number;
|
|
84
|
+
}
|
|
85
|
+
export declare const isLeafNode: <TKey, TValue>(node: BTreeNode<TKey, TValue>) => node is LeafNode<TKey, TValue>;
|
|
86
|
+
export declare const writeMinKeyTo: <TKey, TValue>(node: BTreeNode<TKey, TValue>, target: NodeKey<TKey>) => boolean;
|
|
87
|
+
export declare const normalizeNodeCapacity: (value: number | undefined, field: string, defaultValue: number) => number;
|
|
88
|
+
export declare const createLeafNode: <TKey, TValue>(entries: LeafEntry<TKey, TValue>[], parent: BranchNode<TKey, TValue> | null) => LeafNode<TKey, TValue>;
|
|
89
|
+
export declare const createBranchNode: <TKey, TValue>(children: BTreeNode<TKey, TValue>[], parent: BranchNode<TKey, TValue> | null) => BranchNode<TKey, TValue>;
|
|
90
|
+
/** Number of logical entries in the leaf */
|
|
91
|
+
export declare const leafEntryCount: <TKey, TValue>(leaf: LeafNode<TKey, TValue>) => number;
|
|
92
|
+
/** Get logical entry at index i (0-based from the logical start) */
|
|
93
|
+
export declare const leafEntryAt: <TKey, TValue>(leaf: LeafNode<TKey, TValue>, i: number) => LeafEntry<TKey, TValue>;
|
|
94
|
+
/** Remove and return the first logical entry. O(1) amortized — increments offset and compacts when dead slots reach half. */
|
|
95
|
+
export declare const leafShiftEntry: <TKey, TValue>(leaf: LeafNode<TKey, TValue>) => LeafEntry<TKey, TValue> | undefined;
|
|
96
|
+
/** Remove and return the last logical entry. O(1) — pops from the backing array tail. */
|
|
97
|
+
export declare const leafPopEntry: <TKey, TValue>(leaf: LeafNode<TKey, TValue>) => LeafEntry<TKey, TValue> | undefined;
|
|
98
|
+
/** Prepend entry to logical start. Falls back to unshift if no gap, otherwise fills gap. */
|
|
99
|
+
export declare const leafUnshiftEntry: <TKey, TValue>(leaf: LeafNode<TKey, TValue>, entry: LeafEntry<TKey, TValue>) => void;
|
|
100
|
+
/** Remove logical entry at index. Shifts the smaller side to halve average cost. */
|
|
101
|
+
export declare const leafRemoveAt: <TKey, TValue>(leaf: LeafNode<TKey, TValue>, logicalIndex: number) => void;
|
|
102
|
+
/** Insert entry at logical index. Uses entryOffset gap when inserting in the first half. */
|
|
103
|
+
export declare const leafInsertAt: <TKey, TValue>(leaf: LeafNode<TKey, TValue>, logicalIndex: number, entry: LeafEntry<TKey, TValue>) => void;
|
|
104
|
+
/** Compact the backing array — remove dead slots before entryOffset. Call before splits/merges. */
|
|
105
|
+
export declare const leafCompact: <TKey, TValue>(leaf: LeafNode<TKey, TValue>) => void;
|
|
106
|
+
/** Compact branch arrays — remove dead slots before childOffset, keeping a small gap. */
|
|
107
|
+
export declare const branchCompact: <TKey, TValue>(branch: BranchNode<TKey, TValue>) => void;
|
|
108
|
+
/** Number of logical children in the branch. */
|
|
109
|
+
export declare const branchChildCount: <TKey, TValue>(branch: BranchNode<TKey, TValue>) => number;
|
|
110
|
+
/** Insert a child at a logical index. Shifts the smaller side to halve average cost. */
|
|
111
|
+
export declare const branchInsertAt: <TKey, TValue>(branch: BranchNode<TKey, TValue>, logicalIndex: number, child: BTreeNode<TKey, TValue>, key: NodeKey<TKey>) => void;
|
|
112
|
+
/** Remove a child at a physical index. Shifts the smaller side. */
|
|
113
|
+
export declare const branchRemoveAt: <TKey, TValue>(branch: BranchNode<TKey, TValue>, physIndex: number) => void;
|