tiny_trie/bit_trie.rs
1//! Bit Trie — a binary radix trie indexed by individual key bits.
2//!
3//! Each node has exactly two children (bit 0 and bit 1), stored inline as
4//! `[u32; 2]`. Because both children are always present in a binary trie,
5//! there are no empty slots and no mask needed for child enumeration —
6//! just `children[bit]`.
7//!
8//! # Terminal Nodes
9//!
10//! Keys that are prefixes of other keys (e.g. "ab" in {"ab", "abc"}) are
11//! represented by a `terminal` flag on the node where the key ends, rather
12//! than a null-byte leaf child. This eliminates null terminators, allows
13//! `0x00` bytes in keys, and makes `get()` accept plain `&[u8]`.
14//!
15//! # High-Bit Leaf Encoding
16//!
17//! Bit 31 of each `children[i]` indicates whether the value is a leaf key
18//! index (bit set) or an arena index (bit clear). Bit 31 of `leaf` indicates
19//! whether the node is terminal. This packs the leaf/terminal flags into
20//! existing fields, eliminating the separate `leaf_mask` byte.
21//!
22//! # Per-Child Prefix Lengths
23//!
24//! Each node stores `prefix_lens: [u16; 2]` — the prefix length (in bits) for
25//! each child. The node's own prefix length comes from its parent. The root's
26//! prefix length is stored in `BitTrie.root_prefix_len`.
27//!
28//! # Key Index Encoding
29//!
30//! A dummy entry at `index[0] = (0, 0)` points at `buf[0]` (empty key).
31//! Real keys start at index 1. This allows 0 to be used as a sentinel for
32//! "empty" in `children[]` slots.
33
34use crate::{KeyStore, TrieKey};
35use std::simd::{Simd, cmp::SimdPartialEq};
36
37// ---------------------------------------------------------------------------
38// Constants
39// ---------------------------------------------------------------------------
40
41/// Bit 31 of `children[i]` indicates the value is a leaf key index.
42const LEAF_BIT: u32 = 1u32 << 31;
43
44/// Bit 31 of `leaf` indicates the node is terminal (its own key ends here).
45const TERMINAL_BIT: u32 = 1u32 << 31;
46
47/// Sentinel for the iterator: "positioned at the terminal value of this node."
48/// In a binary trie, child positions are 0 and 1, so 2 is available as a sentinel.
49const TERMINAL_POS: u8 = 2;
50
51// ---------------------------------------------------------------------------
52// Core types
53// ---------------------------------------------------------------------------
54
55/// A single node in the bit trie arena.
56///
57/// Layout (16 bytes):
58/// - `children`: 2 slots indexed by bit value (0 or 1). Bit 31 = is_leaf;
59/// bits 0-30 = key index (if leaf) or arena index (if internal). Value 0
60/// means empty (transient during construction only).
61/// - `prefix_lens`: per-child prefix lengths in bits. `prefix_lens[0]` is the
62/// prefix length of the subtree rooted at `children[0]`, and likewise for [1].
63/// The node's own prefix length comes from its parent.
64/// - `leaf`: bit 31 = is_terminal (this node represents a key that ends here);
65/// bits 0-30 = key index for the reference/terminal key.
66#[derive(Clone, Copy)]
67struct Node {
68 children: [u32; 2],
69 prefix_lens: [u16; 2],
70 leaf: u32,
71}
72
73impl Node {
74 fn new() -> Self {
75 Node {
76 children: [0; 2],
77 prefix_lens: [0; 2],
78 leaf: 0,
79 }
80 }
81
82 // -------------------------------------------------------------------
83 // Child helpers
84 // -------------------------------------------------------------------
85
86 #[inline]
87 fn is_leaf(&self, bit: usize) -> bool {
88 debug_assert!(bit < 2);
89 (self.children[bit] & LEAF_BIT) != 0
90 }
91
92 #[inline]
93 fn child_index(&self, bit: usize) -> u32 {
94 debug_assert!(bit < 2);
95 self.children[bit] & !LEAF_BIT
96 }
97
98 #[inline]
99 fn is_empty(&self, bit: usize) -> bool {
100 debug_assert!(bit < 2);
101 self.children[bit] == 0
102 }
103
104 /// Store a leaf key index at `bit`. Key index must be ≥ 1
105 /// (index[0] is the dummy entry). Sets LEAF_BIT.
106 #[inline]
107 fn set_leaf_child(&mut self, bit: usize, key_index: u32, prefix_len: u16) {
108 debug_assert!(bit < 2);
109 debug_assert!(key_index > 0, "key index 0 is the dummy");
110 self.children[bit] = key_index | LEAF_BIT;
111 self.prefix_lens[bit] = prefix_len;
112 }
113
114 /// Store an arena index at `bit` (internal node reference).
115 /// Arena index must be ≥ 1 (root at index 0 is never a child).
116 /// Clears LEAF_BIT.
117 #[inline]
118 fn set_internal_child(&mut self, bit: usize, arena_index: u32, prefix_len: u16) {
119 debug_assert!(bit < 2);
120 debug_assert!(arena_index > 0);
121 self.children[bit] = arena_index; // no LEAF_BIT
122 self.prefix_lens[bit] = prefix_len;
123 }
124
125 /// Decode a leaf child at `bit` into a key index.
126 /// Returns `None` if the slot is empty or not a leaf.
127 #[inline]
128 fn leaf_key_index(&self, bit: usize) -> Option<u32> {
129 debug_assert!(bit < 2);
130 if self.is_leaf(bit) {
131 let idx = self.child_index(bit);
132 if idx != 0 {
133 return Some(idx);
134 }
135 }
136 None
137 }
138
139 // -------------------------------------------------------------------
140 // Terminal helpers
141 // -------------------------------------------------------------------
142
143 #[inline]
144 fn is_terminal(&self) -> bool {
145 (self.leaf & TERMINAL_BIT) != 0
146 }
147
148 #[inline]
149 fn set_terminal(&mut self, val: bool) {
150 if val {
151 self.leaf |= TERMINAL_BIT;
152 } else {
153 self.leaf &= !TERMINAL_BIT;
154 }
155 }
156
157 /// The key index stored in `leaf` (low 31 bits). For terminal nodes,
158 /// this is the node's own key. For non-terminal nodes, this is a
159 /// reference key used during insertion divergence comparison.
160 #[inline]
161 fn leaf_key_index_val(&self) -> u32 {
162 self.leaf & !TERMINAL_BIT
163 }
164
165 #[inline]
166 fn set_leaf_key_index(&mut self, idx: u32) {
167 debug_assert!(idx > 0, "key index 0 is the dummy");
168 self.leaf = (self.leaf & TERMINAL_BIT) | idx;
169 }
170}
171
172impl std::fmt::Debug for Node {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 let active: Vec<(usize, &str, u32, u16)> = (0..2)
175 .filter(|&b| self.children[b] != 0)
176 .map(|b| {
177 let tag = if self.is_leaf(b) { "L" } else { "I" };
178 let idx = self.child_index(b);
179 (b, tag, idx, self.prefix_lens[b])
180 })
181 .collect();
182 f.debug_struct("Node")
183 .field("prefix_lens", &self.prefix_lens)
184 .field("terminal", &self.is_terminal())
185 .field("leaf_idx", &self.leaf_key_index_val())
186 .field("children", &active)
187 .finish()
188 }
189}
190
191// ---------------------------------------------------------------------------
192// BitTrie
193// ---------------------------------------------------------------------------
194
195#[derive(Clone)]
196pub struct BitTrie<K: TrieKey, V> {
197 arena: Vec<Node>,
198 keys: K::Store,
199 values: Vec<V>,
200 /// The root node has no parent, so its prefix_len is stored here.
201 root_prefix_len: u16,
202}
203
204// ---------------------------------------------------------------------------
205// Divergence result
206// ---------------------------------------------------------------------------
207
208/// Outcome of comparing two keys for divergence starting from a given bit
209/// position. `from` lets callers skip already-confirmed-matching prefixes.
210enum DivergeResult {
211 /// The keys are identical (same bit count, same content).
212 Duplicate,
213 /// The keys diverge at this bit position, or one key is a prefix of the
214 /// other (position = bit count of the shorter key).
215 At(usize),
216}
217
218/// Bounded check: do the keys match from bit `from` to bit `to` (exclusive)?
219/// Returns `true` only if all bits in [from, to) are equal in both keys AND
220/// both keys are long enough to have bits in that range. If one key is a prefix
221/// of the other within [from, to), returns `false`.
222///
223/// This is the fast path for internal node descent: we only need to confirm
224/// that the new key shares the subtree prefix through the node's discriminating
225/// bit, without scanning the full key.
226#[inline]
227fn prefix_matches(key_a: &[u8], key_b: &[u8], from: usize, to: usize) -> bool {
228 // If `to` extends beyond the shorter key, one key is a prefix of the
229 // other — that's a divergence, not a match for descent.
230 if key_a.len() * 8 < to || key_b.len() * 8 < to {
231 return false;
232 }
233 // Compare byte-by-byte where possible, then bit-by-bit for the tail.
234 // Bits `from..to` span bytes from `from_byte` to `to_byte`.
235 let from_byte = from / 8;
236 let to_byte = (to + 7) / 8; // ceil(to / 8)
237 let min_len = key_a.len().min(key_b.len()).min(to_byte);
238 for i in from_byte..min_len {
239 if key_a[i] != key_b[i] {
240 // Check if the differing bit is within [from, to)
241 let xor = key_a[i] ^ key_b[i];
242 let first_diff_bit = i * 8 + xor.leading_zeros() as usize;
243 return first_diff_bit >= to;
244 }
245 }
246 true
247}
248
249/// Scan two keys from `from` onward to find the first diverging bit.
250#[inline]
251fn find_divergence(key_a: &[u8], key_b: &[u8], from: usize) -> DivergeResult {
252 let total_a = key_a.len() * 8;
253 let total_b = key_b.len() * 8;
254 let min = total_a.min(total_b);
255 let mut d = from;
256 while d < min {
257 if key_bit_at(key_a, d) != key_bit_at(key_b, d) {
258 return DivergeResult::At(d);
259 }
260 d += 1;
261 }
262 if total_a == total_b {
263 DivergeResult::Duplicate
264 } else {
265 DivergeResult::At(d)
266 }
267}
268
269/// Given two differing bytes, return the bit position of the first divergence.
270/// MSB-first: bit 0 = MSB of byte 0. The position of the first 1 bit in the
271/// XOR gives the bit index directly (since leading_zeros counts from MSB).
272#[inline]
273fn diverging_bit(xor: u8, byte_idx: usize) -> usize {
274 byte_idx * 8 + xor.leading_zeros() as usize
275}
276
277fn simd_find_divergence<const N: usize>(key_a: &[u8], key_b: &[u8], from: usize) -> DivergeResult
278{
279 let minlen = key_a.len().min(key_b.len());
280 let mut i = from / 8; // byte containing bit `from`
281
282 while i + N <= minlen {
283 let a = Simd::<u8, N>::from_slice(unsafe { key_a.get_unchecked(i..i + N) });
284 let b = Simd::<u8, N>::from_slice(unsafe { key_b.get_unchecked(i..i + N) });
285 let mask = a.simd_ne(b);
286 if mask.any() {
287 let diff_byte_idx = i + mask.first_set().unwrap();
288 let xor = unsafe { *key_a.get_unchecked(diff_byte_idx) ^ *key_b.get_unchecked(diff_byte_idx) };
289 return DivergeResult::At(diverging_bit(xor, diff_byte_idx));
290 }
291 i += N;
292 }
293
294 // Scalar tail
295 find_divergence(key_a, key_b, i * 8)
296}
297
298/// SIMD-accelerated byte equality check. Returns `true` if both slices have
299/// the same length and identical content.
300#[inline]
301fn simd_eq(a: &[u8], b: &[u8]) -> bool {
302 if a.len() != b.len() {
303 return false;
304 }
305 let len = a.len();
306 let mut i = 0;
307 while i + 16 <= len {
308 let va = Simd::<u8, 16>::from_slice(unsafe { a.get_unchecked(i..i + 16) });
309 let vb = Simd::<u8, 16>::from_slice(unsafe { b.get_unchecked(i..i + 16) });
310 if va.simd_ne(vb).any() {
311 return false;
312 }
313 i += 16;
314 }
315 // Scalar tail
316 while i < len {
317 if unsafe { *a.get_unchecked(i) != *b.get_unchecked(i) } {
318 return false;
319 }
320 i += 1;
321 }
322 true
323}
324
325// ---------------------------------------------------------------------------
326// Bit helpers
327// ---------------------------------------------------------------------------
328
329/// Extract bit at absolute position `idx` from `key`. MSB-first ordering:
330/// bit 0 = MSB of byte 0, bit 7 = LSB of byte 0, bit 8 = MSB of byte 1, etc.
331/// Past the end of the key, returns 0 (implicit null terminator for ordering:
332/// shorter keys sort before longer keys that extend them).
333#[inline]
334fn key_bit_at(key: &[u8], idx: usize) -> u8 {
335 let byte_idx = idx / 8;
336 if byte_idx < key.len() {
337 (key[byte_idx] >> (7 - idx % 8)) & 1
338 } else {
339 0
340 }
341}
342
343// ---------------------------------------------------------------------------
344// BitTrie implementation
345// ---------------------------------------------------------------------------
346
347impl<K: TrieKey, V> BitTrie<K, V> {
348 pub fn new() -> Self {
349 BitTrie {
350 arena: Vec::new(),
351 keys: K::Store::default(),
352 values: Vec::new(),
353 root_prefix_len: 0,
354 }
355 }
356
357 pub fn len(&self) -> usize {
358 self.keys.len()
359 }
360
361 pub fn is_empty(&self) -> bool {
362 self.keys.len() == 0
363 }
364
365 // -----------------------------------------------------------------------
366 // Lookup
367 // -----------------------------------------------------------------------
368
369 #[inline]
370 pub fn get_index(&self, key: &[u8]) -> Option<usize> {
371 if self.arena.is_empty() {
372 return None;
373 }
374 let max_bits = key.len() * 8;
375 let mut node_idx: u32 = 0;
376 let mut prefix_len = self.root_prefix_len as usize;
377
378 loop {
379 let node = &self.arena[node_idx as usize];
380
381 // Key bits exhausted — check if this node is terminal
382 if prefix_len >= max_bits {
383 if node.is_terminal() {
384 let ki = node.leaf_key_index_val();
385 let key_in_buf = self.keys.key_bytes(ki);
386 if simd_eq(key_in_buf, key) {
387 return Some(ki as usize);
388 }
389 }
390 return None;
391 }
392
393 let bit = key_bit_at(key, prefix_len) as usize;
394 let child = node.children[bit];
395
396 // Empty child slot — no match
397 if child == 0 {
398 return None;
399 }
400
401 if child & LEAF_BIT != 0 {
402 // Leaf — verify full key match
403 let ki = child & !LEAF_BIT;
404 return if simd_eq(self.keys.key_bytes(ki), key) {
405 Some(ki as usize)
406 } else {
407 None
408 };
409 }
410
411 // Internal node — descend
412 prefix_len = node.prefix_lens[bit] as usize;
413 node_idx = child;
414 }
415 }
416
417 pub fn get(&self, key: &[u8]) -> Option<&V> {
418 self.get_index(key).map(|idx| &self.values[idx - 1])
419 }
420
421 pub fn get_mut(&mut self, key: &[u8]) -> Option<&mut V> {
422 self.get_index(key).map(|idx| &mut self.values[idx - 1])
423 }
424
425 // -----------------------------------------------------------------------
426 // Insertion
427 // -----------------------------------------------------------------------
428
429 pub fn insert(&mut self, key: K, value: V) -> Result<usize, ()> {
430 // No null byte rejection — 0x00 bytes are valid in keys.
431
432 let new_index = self.keys.push(key);
433 self.values.push(value);
434
435 let new_key = self.keys.key_bytes(new_index);
436 let max_bits = new_key.len() * 8;
437
438 if self.arena.is_empty() {
439 if max_bits == 0 {
440 // Empty key — root node itself is terminal
441 let mut root = Node::new();
442 root.set_terminal(true);
443 root.set_leaf_key_index(new_index);
444 self.arena.push(root);
445 self.root_prefix_len = 0;
446 return Ok(new_index as usize);
447 }
448 // First key: create root at bit 0
449 let first_bit = key_bit_at(new_key, 0) as usize;
450 let mut root = Node::new();
451 root.set_leaf_child(first_bit, new_index, max_bits as u16);
452 root.set_leaf_key_index(new_index);
453 self.arena.push(root);
454 self.root_prefix_len = 0;
455 return Ok(new_index as usize);
456 }
457
458 let mut node_idx: u32 = 0;
459 let mut confirmed: usize = 0;
460 let mut prefix_len = self.root_prefix_len as usize;
461 // Track parent so we can update prefix_lens when a node is split.
462 // parent_info = (parent_arena_index, which_child_bit)
463 let mut parent_info: Option<(u32, usize)> = None;
464
465 loop {
466 let node = &self.arena[node_idx as usize];
467 // Use leaf field for reference key (O(1), no find_any_leaf)
468 let ref_ki = node.leaf_key_index_val();
469 let ref_key = self.keys.key_bytes(ref_ki);
470
471 // Fast path: bounded comparison from confirmed to prefix_len.
472 // We only need to know if the new key matches the reference key
473 // through this node's discriminating bit position.
474 if prefix_matches(new_key, ref_key, confirmed, prefix_len) {
475 // Keys match from confirmed to prefix_len — descend or handle
476 // terminal/empty/leaf cases.
477
478 // Check if the new key is a prefix that ends at this node
479 if max_bits <= prefix_len {
480 // Key bits exhausted at this node — mark terminal
481 self.arena[node_idx as usize].set_terminal(true);
482 self.arena[node_idx as usize].set_leaf_key_index(new_index);
483 return Ok(new_index as usize);
484 }
485
486 let bit = key_bit_at(new_key, prefix_len) as usize;
487 let child = node.children[bit];
488
489 // Empty child slot — insert leaf directly
490 if child == 0 {
491 self.arena[node_idx as usize]
492 .set_leaf_child(bit, new_index, max_bits as u16);
493 return Ok(new_index as usize);
494 }
495
496 if child & LEAF_BIT != 0 {
497 // Leaf child — need full divergence scan for the split
498 let existing_ki = child & !LEAF_BIT;
499 let existing_key = self.keys.key_bytes(existing_ki);
500 let existing_prefix = node.prefix_lens[bit];
501
502 match simd_find_divergence::<8>(new_key, existing_key, confirmed) {
503 DivergeResult::Duplicate => {
504 // Should not happen — caught above via prefix_matches
505 self.keys.rollback();
506 let _ = self.values.pop();
507 return Err(());
508 }
509 DivergeResult::At(d) => {
510 let mut split_node = Node::new();
511
512 if d >= max_bits {
513 // New key ends at the split point — terminal
514 let exist_bit = key_bit_at(existing_key, d) as usize;
515 split_node.set_terminal(true);
516 split_node.set_leaf_key_index(new_index);
517 split_node.set_leaf_child(exist_bit, existing_ki, existing_prefix);
518 } else if d >= existing_key.len() * 8 {
519 // Existing key ends at the split point — terminal
520 let new_child_bit = key_bit_at(new_key, d) as usize;
521 split_node.set_terminal(true);
522 split_node.set_leaf_key_index(existing_ki);
523 split_node.set_leaf_child(new_child_bit, new_index, max_bits as u16);
524 } else {
525 // Neither key ends at the split point
526 let new_child_bit = key_bit_at(new_key, d) as usize;
527 let exist_bit = key_bit_at(existing_key, d) as usize;
528 debug_assert_ne!(new_child_bit, exist_bit);
529 split_node.set_leaf_child(new_child_bit, new_index, max_bits as u16);
530 split_node.set_leaf_child(exist_bit, existing_ki, existing_prefix);
531 split_node.set_leaf_key_index(existing_ki);
532 }
533
534 let split_idx = self.arena.len() as u32;
535 self.arena.push(split_node);
536 self.arena[node_idx as usize]
537 .set_internal_child(bit, split_idx, d as u16);
538 }
539 }
540 return Ok(new_index as usize);
541 }
542
543 // Internal child — descend
544 confirmed = prefix_len + 1;
545 parent_info = Some((node_idx, bit));
546 prefix_len = node.prefix_lens[bit] as usize;
547 node_idx = child;
548 } else {
549 // Keys diverge before prefix_len — need the exact divergence
550 // point for a node split. Full scan from confirmed.
551 match simd_find_divergence::<8>(new_key, ref_key, confirmed) {
552 DivergeResult::Duplicate => {
553 // Duplicate key — roll back
554 self.keys.rollback();
555 let _ = self.values.pop();
556 return Err(());
557 }
558 DivergeResult::At(diverge) => {
559 // Divergence before this node's discriminating bit —
560 // create a new parent at the divergence point.
561 debug_assert!(diverge < prefix_len, "prefix_matches said diverge but simd found no divergence before prefix_len");
562 let new_bit = key_bit_at(new_key, diverge) as usize;
563 let ref_bit = key_bit_at(ref_key, diverge) as usize;
564
565 let mut new_parent = Node::new();
566 new_parent.prefix_lens[ref_bit] = prefix_len as u16; // old node's prefix_len
567
568 if diverge >= max_bits {
569 // New key ends at the split point — terminal
570 new_parent.set_terminal(true);
571 new_parent.set_leaf_key_index(new_index);
572 } else {
573 new_parent.set_leaf_child(new_bit, new_index, max_bits as u16);
574 new_parent.set_leaf_key_index(new_index);
575 }
576
577 let old_node = std::mem::replace(
578 &mut self.arena[node_idx as usize],
579 new_parent,
580 );
581 let old_idx = self.arena.len() as u32;
582 self.arena.push(old_node);
583
584 // Wire old node as internal child of new parent
585 self.arena[node_idx as usize]
586 .set_internal_child(ref_bit, old_idx, prefix_len as u16);
587
588 // Update parent's prefix_lens to reflect the new prefix_len
589 if let Some((pidx, pbit)) = parent_info {
590 self.arena[pidx as usize].prefix_lens[pbit] = diverge as u16;
591 } else {
592 // We split the root
593 self.root_prefix_len = diverge as u16;
594 }
595
596 return Ok(new_index as usize);
597 }
598 }
599 }
600 }
601 }
602
603 // -----------------------------------------------------------------------
604 // Iteration
605 // -----------------------------------------------------------------------
606
607 pub fn iter(&self) -> Cursor<'_, K, V> {
608 Cursor::new(self)
609 }
610
611 pub fn iter_last(&self) -> Cursor<'_, K, V> {
612 Cursor::new_last(self)
613 }
614
615 /// Public forward mutable cursor: a lending tree-walk that hands out `&mut V`
616 /// borrows tied to the cursor (see [`CursorMut`]). Parked *before* the first
617 /// key — call `next()`/`first()` to position.
618 pub fn iter_mut(&mut self) -> CursorMut<'_, K, V> {
619 CursorMut::new(self)
620 }
621
622 /// Public reverse mutable cursor: a lending tree-walk parked *on* the last
623 /// key (see [`CursorMut`]).
624 pub fn iter_mut_last(&mut self) -> CursorMut<'_, K, V> {
625 CursorMut::new_last(self)
626 }
627
628 pub fn into_keys_values(self) -> (Vec<K>, Vec<V>) {
629 let keys = self.keys.into_keys();
630 (keys, self.values)
631 }
632}
633
634impl<K: TrieKey, V> Default for BitTrie<K, V> {
635 fn default() -> Self {
636 Self::new()
637 }
638}
639
640// ---------------------------------------------------------------------------
641// Iterator
642// ---------------------------------------------------------------------------
643
644pub struct Cursor<'a, K: TrieKey, V> {
645 trie: &'a BitTrie<K, V>,
646 /// Stack of (arena_index, which_child) pairs.
647 ///
648 /// - `arena_idx`: index into the arena (which node)
649 /// - `which_child`: 0 or 1 for child slots, `TERMINAL_POS` (2) for
650 /// the terminal value, `u8::MAX` as a sentinel meaning "before first".
651 stack: Vec<(u32, u8)>,
652}
653
654impl<'a, K: TrieKey, V> Cursor<'a, K, V> {
655 fn new(trie: &'a BitTrie<K, V>) -> Self {
656 if trie.arena.is_empty() {
657 return Cursor { trie, stack: Vec::new() };
658 }
659 Cursor { trie, stack: vec![(0, u8::MAX)] }
660 }
661
662 fn new_last(trie: &'a BitTrie<K, V>) -> Self {
663 if trie.arena.is_empty() {
664 return Cursor { trie, stack: Vec::new() };
665 }
666 let mut iter = Cursor { trie, stack: Vec::new() };
667 iter.descend_last(0);
668 iter
669 }
670
671 /// Descend from internal node `idx` to its leftmost position.
672 /// If the first node encountered is terminal, position at its terminal value.
673 /// Otherwise find the leftmost child.
674 fn descend_first(&mut self, mut idx: u32) {
675 loop {
676 let node = &self.trie.arena[idx as usize];
677 if node.is_terminal() {
678 self.stack.push((idx, TERMINAL_POS));
679 return;
680 }
681 // Find leftmost non-empty child
682 if !node.is_empty(0) {
683 self.stack.push((idx, 0));
684 if node.is_leaf(0) {
685 return;
686 } else {
687 idx = node.child_index(0);
688 continue;
689 }
690 }
691 if !node.is_empty(1) {
692 self.stack.push((idx, 1));
693 if node.is_leaf(1) {
694 return;
695 } else {
696 idx = node.child_index(1);
697 continue;
698 }
699 }
700 // No children and not terminal — shouldn't happen in valid trie
701 return;
702 }
703 }
704
705 /// Descend from internal node `idx` to its rightmost position.
706 fn descend_last(&mut self, mut idx: u32) {
707 loop {
708 let node = &self.trie.arena[idx as usize];
709 // Try rightmost child first
710 if !node.is_empty(1) {
711 self.stack.push((idx, 1));
712 if node.is_leaf(1) {
713 return;
714 } else {
715 idx = node.child_index(1);
716 continue;
717 }
718 }
719 if !node.is_empty(0) {
720 self.stack.push((idx, 0));
721 if node.is_leaf(0) {
722 return;
723 } else {
724 idx = node.child_index(0);
725 continue;
726 }
727 }
728 // No children — terminal only
729 if node.is_terminal() {
730 self.stack.push((idx, TERMINAL_POS));
731 }
732 return;
733 }
734 }
735
736 /// Return the key and value at the current cursor position.
737 pub fn current(&self) -> Option<(&[u8], &V)> {
738 let ki = self.current_index()?;
739 let key = self.trie.keys.key_bytes(ki as u32);
740 let value = &self.trie.values[ki - 1];
741 Some((key, value))
742 }
743
744 /// Return just the key index at the current cursor position, skipping
745 /// key buffer and value reads. Useful when only the position matters.
746 pub fn current_index(&self) -> Option<usize> {
747 let &(arena_idx, which) = self.stack.last()?;
748 if which == u8::MAX {
749 return None;
750 }
751 let node = &self.trie.arena[arena_idx as usize];
752 if which == TERMINAL_POS {
753 Some(node.leaf_key_index_val() as usize)
754 } else {
755 node.leaf_key_index(which as usize).map(|ki| ki as usize)
756 }
757 }
758
759 /// Advance cursor to the next position. Returns `true` if positioned,
760 /// `false` if exhausted. Shared navigation for `next` and `next_index`.
761 #[inline]
762 fn advance_next(&mut self) -> bool {
763 loop {
764 let (arena_idx, which) = match self.stack.pop() {
765 Some(v) => v,
766 None => return false,
767 };
768
769 if which == TERMINAL_POS {
770 // After terminal — try children in order (bit 0, then bit 1)
771 let node = &self.trie.arena[arena_idx as usize];
772 if !node.is_empty(0) {
773 self.stack.push((arena_idx, 0));
774 if node.is_leaf(0) {
775 return true;
776 } else {
777 self.descend_first(node.child_index(0));
778 return true;
779 }
780 }
781 if !node.is_empty(1) {
782 self.stack.push((arena_idx, 1));
783 if node.is_leaf(1) {
784 return true;
785 } else {
786 self.descend_first(node.child_index(1));
787 return true;
788 }
789 }
790 // Terminal-only node with no children — pop up
791 continue;
792 }
793
794 if which == u8::MAX {
795 // Before-first — position at first entry
796 let node = &self.trie.arena[arena_idx as usize];
797 if node.is_terminal() {
798 self.stack.push((arena_idx, TERMINAL_POS));
799 return true;
800 }
801 for bit in 0..2u8 {
802 if !node.is_empty(bit as usize) {
803 self.stack.push((arena_idx, bit));
804 if node.is_leaf(bit as usize) {
805 return true;
806 } else {
807 self.descend_first(node.child_index(bit as usize));
808 return true;
809 }
810 }
811 }
812 continue;
813 }
814
815 // After child `which` — try the next child or pop up
816 let search_bit = which as usize + 1;
817 if search_bit < 2 {
818 let node = &self.trie.arena[arena_idx as usize];
819 if !node.is_empty(search_bit) {
820 self.stack.push((arena_idx, search_bit as u8));
821 if node.is_leaf(search_bit) {
822 return true;
823 } else {
824 self.descend_first(node.child_index(search_bit));
825 return true;
826 }
827 }
828 }
829 // No next child at this level — pop up
830 }
831 }
832
833 /// Advance cursor to the previous position. Returns `true` if positioned,
834 /// `false` if exhausted. Shared navigation for `prev` and `prev_index`.
835 #[inline]
836 fn advance_prev(&mut self) -> bool {
837 loop {
838 let (arena_idx, which) = match self.stack.pop() {
839 Some(v) => v,
840 None => return false,
841 };
842
843 if which == TERMINAL_POS {
844 // Before terminal in forward order = after terminal in backward.
845 // Going backward from terminal means going to parent's previous sibling.
846 continue;
847 }
848
849 if which == u8::MAX {
850 continue;
851 }
852
853 let bit = which as usize;
854
855 // Try the previous sibling
856 if bit > 0 {
857 let prev_bit = bit - 1;
858 let node = &self.trie.arena[arena_idx as usize];
859 if !node.is_empty(prev_bit) {
860 self.stack.push((arena_idx, prev_bit as u8));
861 if node.is_leaf(prev_bit) {
862 return true;
863 } else {
864 self.descend_last(node.child_index(prev_bit));
865 return true;
866 }
867 }
868 }
869
870 // No previous sibling — check if this node is terminal.
871 // In backward order, terminal comes before children in forward,
872 // which means after children in backward.
873 if bit == 0 {
874 let node = &self.trie.arena[arena_idx as usize];
875 if node.is_terminal() {
876 self.stack.push((arena_idx, TERMINAL_POS));
877 return true;
878 }
879 }
880
881 // Pop up to parent
882 }
883 }
884
885 /// Advance to the next key in sorted order, returning key and value.
886 #[inline]
887 pub fn next(&mut self) -> Option<(&[u8], &V)> {
888 if self.advance_next() { self.current() } else { None }
889 }
890
891 /// Move to the previous key in sorted order, returning key and value.
892 #[inline]
893 pub fn prev(&mut self) -> Option<(&[u8], &V)> {
894 if self.advance_prev() { self.current() } else { None }
895 }
896
897 /// Advance to the next key, returning only its index.
898 #[inline]
899 pub fn next_index(&mut self) -> Option<usize> {
900 if self.advance_next() { self.current_index() } else { None }
901 }
902
903 /// Move to the previous key, returning only its index.
904 #[inline]
905 pub fn prev_index(&mut self) -> Option<usize> {
906 if self.advance_prev() { self.current_index() } else { None }
907 }
908
909 pub fn seek(&mut self, key: &[u8]) -> Option<(&[u8], &V)> {
910 if self.trie.arena.is_empty() {
911 self.stack.clear();
912 return None;
913 }
914
915 self.stack.clear();
916 let mut node_idx: u32 = 0;
917 let mut prefix_len = self.trie.root_prefix_len as usize;
918 let max_bits = key.len() * 8;
919
920 loop {
921 let node = &self.trie.arena[node_idx as usize];
922
923 // Check if key is exhausted at this node
924 if prefix_len >= max_bits {
925 if node.is_terminal() {
926 self.stack.push((node_idx, TERMINAL_POS));
927 return self.current();
928 }
929 // Key exhausted but node not terminal — find first child
930 for bit in 0..2u8 {
931 if !node.is_empty(bit as usize) {
932 self.stack.push((node_idx, bit));
933 if node.is_leaf(bit as usize) {
934 return self.current();
935 } else {
936 self.descend_first(node.child_index(bit as usize));
937 return self.current();
938 }
939 }
940 }
941 // No children — need to advance forward
942 return self.next();
943 }
944
945 let bit = key_bit_at(key, prefix_len) as usize;
946 let child = node.children[bit];
947
948 if child != 0 {
949 self.stack.push((node_idx, bit as u8));
950 if child & LEAF_BIT != 0 {
951 // Leaf — check if leaf key >= seek key
952 let ki = child & !LEAF_BIT;
953 let leaf_key = self.trie.keys.key_bytes(ki);
954 if leaf_key >= key {
955 return self.current();
956 }
957 // Leaf key < seek key — advance past it
958 return self.next();
959 } else {
960 // Internal — descend
961 prefix_len = node.prefix_lens[bit] as usize;
962 node_idx = child;
963 continue;
964 }
965 }
966
967 // No child at this bit — try the other bit (higher)
968 let other_bit = 1 - bit;
969 let other_child = node.children[other_bit];
970 if other_child != 0 && other_bit > bit {
971 self.stack.push((node_idx, other_bit as u8));
972 if other_child & LEAF_BIT != 0 {
973 return self.current();
974 } else {
975 self.descend_first(other_child);
976 return self.current();
977 }
978 }
979
980 // Check terminal before trying to go up
981 if node.is_terminal() && bit == 0 {
982 // Terminal key at this node — is it >= seek key?
983 let ki = node.leaf_key_index_val();
984 let term_key = self.trie.keys.key_bytes(ki);
985 if term_key >= key {
986 self.stack.push((node_idx, TERMINAL_POS));
987 return self.current();
988 }
989 }
990
991 // No higher child at this level — backtrack
992 loop {
993 let (parent_idx, parent_bit) = self.stack.pop()?;
994 if parent_bit == TERMINAL_POS || parent_bit == u8::MAX {
995 // After terminal or before-first — try children from parent
996 let parent = &self.trie.arena[parent_idx as usize];
997 for next_bit in 0..2u8 {
998 if !parent.is_empty(next_bit as usize) {
999 self.stack.push((parent_idx, next_bit));
1000 if parent.is_leaf(next_bit as usize) {
1001 return self.current();
1002 } else {
1003 self.descend_first(parent.child_index(next_bit as usize));
1004 return self.current();
1005 }
1006 }
1007 }
1008 continue;
1009 }
1010 if parent_bit == 0 {
1011 // We came from child[0], try child[1]
1012 let parent = &self.trie.arena[parent_idx as usize];
1013 if !parent.is_empty(1) {
1014 self.stack.push((parent_idx, 1));
1015 if parent.is_leaf(1) {
1016 return self.current();
1017 } else {
1018 self.descend_first(parent.child_index(1));
1019 return self.current();
1020 }
1021 }
1022 }
1023 // Continue backtracking
1024 }
1025 }
1026 }
1027}
1028
1029// ---------------------------------------------------------------------------
1030// CursorMut — lending tree-walk iterator handing out &mut V
1031// ---------------------------------------------------------------------------
1032
1033/// Mutable counterpart to [`Cursor`]: a tree-walk iterator that lends out
1034/// `&mut V` borrows over the stored values, in sorted (DFS) key order.
1035///
1036/// Unlike [`Cursor`], the value reference is tied to `&mut self` (a *lending*
1037/// cursor), not to the trie lifetime `'a`. This is a soundness requirement, not
1038/// a stylistic choice: a cursor is re-positionable — `current()`, `seek()`,
1039/// `first()`, `last()` can all revisit a slot already visited. An `'a`-tied
1040/// `&mut V` (as the immutable cursor hands out `&'a V`) would let two such
1041/// calls return `&mut V` to the *same* element simultaneously — aliasing
1042/// undefined behavior. Tying the borrow to `&mut self` makes the borrow checker
1043/// enforce "one live `&mut V` at a time," which is the only sound rule for a
1044/// re-positionable mutable cursor. The practical consequence: you cannot
1045/// collect the `&mut V` into a `Vec` or hold two at once; each must be released
1046/// before the next `next()`/`prev()`/`current()`/`seek()` call. In-place
1047/// mutation loops (`while let Some((k, v)) = c.next() { *v += 1; }`) work as
1048/// expected.
1049///
1050/// The key is returned as `&[u8]` borrowing the trie's key store (zero
1051/// allocation, matching the immutable cursor's borrowed key). Both the key and
1052/// the `&mut V` are tied to `&mut self`. Only the stored *value* is mutated;
1053/// the cursor never alters key bytes, node structure, or slot occupancy, so
1054/// trie invariants are preserved.
1055pub struct CursorMut<'a, K: TrieKey, V> {
1056 trie: &'a mut BitTrie<K, V>,
1057 /// Stack of (arena_index, which_child) pairs — same shape as
1058 /// [`Cursor::stack`].
1059 stack: Vec<(u32, u8)>,
1060}
1061
1062impl<'a, K: TrieKey, V> CursorMut<'a, K, V> {
1063 /// Forward mutable cursor parked *before* the first key.
1064 pub fn new(trie: &'a mut BitTrie<K, V>) -> Self {
1065 if trie.arena.is_empty() {
1066 return CursorMut { trie, stack: Vec::new() };
1067 }
1068 CursorMut { trie, stack: vec![(0, u8::MAX)] }
1069 }
1070
1071 /// Reverse mutable cursor parked *on* the last key (or empty if the trie is
1072 /// empty).
1073 pub fn new_last(trie: &'a mut BitTrie<K, V>) -> Self {
1074 let mut c = CursorMut { trie, stack: Vec::new() };
1075 c.last();
1076 c
1077 }
1078
1079 fn descend_first(&mut self, mut idx: u32) {
1080 loop {
1081 let node = &self.trie.arena[idx as usize];
1082 if node.is_terminal() {
1083 self.stack.push((idx, TERMINAL_POS));
1084 return;
1085 }
1086 if !node.is_empty(0) {
1087 self.stack.push((idx, 0));
1088 if node.is_leaf(0) {
1089 return;
1090 } else {
1091 idx = node.child_index(0);
1092 continue;
1093 }
1094 }
1095 if !node.is_empty(1) {
1096 self.stack.push((idx, 1));
1097 if node.is_leaf(1) {
1098 return;
1099 } else {
1100 idx = node.child_index(1);
1101 continue;
1102 }
1103 }
1104 return;
1105 }
1106 }
1107
1108 fn descend_last(&mut self, mut idx: u32) {
1109 loop {
1110 let node = &self.trie.arena[idx as usize];
1111 if !node.is_empty(1) {
1112 self.stack.push((idx, 1));
1113 if node.is_leaf(1) {
1114 return;
1115 } else {
1116 idx = node.child_index(1);
1117 continue;
1118 }
1119 }
1120 if !node.is_empty(0) {
1121 self.stack.push((idx, 0));
1122 if node.is_leaf(0) {
1123 return;
1124 } else {
1125 idx = node.child_index(0);
1126 continue;
1127 }
1128 }
1129 if node.is_terminal() {
1130 self.stack.push((idx, TERMINAL_POS));
1131 }
1132 return;
1133 }
1134 }
1135
1136 /// The key/value the cursor is parked on, or `None` if not parked (before
1137 /// first, or exhausted). The key borrows the trie's key store and the
1138 /// `&mut V` reborrows the stored value — both tied to `&mut self`.
1139 ///
1140 /// `keys` and `values` are disjoint fields of the trie, so the shared key
1141 /// borrow (via `key_bytes`) and the mutable value borrow coexist without
1142 /// aliasing.
1143 #[inline]
1144 pub fn current(&mut self) -> Option<(&[u8], &mut V)> {
1145 let ki = self.current_index()?;
1146 let key = self.trie.keys.key_bytes(ki as u32);
1147 let value = &mut self.trie.values[ki - 1];
1148 Some((key, value))
1149 }
1150
1151 /// The key index the cursor is parked on, or `None` if not parked.
1152 #[inline]
1153 pub fn current_index(&self) -> Option<usize> {
1154 let &(arena_idx, which) = self.stack.last()?;
1155 if which == u8::MAX {
1156 return None;
1157 }
1158 let node = &self.trie.arena[arena_idx as usize];
1159 if which == TERMINAL_POS {
1160 Some(node.leaf_key_index_val() as usize)
1161 } else {
1162 node.leaf_key_index(which as usize).map(|ki| ki as usize)
1163 }
1164 }
1165
1166 #[inline]
1167 fn advance_next(&mut self) -> bool {
1168 loop {
1169 let (arena_idx, which) = match self.stack.pop() {
1170 Some(v) => v,
1171 None => return false,
1172 };
1173
1174 if which == TERMINAL_POS {
1175 let node = &self.trie.arena[arena_idx as usize];
1176 if !node.is_empty(0) {
1177 self.stack.push((arena_idx, 0));
1178 if node.is_leaf(0) {
1179 return true;
1180 } else {
1181 self.descend_first(node.child_index(0));
1182 return true;
1183 }
1184 }
1185 if !node.is_empty(1) {
1186 self.stack.push((arena_idx, 1));
1187 if node.is_leaf(1) {
1188 return true;
1189 } else {
1190 self.descend_first(node.child_index(1));
1191 return true;
1192 }
1193 }
1194 continue;
1195 }
1196
1197 if which == u8::MAX {
1198 let node = &self.trie.arena[arena_idx as usize];
1199 if node.is_terminal() {
1200 self.stack.push((arena_idx, TERMINAL_POS));
1201 return true;
1202 }
1203 for bit in 0..2u8 {
1204 if !node.is_empty(bit as usize) {
1205 self.stack.push((arena_idx, bit));
1206 if node.is_leaf(bit as usize) {
1207 return true;
1208 } else {
1209 self.descend_first(node.child_index(bit as usize));
1210 return true;
1211 }
1212 }
1213 }
1214 continue;
1215 }
1216
1217 let search_bit = which as usize + 1;
1218 if search_bit < 2 {
1219 let node = &self.trie.arena[arena_idx as usize];
1220 if !node.is_empty(search_bit) {
1221 self.stack.push((arena_idx, search_bit as u8));
1222 if node.is_leaf(search_bit) {
1223 return true;
1224 } else {
1225 self.descend_first(node.child_index(search_bit));
1226 return true;
1227 }
1228 }
1229 }
1230 }
1231 }
1232
1233 #[inline]
1234 fn advance_prev(&mut self) -> bool {
1235 loop {
1236 let (arena_idx, which) = match self.stack.pop() {
1237 Some(v) => v,
1238 None => return false,
1239 };
1240
1241 if which == TERMINAL_POS {
1242 continue;
1243 }
1244
1245 if which == u8::MAX {
1246 continue;
1247 }
1248
1249 let bit = which as usize;
1250
1251 if bit > 0 {
1252 let prev_bit = bit - 1;
1253 let node = &self.trie.arena[arena_idx as usize];
1254 if !node.is_empty(prev_bit) {
1255 self.stack.push((arena_idx, prev_bit as u8));
1256 if node.is_leaf(prev_bit) {
1257 return true;
1258 } else {
1259 self.descend_last(node.child_index(prev_bit));
1260 return true;
1261 }
1262 }
1263 }
1264
1265 if bit == 0 {
1266 let node = &self.trie.arena[arena_idx as usize];
1267 if node.is_terminal() {
1268 self.stack.push((arena_idx, TERMINAL_POS));
1269 return true;
1270 }
1271 }
1272 }
1273 }
1274
1275 /// Jump to the first key (smallest in sorted order). Returns its key/value,
1276 /// or `None` if the trie is empty.
1277 pub fn first(&mut self) -> Option<(&[u8], &mut V)> {
1278 if self.trie.arena.is_empty() {
1279 self.stack.clear();
1280 return None;
1281 }
1282 self.stack.clear();
1283 self.stack.push((0, u8::MAX));
1284 if self.advance_next() { self.current() } else { None }
1285 }
1286
1287 /// Jump to the last key (largest in sorted order). Returns its key/value,
1288 /// or `None` if the trie is empty.
1289 pub fn last(&mut self) -> Option<(&[u8], &mut V)> {
1290 if self.trie.arena.is_empty() {
1291 self.stack.clear();
1292 return None;
1293 }
1294 self.stack.clear();
1295 self.descend_last(0);
1296 self.current()
1297 }
1298
1299 #[inline]
1300 pub fn next(&mut self) -> Option<(&[u8], &mut V)> {
1301 if self.advance_next() { self.current() } else { None }
1302 }
1303
1304 #[inline]
1305 pub fn prev(&mut self) -> Option<(&[u8], &mut V)> {
1306 if self.advance_prev() { self.current() } else { None }
1307 }
1308
1309 #[inline]
1310 pub fn next_index(&mut self) -> Option<usize> {
1311 if self.advance_next() { self.current_index() } else { None }
1312 }
1313
1314 #[inline]
1315 pub fn prev_index(&mut self) -> Option<usize> {
1316 if self.advance_prev() { self.current_index() } else { None }
1317 }
1318
1319 pub fn seek(&mut self, key: &[u8]) -> Option<(&[u8], &mut V)> {
1320 if self.trie.arena.is_empty() {
1321 self.stack.clear();
1322 return None;
1323 }
1324
1325 self.stack.clear();
1326 let mut node_idx: u32 = 0;
1327 let mut prefix_len = self.trie.root_prefix_len as usize;
1328 let max_bits = key.len() * 8;
1329
1330 loop {
1331 let node = &self.trie.arena[node_idx as usize];
1332
1333 if prefix_len >= max_bits {
1334 if node.is_terminal() {
1335 self.stack.push((node_idx, TERMINAL_POS));
1336 return self.current();
1337 }
1338 for bit in 0..2u8 {
1339 if !node.is_empty(bit as usize) {
1340 self.stack.push((node_idx, bit));
1341 if node.is_leaf(bit as usize) {
1342 return self.current();
1343 } else {
1344 self.descend_first(node.child_index(bit as usize));
1345 return self.current();
1346 }
1347 }
1348 }
1349 return self.next();
1350 }
1351
1352 let bit = key_bit_at(key, prefix_len) as usize;
1353 let child = node.children[bit];
1354
1355 if child != 0 {
1356 self.stack.push((node_idx, bit as u8));
1357 if child & LEAF_BIT != 0 {
1358 let ki = child & !LEAF_BIT;
1359 let leaf_key = self.trie.keys.key_bytes(ki);
1360 if leaf_key >= key {
1361 return self.current();
1362 }
1363 return self.next();
1364 } else {
1365 prefix_len = node.prefix_lens[bit] as usize;
1366 node_idx = child;
1367 continue;
1368 }
1369 }
1370
1371 let other_bit = 1 - bit;
1372 let other_child = node.children[other_bit];
1373 if other_child != 0 && other_bit > bit {
1374 self.stack.push((node_idx, other_bit as u8));
1375 if other_child & LEAF_BIT != 0 {
1376 return self.current();
1377 } else {
1378 self.descend_first(other_child);
1379 return self.current();
1380 }
1381 }
1382
1383 if node.is_terminal() && bit == 0 {
1384 let ki = node.leaf_key_index_val();
1385 let term_key = self.trie.keys.key_bytes(ki);
1386 if term_key >= key {
1387 self.stack.push((node_idx, TERMINAL_POS));
1388 return self.current();
1389 }
1390 }
1391
1392 loop {
1393 let (parent_idx, parent_bit) = self.stack.pop()?;
1394 if parent_bit == TERMINAL_POS || parent_bit == u8::MAX {
1395 let parent = &self.trie.arena[parent_idx as usize];
1396 for next_bit in 0..2u8 {
1397 if !parent.is_empty(next_bit as usize) {
1398 self.stack.push((parent_idx, next_bit));
1399 if parent.is_leaf(next_bit as usize) {
1400 return self.current();
1401 } else {
1402 self.descend_first(parent.child_index(next_bit as usize));
1403 return self.current();
1404 }
1405 }
1406 }
1407 continue;
1408 }
1409 if parent_bit == 0 {
1410 let parent = &self.trie.arena[parent_idx as usize];
1411 if !parent.is_empty(1) {
1412 self.stack.push((parent_idx, 1));
1413 if parent.is_leaf(1) {
1414 return self.current();
1415 } else {
1416 self.descend_first(parent.child_index(1));
1417 return self.current();
1418 }
1419 }
1420 }
1421 }
1422 }
1423 }
1424}
1425
1426// ---------------------------------------------------------------------------
1427// Tests
1428// ---------------------------------------------------------------------------
1429
1430#[cfg(test)]
1431#[path = "tests/bit_trie.rs"]
1432mod tests;