1use alloc::vec::Vec;
4use core::ops::RangeBounds;
5
6use crate::iter::Iter;
7use crate::node::Node;
8use crate::ops;
9use crate::store::{InMemoryStore, NodeId, NodeStore};
10
11const MIN_ORDER: usize = 3;
14
15const DEFAULT_ORDER: usize = 64;
19
20pub struct BPlusTree<K, V> {
53 root: NodeId,
55 store: InMemoryStore<K, V>,
57 order: usize,
60 len: usize,
62}
63
64impl<K, V> BPlusTree<K, V> {
65 #[must_use]
76 pub fn new() -> Self {
77 Self::with_order(DEFAULT_ORDER)
78 }
79
80 #[must_use]
86 pub(crate) fn with_order(order: usize) -> Self {
87 let mut store = InMemoryStore::new();
88 let root = store.alloc(Node::empty_leaf());
89 BPlusTree {
90 root,
91 store,
92 order: order.max(MIN_ORDER),
93 len: 0,
94 }
95 }
96}
97
98impl<K: Ord + Clone, V> BPlusTree<K, V> {
99 #[must_use]
121 pub fn from_sorted<I: IntoIterator<Item = (K, V)>>(entries: I) -> Self {
122 Self::from_sorted_with_order(entries, DEFAULT_ORDER)
123 }
124
125 #[must_use]
127 pub(crate) fn from_sorted_with_order<I>(entries: I, order: usize) -> Self
128 where
129 I: IntoIterator<Item = (K, V)>,
130 {
131 let order = order.max(MIN_ORDER);
132 let entries: Vec<(K, V)> = entries.into_iter().collect();
133 let ascending = entries.windows(2).all(|w| w[0].0 < w[1].0);
134 if ascending {
135 let mut store = InMemoryStore::new();
136 let (root, len) = ops::bulk_load(&mut store, entries, order);
137 BPlusTree {
138 root,
139 store,
140 order,
141 len,
142 }
143 } else {
144 let mut tree = Self::with_order(order);
145 for (key, value) in entries {
146 let _previous = tree.insert(key, value);
147 }
148 tree
149 }
150 }
151}
152
153impl<K, V> BPlusTree<K, V> {
154 #[must_use]
166 #[inline]
167 pub fn len(&self) -> usize {
168 self.len
169 }
170
171 #[must_use]
184 #[inline]
185 pub fn is_empty(&self) -> bool {
186 self.len == 0
187 }
188}
189
190impl<K, V> BPlusTree<K, V> {
191 #[must_use]
210 pub fn height(&self) -> usize {
211 let mut height = 1;
212 let mut id = self.root;
213 while let Node::Internal(internal) = self.store.get(id) {
214 height += 1;
215 id = internal.children[0];
216 }
217 height
218 }
219
220 pub fn clear(&mut self) {
234 self.root = self.store.reset();
235 self.len = 0;
236 }
237
238 #[must_use]
261 pub fn iter(&self) -> Iter<'_, K, V> {
262 Iter::full(&self.store, self.root)
263 }
264}
265
266impl<K: Ord, V> BPlusTree<K, V> {
267 #[must_use]
280 #[inline]
281 pub fn get(&self, key: &K) -> Option<&V> {
282 ops::get(&self.store, self.root, key)
283 }
284
285 #[must_use]
298 #[inline]
299 pub fn contains_key(&self, key: &K) -> bool {
300 self.get(key).is_some()
301 }
302
303 #[must_use]
334 pub fn range<R: RangeBounds<K>>(&self, range: R) -> Iter<'_, K, V> {
335 Iter::range(
336 &self.store,
337 self.root,
338 range.start_bound(),
339 range.end_bound(),
340 )
341 }
342}
343
344impl<K: Ord + Clone, V> BPlusTree<K, V> {
345 pub fn insert(&mut self, key: K, value: V) -> Option<V> {
360 let (replaced, root) = ops::insert(&mut self.store, self.root, key, value, self.order);
361 self.root = root;
362 if replaced.is_none() {
363 self.len = self.len.saturating_add(1);
364 }
365 replaced
366 }
367
368 pub fn remove(&mut self, key: &K) -> Option<V> {
390 let min_keys = self.min_keys();
391 let (removed, root) = ops::remove(&mut self.store, self.root, key, min_keys);
392 self.root = root;
393 if removed.is_some() {
394 self.len -= 1;
395 }
396 removed
397 }
398
399 #[inline]
402 fn min_keys(&self) -> usize {
403 self.order.div_ceil(2) - 1
404 }
405}
406
407impl<K, V> Default for BPlusTree<K, V> {
408 fn default() -> Self {
409 Self::new()
410 }
411}
412
413impl<'a, K, V> IntoIterator for &'a BPlusTree<K, V> {
414 type Item = (&'a K, &'a V);
415 type IntoIter = Iter<'a, K, V>;
416
417 fn into_iter(self) -> Self::IntoIter {
418 self.iter()
419 }
420}
421
422#[cfg(test)]
423#[allow(clippy::unwrap_used, clippy::expect_used, reason = "test assertions")]
424mod tests {
425 use alloc::vec::Vec;
426
427 use proptest::prelude::*;
428
429 use super::*;
430
431 fn check<K: Ord + Clone + core::fmt::Debug, V>(
435 store: &InMemoryStore<K, V>,
436 id: NodeId,
437 order: usize,
438 min_keys: usize,
439 is_root: bool,
440 ) -> (K, K, usize) {
441 match store.get(id) {
442 Node::Leaf(leaf) => {
443 assert!(!leaf.keys.is_empty(), "non-root leaf is empty");
444 assert!(
445 leaf.keys.len() < order,
446 "leaf over capacity: {} >= {order}",
447 leaf.keys.len()
448 );
449 assert!(
450 is_root || leaf.keys.len() >= min_keys,
451 "non-root leaf under capacity: {} < {min_keys}",
452 leaf.keys.len()
453 );
454 assert_eq!(
455 leaf.keys.len(),
456 leaf.vals.len(),
457 "keys/vals length mismatch"
458 );
459 for w in leaf.keys.windows(2) {
460 assert!(w[0] < w[1], "leaf keys not strictly ascending");
461 }
462 (
463 leaf.keys[0].clone(),
464 leaf.keys[leaf.keys.len() - 1].clone(),
465 1,
466 )
467 }
468 Node::Internal(internal) => {
469 assert!(!internal.keys.is_empty(), "internal node has no separators");
470 assert!(
471 internal.keys.len() < order,
472 "internal node over capacity: {} >= {order}",
473 internal.keys.len()
474 );
475 assert!(
476 is_root || internal.keys.len() >= min_keys,
477 "non-root internal node under capacity: {} < {min_keys}",
478 internal.keys.len()
479 );
480 assert_eq!(
481 internal.children.len(),
482 internal.keys.len() + 1,
483 "child count must be separator count + 1"
484 );
485 for w in internal.keys.windows(2) {
486 assert!(w[0] < w[1], "separators not strictly ascending");
487 }
488
489 let mut child_height = None;
490 let mut subtree_min = None;
491 let mut last_max: Option<K> = None;
492 for (i, child) in internal.children.iter().enumerate() {
493 let (cmin, cmax, h) = check(store, *child, order, min_keys, false);
494 match child_height {
495 None => child_height = Some(h),
496 Some(prev) => assert_eq!(prev, h, "subtrees differ in height (unbalanced)"),
497 }
498 if subtree_min.is_none() {
499 subtree_min = Some(cmin.clone());
500 }
501 if i > 0 {
505 let sep = &internal.keys[i - 1];
506 assert!(
507 last_max.as_ref().is_some_and(|m| m < sep),
508 "left subtree max not below separator"
509 );
510 assert!(sep <= &cmin, "separator above right subtree's min key");
511 }
512 last_max = Some(cmax);
513 }
514 let height = child_height.map_or(1, |h| h + 1);
515 match (subtree_min, last_max) {
516 (Some(min), Some(max)) => (min, max, height),
517 _ => panic!("internal node with no children"),
518 }
519 }
520 }
521 }
522
523 fn check_tree<K: Ord + Clone + core::fmt::Debug, V>(tree: &BPlusTree<K, V>) {
525 let _bounds = check(&tree.store, tree.root, tree.order, tree.min_keys(), true);
526 }
527
528 fn collect_keys<K: Clone, V>(store: &InMemoryStore<K, V>, id: NodeId, out: &mut Vec<K>) {
530 match store.get(id) {
531 Node::Leaf(leaf) => out.extend(leaf.keys.iter().cloned()),
532 Node::Internal(internal) => {
533 for child in &internal.children {
534 collect_keys(store, *child, out);
535 }
536 }
537 }
538 }
539
540 #[test]
541 fn test_get_empty_returns_none() {
542 let tree: BPlusTree<u32, u32> = BPlusTree::new();
543 assert_eq!(tree.get(&0), None);
544 assert!(tree.is_empty());
545 assert_eq!(tree.height(), 1);
546 }
547
548 #[test]
549 fn test_insert_duplicate_key_replaces_value() {
550 let mut tree = BPlusTree::new();
551 assert_eq!(tree.insert(1_u32, "a"), None);
552 assert_eq!(tree.insert(1, "b"), Some("a"));
553 assert_eq!(tree.get(&1), Some(&"b"));
554 assert_eq!(tree.len(), 1);
555 }
556
557 #[test]
558 fn test_insert_many_splits_and_stays_balanced() {
559 let mut tree = BPlusTree::with_order(4);
560 for k in 0..256_u32 {
561 assert_eq!(tree.insert(k, k * 10), None);
562 }
563 check_tree(&tree);
564 assert!(
565 tree.height() > 1,
566 "tree should have split into multiple levels"
567 );
568 for k in 0..256_u32 {
569 assert_eq!(tree.get(&k), Some(&(k * 10)));
570 }
571 assert_eq!(tree.get(&256), None);
572 }
573
574 #[test]
575 fn test_insert_reverse_order_keeps_keys_sorted() {
576 let mut tree = BPlusTree::with_order(3);
577 for k in (0..100_u32).rev() {
578 assert_eq!(tree.insert(k, k), None);
579 }
580 let mut keys = Vec::new();
581 collect_keys(&tree.store, tree.root, &mut keys);
582 assert_eq!(keys.len(), 100);
583 assert!(keys.windows(2).all(|w| w[0] < w[1]), "leaf order broken");
584 }
585
586 #[test]
587 fn test_remove_absent_key_returns_none() {
588 let mut tree = BPlusTree::new();
589 assert_eq!(tree.insert(1_u32, "a"), None);
590 assert_eq!(tree.remove(&2), None);
591 assert_eq!(tree.len(), 1);
592 }
593
594 #[test]
595 fn test_remove_present_key_returns_value() {
596 let mut tree = BPlusTree::new();
597 assert_eq!(tree.insert(1_u32, "a"), None);
598 assert_eq!(tree.insert(2, "b"), None);
599 assert_eq!(tree.remove(&1), Some("a"));
600 assert_eq!(tree.get(&1), None);
601 assert_eq!(tree.get(&2), Some(&"b"));
602 assert_eq!(tree.len(), 1);
603 }
604
605 #[test]
606 fn test_remove_all_empties_tree_and_collapses_root() {
607 let mut tree = BPlusTree::with_order(4);
608 for k in 0..200_u32 {
609 let _ = tree.insert(k, k);
610 }
611 assert!(tree.height() > 1);
612 for k in (0..200_u32).step_by(2) {
613 assert_eq!(tree.remove(&k), Some(k));
614 }
615 for k in (1..200_u32).step_by(2) {
616 assert_eq!(tree.remove(&k), Some(k));
617 }
618 assert!(tree.is_empty());
619 assert_eq!(tree.height(), 1, "root should collapse back to a leaf");
620 }
621
622 #[test]
623 fn test_remove_keeps_tree_balanced() {
624 let mut tree = BPlusTree::with_order(3);
625 for k in 0..500_u32 {
626 let _ = tree.insert(k, k);
627 }
628 for k in (0..500_u32).filter(|k| k % 3 == 0) {
629 assert_eq!(tree.remove(&k), Some(k));
630 }
631 check_tree(&tree);
632 for k in 0..500_u32 {
633 assert_eq!(tree.get(&k), if k % 3 == 0 { None } else { Some(&k) });
634 }
635 }
636
637 #[test]
638 fn test_bulk_load_builds_balanced_tree() {
639 for &n in &[0_u32, 1, 2, 5, 63, 64, 65, 1_000] {
640 let tree = BPlusTree::from_sorted_with_order((0..n).map(|k| (k, k * 2)), 5);
641 assert_eq!(tree.len(), n as usize);
642 if n > 0 {
643 check_tree(&tree);
644 }
645 for k in 0..n {
646 assert_eq!(tree.get(&k), Some(&(k * 2)));
647 }
648 let keys: Vec<_> = tree.iter().map(|(&k, _)| k).collect();
649 assert_eq!(keys, (0..n).collect::<Vec<_>>());
650 }
651 }
652
653 #[test]
654 fn test_bulk_load_unsorted_falls_back() {
655 let tree = BPlusTree::from_sorted_with_order([(3_u32, 3), (1, 1), (2, 2), (1, 9)], 4);
656 assert_eq!(tree.len(), 3);
657 assert_eq!(tree.get(&1), Some(&9)); let keys: Vec<_> = tree.iter().map(|(&k, _)| k).collect();
659 assert_eq!(keys, vec![1, 2, 3]);
660 }
661
662 #[test]
663 fn test_iter_empty_yields_nothing() {
664 let tree: BPlusTree<u32, u32> = BPlusTree::new();
665 assert_eq!(tree.iter().count(), 0);
666 assert_eq!(tree.iter().next_back(), None);
667 assert_eq!(tree.range(..).count(), 0);
668 }
669
670 #[test]
671 fn test_iter_forward_and_reverse() {
672 let mut tree = BPlusTree::with_order(4);
673 for k in 0..50_u32 {
674 let _ = tree.insert(k, k * 10);
675 }
676 let fwd: Vec<_> = tree.iter().map(|(&k, &v)| (k, v)).collect();
677 let expected: Vec<_> = (0..50_u32).map(|k| (k, k * 10)).collect();
678 assert_eq!(fwd, expected);
679
680 let rev: Vec<_> = tree.iter().rev().map(|(&k, _)| k).collect();
681 let expected_rev: Vec<_> = (0..50_u32).rev().collect();
682 assert_eq!(rev, expected_rev);
683 }
684
685 #[test]
686 fn test_iter_from_both_ends_meets_in_middle() {
687 let mut tree = BPlusTree::with_order(3);
688 for k in 0..9_u32 {
689 let _ = tree.insert(k, k);
690 }
691 let mut it = tree.iter();
692 let mut seq = Vec::new();
693 let mut take_front = true;
694 loop {
695 let item = if take_front {
696 it.next()
697 } else {
698 it.next_back()
699 };
700 match item {
701 Some((&k, _)) => seq.push(k),
702 None => break,
703 }
704 take_front = !take_front;
705 }
706 assert_eq!(seq, vec![0, 8, 1, 7, 2, 6, 3, 5, 4]);
707 }
708
709 #[test]
710 fn test_range_bounds() {
711 let mut tree = BPlusTree::with_order(4);
712 for k in 0..20_u32 {
713 let _ = tree.insert(k, k);
714 }
715 let collect = |it: Iter<'_, u32, u32>| it.map(|(&k, _)| k).collect::<Vec<_>>();
716 assert_eq!(collect(tree.range(5..10)), vec![5, 6, 7, 8, 9]);
717 assert_eq!(collect(tree.range(5..=10)), vec![5, 6, 7, 8, 9, 10]);
718 assert_eq!(collect(tree.range(..3)), vec![0, 1, 2]);
719 assert_eq!(collect(tree.range(17..)), vec![17, 18, 19]);
720 assert_eq!(collect(tree.range(100..200)), Vec::<u32>::new());
721 let mut sparse = BPlusTree::with_order(3);
722 for k in [0_u32, 10, 20, 30, 40] {
723 let _ = sparse.insert(k, k);
724 }
725 assert_eq!(collect(sparse.range(5..35)), vec![10, 20, 30]);
726 }
727
728 fn adversarial_workload(order: usize, inserts: &[u32], deletes: &[u32]) {
732 use std::collections::BTreeSet;
733
734 let mut tree = BPlusTree::with_order(order);
735 let mut reference = BTreeSet::new();
736 for &k in inserts {
737 let _ = tree.insert(k, k);
738 let _ = reference.insert(k);
739 }
740 check_tree(&tree);
741 for &k in deletes {
742 let in_tree = tree.remove(&k).is_some();
743 let in_ref = reference.remove(&k);
744 assert_eq!(in_tree, in_ref, "remove({k}) disagreed with reference");
745 if !tree.is_empty() {
746 check_tree(&tree);
747 }
748 }
749 let keys: Vec<u32> = tree.iter().map(|(&k, _)| k).collect();
750 let expected: Vec<u32> = reference.iter().copied().collect();
751 assert_eq!(keys, expected);
752 }
753
754 #[test]
755 fn test_adversarial_ascending_insert_descending_delete() {
756 for &order in &[3_usize, 4, 5, 7, 16] {
757 let inserts: Vec<u32> = (0..400).collect();
758 let deletes: Vec<u32> = (0..400).rev().collect();
759 adversarial_workload(order, &inserts, &deletes);
760 }
761 }
762
763 #[test]
764 fn test_adversarial_descending_insert_ascending_delete() {
765 for &order in &[3_usize, 4, 5, 7, 16] {
766 let inserts: Vec<u32> = (0..400).rev().collect();
767 let deletes: Vec<u32> = (0..400).collect();
768 adversarial_workload(order, &inserts, &deletes);
769 }
770 }
771
772 #[test]
773 fn test_adversarial_zigzag_insert_middle_out_delete() {
774 for &order in &[3_usize, 4, 6] {
775 let mut inserts = Vec::new();
777 let (mut lo, mut hi) = (0_u32, 399_u32);
778 while lo <= hi {
779 inserts.push(lo);
780 if lo != hi {
781 inserts.push(hi);
782 }
783 lo += 1;
784 hi = hi.wrapping_sub(1);
785 }
786 let mut deletes = Vec::new();
788 let (mut left, mut right) = (199_i32, 200_i32);
789 while left >= 0 || right < 400 {
790 if left >= 0 {
791 deletes.push(left as u32);
792 left -= 1;
793 }
794 if right < 400 {
795 deletes.push(right as u32);
796 right += 1;
797 }
798 }
799 adversarial_workload(order, &inserts, &deletes);
800 }
801 }
802
803 #[test]
804 fn test_adversarial_clustered_keys() {
805 let inserts: Vec<u32> = (1_000_000..1_000_500).collect();
808 let deletes: Vec<u32> = (1_000_000..1_000_500).step_by(3).collect();
809 adversarial_workload(3, &inserts, &deletes);
810 }
811
812 #[test]
813 fn test_adversarial_repeated_overwrite_then_clear() {
814 let mut tree = BPlusTree::with_order(4);
815 for round in 0..50_u32 {
816 for k in 0..100_u32 {
817 let _ = tree.insert(k, round * 100 + k);
818 }
819 }
820 assert_eq!(tree.len(), 100);
821 for k in 0..100_u32 {
822 assert_eq!(tree.get(&k), Some(&(49 * 100 + k)));
823 }
824 check_tree(&tree);
825 tree.clear();
826 assert!(tree.is_empty());
827 assert_eq!(tree.height(), 1);
828 }
829
830 proptest! {
831 #[test]
835 fn prop_adversarial_small_order(
836 order in 3_usize..6,
837 ops in prop::collection::vec((any::<bool>(), 0_u32..60), 0..800),
838 ) {
839 use std::collections::BTreeMap;
840
841 let mut tree = BPlusTree::with_order(order);
842 let mut reference = BTreeMap::new();
843 for (is_insert, k) in ops {
844 if is_insert {
845 prop_assert_eq!(tree.insert(k, k), reference.insert(k, k));
846 } else {
847 prop_assert_eq!(tree.remove(&k), reference.remove(&k));
848 }
849 prop_assert_eq!(tree.len(), reference.len());
850 if !tree.is_empty() {
851 check_tree(&tree);
852 }
853 }
854 let keys: Vec<u32> = tree.iter().map(|(&k, _)| k).collect();
855 let expected: Vec<u32> = reference.keys().copied().collect();
856 prop_assert_eq!(keys, expected);
857 }
858 #[test]
859 fn prop_matches_reference_map(
860 order in 3_usize..8,
861 ops in prop::collection::vec((0_u32..200, 0_u32..1_000_000), 0..400),
862 ) {
863 use std::collections::BTreeMap;
864
865 let mut tree = BPlusTree::with_order(order);
866 let mut reference = BTreeMap::new();
867 for (k, v) in ops {
868 prop_assert_eq!(tree.insert(k, v), reference.insert(k, v));
869 }
870
871 prop_assert_eq!(tree.len(), reference.len());
872 if !tree.is_empty() {
873 check_tree(&tree);
874 }
875 for (k, v) in &reference {
876 prop_assert_eq!(tree.get(k), Some(v));
877 }
878 for k in 0_u32..200 {
879 if !reference.contains_key(&k) {
880 prop_assert_eq!(tree.get(&k), None);
881 }
882 }
883 let mut keys = Vec::new();
884 collect_keys(&tree.store, tree.root, &mut keys);
885 let expected: Vec<u32> = reference.keys().copied().collect();
886 prop_assert_eq!(keys, expected);
887 }
888
889 #[test]
890 fn prop_iter_and_range_match_reference(
891 order in 3_usize..8,
892 keys in prop::collection::vec(0_u32..200, 0..300),
893 lo in 0_u32..200,
894 hi in 0_u32..200,
895 ) {
896 use std::collections::BTreeMap;
897
898 let mut tree = BPlusTree::with_order(order);
899 let mut reference = BTreeMap::new();
900 for k in keys {
901 let _ = tree.insert(k, k.wrapping_mul(7));
902 let _ = reference.insert(k, k.wrapping_mul(7));
903 }
904
905 let tree_fwd: Vec<_> = tree.iter().map(|(&k, &v)| (k, v)).collect();
906 let ref_fwd: Vec<_> = reference.iter().map(|(&k, &v)| (k, v)).collect();
907 prop_assert_eq!(&tree_fwd, &ref_fwd);
908
909 let tree_rev: Vec<_> = tree.iter().rev().map(|(&k, &v)| (k, v)).collect();
910 let ref_rev: Vec<_> = reference.iter().rev().map(|(&k, &v)| (k, v)).collect();
911 prop_assert_eq!(tree_rev, ref_rev);
912
913 let (lo, hi) = (lo.min(hi), lo.max(hi));
914 let tree_range: Vec<_> = tree.range(lo..hi).map(|(&k, _)| k).collect();
915 let ref_range: Vec<_> = reference.range(lo..hi).map(|(&k, _)| k).collect();
916 prop_assert_eq!(tree_range, ref_range);
917
918 let tree_incl: Vec<_> = tree.range(lo..=hi).rev().map(|(&k, _)| k).collect();
919 let ref_incl: Vec<_> = reference.range(lo..=hi).rev().map(|(&k, _)| k).collect();
920 prop_assert_eq!(tree_incl, ref_incl);
921 }
922
923 #[test]
924 fn prop_insert_remove_matches_reference(
925 order in 3_usize..8,
926 ops in prop::collection::vec((any::<bool>(), 0_u32..150), 0..600),
927 ) {
928 use std::collections::BTreeMap;
929
930 let mut tree = BPlusTree::with_order(order);
931 let mut reference = BTreeMap::new();
932 for (is_insert, k) in ops {
933 if is_insert {
934 prop_assert_eq!(tree.insert(k, k), reference.insert(k, k));
935 } else {
936 prop_assert_eq!(tree.remove(&k), reference.remove(&k));
937 }
938 prop_assert_eq!(tree.len(), reference.len());
939 if !tree.is_empty() {
940 check_tree(&tree);
941 }
942 }
943
944 let mut keys = Vec::new();
945 collect_keys(&tree.store, tree.root, &mut keys);
946 let expected: Vec<u32> = reference.keys().copied().collect();
947 prop_assert_eq!(keys, expected);
948 }
949
950 #[test]
951 fn prop_bulk_load_matches_inserts(
952 order in 3_usize..8,
953 keys in prop::collection::btree_set(0_u32..1_000, 0..400),
954 ) {
955 let sorted: Vec<(u32, u32)> = keys.iter().map(|&k| (k, k)).collect();
956 let bulk = BPlusTree::from_sorted_with_order(sorted.iter().copied(), order);
957 prop_assert_eq!(bulk.len(), keys.len());
958 if !bulk.is_empty() {
959 check_tree(&bulk);
960 }
961 let bulk_keys: Vec<_> = bulk.iter().map(|(&k, _)| k).collect();
962 let expected: Vec<u32> = keys.iter().copied().collect();
963 prop_assert_eq!(bulk_keys, expected);
964 }
965 }
966}