From 83efd2c8cdc28cd20021cdec5553f2a5619df2aa Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Tue, 15 Apr 2025 19:20:56 +0200 Subject: [PATCH 01/66] k/v --- .gitignore | 2 ++ src/btreemap.rs | 49 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 707f8413..cbad8b17 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ .vscode/ .idea/ **/*~ + +tmp/ diff --git a/src/btreemap.rs b/src/btreemap.rs index e72567e4..e0389fc1 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1167,6 +1167,24 @@ mod test { Rc::new(RefCell::new(Vec::new())) } + fn make_buffer(i: u32) -> [u8; N] { + let mut buf = [0u8; N]; + let bytes = i.to_le_bytes(); + let len = N.min(bytes.len()); + buf[..len].copy_from_slice(&bytes[..len]); + buf + } + + /// Creates a key from a u32. + fn k(i: u32) -> Blob<10> { + Blob::<10>::try_from(&make_buffer::<10>(i)[..]).unwrap() + } + + /// Creates a value from a u32. + fn v(i: u32) -> Blob<10> { + Blob::<10>::try_from(&make_buffer::<10>(i)[..]).unwrap() + } + /// A helper method to succinctly create an entry. fn e(x: u8) -> (Blob<10>, Vec) { (b(&[x]), vec![]) @@ -1204,46 +1222,43 @@ mod test { #[test] fn init_preserves_data() { btree_test(|mut btree| { - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + assert_eq!(btree.insert(k(123), v(456)), None); + assert_eq!(btree.get(&k(123)), Some(v(456))); // Reload the btree let btree = BTreeMap::init(btree.into_memory()); // Data still exists. - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + assert_eq!(btree.get(&k(123)), Some(v(456))); }); } #[test] fn insert_get() { btree_test(|mut btree| { - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + assert_eq!(btree.insert(k(123), v(456)), None); + assert_eq!(btree.get(&k(123)), Some(v(456))); }); } #[test] fn insert_overwrites_previous_value() { btree_test(|mut btree| { - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!( - btree.insert(b(&[1, 2, 3]), b(&[7, 8, 9])), - Some(b(&[4, 5, 6])) - ); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[7, 8, 9]))); + assert_eq!(btree.insert(k(123), v(456)), None); + assert_eq!(btree.insert(k(123), v(789)), Some(v(456))); + assert_eq!(btree.get(&k(123)), Some(v(789))); }); } #[test] fn insert_get_multiple() { btree_test(|mut btree| { - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.insert(b(&[4, 5]), b(&[7, 8, 9, 10])), None); - assert_eq!(btree.insert(b(&[]), b(&[11])), None); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - assert_eq!(btree.get(&b(&[4, 5])), Some(b(&[7, 8, 9, 10]))); - assert_eq!(btree.get(&b(&[])), Some(b(&[11]))); + assert_eq!(btree.insert(k(123), v(456)), None); + assert_eq!(btree.insert(k(45), v(789)), None); + assert_eq!(btree.insert(b(&[]), v(111)), None); + assert_eq!(btree.get(&k(123)), Some(v(456))); + assert_eq!(btree.get(&k(45)), Some(v(789))); + assert_eq!(btree.get(&b(&[])), Some(v(111))); }); } From 80011896f98b4c60c2373440d71145d1db932732 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Tue, 15 Apr 2025 19:46:32 +0200 Subject: [PATCH 02/66] . --- src/btreemap.rs | 157 +++++++++++++++++++------------------- src/btreemap/proptests.rs | 10 +-- 2 files changed, 84 insertions(+), 83 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index e0389fc1..f99f8f62 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1196,77 +1196,75 @@ mod test { } /// A test runner that runs the test using both V1 and V2 btrees. - pub fn btree_test(f: F) + pub fn run_btree_test(f: F) where K: Storable + Ord + Clone, V: Storable, F: Fn(BTreeMap) -> R, { - // Run the test with the V1 btree. + // Test with V1. let mem = make_memory(); - let btree = BTreeMap::new_v1(mem); - f(btree); + let tree_v1 = BTreeMap::new_v1(mem); + f(tree_v1); - // Run the test with a V2 btree that was migrated from V1. + // Test with V2 migrated from V1. let mem = make_memory(); - let btree: BTreeMap = BTreeMap::new_v1(mem); - let btree = BTreeMap::load_helper(btree.into_memory(), true); - f(btree); + let tree_v1: BTreeMap = BTreeMap::new_v1(mem); + let tree_v2_migrated = BTreeMap::load_helper(tree_v1.into_memory(), true); + f(tree_v2_migrated); - // Run the test with the V2 btree. + // Test with direct V2. let mem = make_memory(); - let btree = BTreeMap::new(mem); - f(btree); + let tree_v2 = BTreeMap::new(mem); + f(tree_v2); } #[test] - fn init_preserves_data() { - btree_test(|mut btree| { - assert_eq!(btree.insert(k(123), v(456)), None); - assert_eq!(btree.get(&k(123)), Some(v(456))); - - // Reload the btree - let btree = BTreeMap::init(btree.into_memory()); - - // Data still exists. - assert_eq!(btree.get(&k(123)), Some(v(456))); + fn test_insert_and_get() { + run_btree_test(|mut btree| { + assert_eq!(btree.insert(k(1), v(2)), None); + assert_eq!(btree.get(&k(1)), Some(v(2))); }); } #[test] - fn insert_get() { - btree_test(|mut btree| { - assert_eq!(btree.insert(k(123), v(456)), None); - assert_eq!(btree.get(&k(123)), Some(v(456))); + fn test_init_preserves_data() { + run_btree_test(|mut btree| { + assert_eq!(btree.insert(k(1), v(2)), None); + assert_eq!(btree.get(&k(1)), Some(v(2))); + + // Reload the btree, verfiy data still exists. + let btree = BTreeMap::init(btree.into_memory()); + assert_eq!(btree.get(&k(1)), Some(v(2))); }); } #[test] - fn insert_overwrites_previous_value() { - btree_test(|mut btree| { - assert_eq!(btree.insert(k(123), v(456)), None); - assert_eq!(btree.insert(k(123), v(789)), Some(v(456))); - assert_eq!(btree.get(&k(123)), Some(v(789))); + fn test_insert_overwrites_previous_value() { + run_btree_test(|mut btree| { + assert_eq!(btree.insert(k(1), v(2)), None); + assert_eq!(btree.insert(k(1), v(3)), Some(v(2))); + assert_eq!(btree.get(&k(1)), Some(v(3))); }); } #[test] - fn insert_get_multiple() { - btree_test(|mut btree| { - assert_eq!(btree.insert(k(123), v(456)), None); - assert_eq!(btree.insert(k(45), v(789)), None); - assert_eq!(btree.insert(b(&[]), v(111)), None); - assert_eq!(btree.get(&k(123)), Some(v(456))); - assert_eq!(btree.get(&k(45)), Some(v(789))); - assert_eq!(btree.get(&b(&[])), Some(v(111))); + fn test_insert_get_multiple_entries() { + run_btree_test(|mut btree| { + assert_eq!(btree.insert(k(1), v(10)), None); + assert_eq!(btree.insert(k(2), v(20)), None); + assert_eq!(btree.insert(b(&[]), v(30)), None); + assert_eq!(btree.get(&k(1)), Some(v(10))); + assert_eq!(btree.get(&k(2)), Some(v(20))); + assert_eq!(btree.get(&b(&[])), Some(v(30))); }); } #[test] fn insert_overwrite_median_key_in_full_child_node() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=17 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); + assert_eq!(btree.insert(k(i), v(0)), None); } // The result should look like this: @@ -1276,18 +1274,21 @@ mod test { let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(6)]); + assert_eq!( + root.entries(btree.memory()), + vec![(k(6), v(0).as_slice().to_vec())] + ); assert_eq!(root.children_len(), 2); // The right child should now be full, with the median key being "12" let right_child = btree.load_node(root.child(1)); assert!(right_child.is_full()); let median_index = right_child.entries_len() / 2; - assert_eq!(right_child.key(median_index), &b(&[12])); + assert_eq!(right_child.key(median_index), &k(12)); // Overwrite the value of the median key. - assert_eq!(btree.insert(b(&[12]), b(&[1, 2, 3])), Some(b(&[]))); - assert_eq!(btree.get(&b(&[12])), Some(b(&[1, 2, 3]))); + assert_eq!(btree.insert(k(12), v(123)), Some(v(0))); + assert_eq!(btree.get(&k(12)), Some(v(123))); // The child has not been split and is still full. let right_child = btree.load_node(root.child(1)); @@ -1298,7 +1299,7 @@ mod test { #[test] fn insert_overwrite_key_in_full_root_node() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -1321,7 +1322,7 @@ mod test { #[test] fn allocations() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { // Insert entries until the root node is full. let mut i = 0; loop { @@ -1345,7 +1346,7 @@ mod test { #[test] fn allocations_2() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); assert_eq!(btree.insert(b(&[]), b(&[])), None); @@ -1358,7 +1359,7 @@ mod test { #[test] fn pop_last_single_entry() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); assert_eq!(btree.insert(b(&[]), b(&[])), None); @@ -1373,7 +1374,7 @@ mod test { #[test] fn pop_first_single_entry() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); assert_eq!(btree.insert(b(&[]), b(&[])), None); @@ -1388,7 +1389,7 @@ mod test { #[test] fn insert_same_key_multiple() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { assert_eq!(btree.insert(b(&[1]), b(&[2])), None); for i in 2..10 { assert_eq!(btree.insert(b(&[1]), b(&[i + 1])), Some(b(&[i]))); @@ -1399,7 +1400,7 @@ mod test { #[test] fn insert_split_node() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -1420,7 +1421,7 @@ mod test { #[test] fn insert_split_multiple_nodes() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -1498,7 +1499,7 @@ mod test { #[test] fn remove_simple() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); assert_eq!(btree.remove(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); @@ -1508,7 +1509,7 @@ mod test { #[test] fn pop_last_simple() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); assert_eq!(btree.pop_last().unwrap().1, b(&[4, 5, 6])); @@ -1518,7 +1519,7 @@ mod test { #[test] fn pop_first_simple() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); assert_eq!(btree.pop_first().map(|e| e.1), Some(b(&[4, 5, 6]))); @@ -1528,7 +1529,7 @@ mod test { #[test] fn pop_on_empty_tree_simple() { - btree_test( + run_btree_test( |mut btree: BTreeMap, Blob<10>, Rc>>>| { assert_eq!(btree.pop_last(), None); assert_eq!(btree.pop_first(), None); @@ -1538,7 +1539,7 @@ mod test { #[test] fn last_key_value_empty_tree_simple() { - btree_test( + run_btree_test( |btree: BTreeMap, Blob<10>, Rc>>>| { assert_eq!(btree.last_key_value(), None); }, @@ -1547,7 +1548,7 @@ mod test { #[test] fn first_key_value_empty_tree_simple() { - btree_test( + run_btree_test( |btree: BTreeMap, Blob<10>, Rc>>>| { assert_eq!(btree.first_key_value(), None); }, @@ -1556,7 +1557,7 @@ mod test { #[test] fn remove_case_2a_and_2c() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -1622,7 +1623,7 @@ mod test { #[test] fn remove_case_2b() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -1691,7 +1692,7 @@ mod test { #[test] fn remove_case_3a_right() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -1737,7 +1738,7 @@ mod test { #[test] fn remove_case_3a_left() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -1782,7 +1783,7 @@ mod test { #[test] fn remove_case_3b_merge_into_right() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -2084,7 +2085,7 @@ mod test { #[test] fn reloading() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { // The btree is initially empty. assert_eq!(btree.len(), 0); assert!(btree.is_empty()); @@ -2117,7 +2118,7 @@ mod test { #[test] fn len() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 0..1000u32 { assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); } @@ -2136,7 +2137,7 @@ mod test { #[test] fn pop_first_len() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 0..1000u32 { assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); } @@ -2155,7 +2156,7 @@ mod test { #[test] fn pop_last_len() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 0..1000u32 { assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); } @@ -2174,7 +2175,7 @@ mod test { #[test] fn contains_key() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { // Insert even numbers from 0 to 1000. for i in (0..1000u32).step_by(2) { assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); @@ -2190,7 +2191,7 @@ mod test { #[test] fn range_empty() { - btree_test(|btree| { + run_btree_test(|btree| { // Test prefixes that don't exist in the map. assert_eq!( btree @@ -2205,7 +2206,7 @@ mod test { // Tests the case where the prefix is larger than all the entries in a leaf node. #[test] fn range_leaf_prefix_greater_than_all_entries() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { btree.insert(b(&[0]), b(&[])); // Test a prefix that's larger than the value in the leaf node. Should be empty. @@ -2216,7 +2217,7 @@ mod test { // Tests the case where the prefix is larger than all the entries in an internal node. #[test] fn range_internal_prefix_greater_than_all_entries() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in 1..=12 { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } @@ -2236,7 +2237,7 @@ mod test { #[test] fn range_various_prefixes() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { btree.insert(b(&[0, 1]), b(&[])); btree.insert(b(&[0, 2]), b(&[])); btree.insert(b(&[0, 3]), b(&[])); @@ -2297,7 +2298,7 @@ mod test { #[test] fn range_various_prefixes_2() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { btree.insert(b(&[0, 1]), b(&[])); btree.insert(b(&[0, 2]), b(&[])); btree.insert(b(&[0, 3]), b(&[])); @@ -2424,7 +2425,7 @@ mod test { #[test] fn range_large() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { // Insert 1000 elements with prefix 0 and another 1000 elements with prefix 1. for prefix in 0..=1 { for i in 0..1000u32 { @@ -2465,7 +2466,7 @@ mod test { #[test] fn range_various_prefixes_with_offset() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { btree.insert(b(&[0, 1]), b(&[])); btree.insert(b(&[0, 2]), b(&[])); btree.insert(b(&[0, 3]), b(&[])); @@ -2512,7 +2513,7 @@ mod test { #[test] fn range_various_prefixes_with_offset_2() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { btree.insert(b(&[0, 1]), b(&[])); btree.insert(b(&[0, 2]), b(&[])); btree.insert(b(&[0, 3]), b(&[])); @@ -2680,7 +2681,7 @@ mod test { #[test] fn bruteforce_range_search() { - btree_test(|mut stable_map| { + run_btree_test(|mut stable_map| { use std::collections::BTreeMap; const NKEYS: u64 = 60; let mut std_map = BTreeMap::new(); @@ -2741,7 +2742,7 @@ mod test { #[test] fn test_iter_upper_bound() { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for k in 0..100u64 { btree.insert(k, ()); for i in 0..=k { diff --git a/src/btreemap/proptests.rs b/src/btreemap/proptests.rs index e8bf8675..020f1bcb 100644 --- a/src/btreemap/proptests.rs +++ b/src/btreemap/proptests.rs @@ -1,6 +1,6 @@ use crate::{ btreemap::{ - test::{b, btree_test, make_memory}, + test::{b, make_memory, run_btree_test}, BTreeMap, }, storable::Blob, @@ -105,7 +105,7 @@ fn comprehensive_fuzz() { #[proptest(cases = 10)] fn insert(#[strategy(pset(arb_blob(), 1000..10_000))] keys: BTreeSet>) { - btree_test(|mut btree| { + run_btree_test(|mut btree| { let keys = keys.clone(); for key in keys.iter() { assert_eq!(btree.insert(*key, *key), None); @@ -122,7 +122,7 @@ fn insert(#[strategy(pset(arb_blob(), 1000..10_000))] keys: BTreeSet>) #[proptest] fn map_min_max(#[strategy(pvec(any::(), 10..100))] keys: Vec) { - btree_test(|mut map| { + run_btree_test(|mut map| { prop_assert_eq!(map.first_key_value(), None); prop_assert_eq!(map.last_key_value(), None); @@ -142,7 +142,7 @@ fn map_min_max(#[strategy(pvec(any::(), 10..100))] keys: Vec) { #[proptest] fn map_upper_bound_iter(#[strategy(pvec(0u64..u64::MAX -1 , 10..100))] keys: Vec) { - btree_test(|mut map| { + run_btree_test(|mut map| { for k in keys.iter() { map.insert(*k, ()); @@ -155,7 +155,7 @@ fn map_upper_bound_iter(#[strategy(pvec(0u64..u64::MAX -1 , 10..100))] keys: Vec #[proptest(cases = 10)] fn iter_count_test(#[strategy(0..250u8)] start: u8, #[strategy(#start..255u8)] end: u8) { - btree_test(|mut btree| { + run_btree_test(|mut btree| { for i in start..end { assert_eq!(btree.insert(b(&[i]), b(&[])), None); } From ca1bd7e3755185f1ebcea0013585846e0c7c9493 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 08:50:57 +0200 Subject: [PATCH 03/66] comment not-refactored-yet tests --- src/btreemap.rs | 3608 +++++++++++++++++++++++------------------------ 1 file changed, 1804 insertions(+), 1804 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index f99f8f62..e429fa3a 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1297,1808 +1297,1808 @@ mod test { }); } - #[test] - fn insert_overwrite_key_in_full_root_node() { - run_btree_test(|mut btree| { - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - - // We now have a root that is full and looks like this: - // - // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - let root = btree.load_node(btree.root_addr); - assert!(root.is_full()); - - // Overwrite an element in the root. It should NOT cause the node to be split. - assert_eq!(btree.insert(b(&[6]), b(&[4, 5, 6])), Some(b(&[]))); - - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Leaf); - assert_eq!(btree.get(&b(&[6])), Some(b(&[4, 5, 6]))); - assert_eq!(root.entries_len(), 11); - }); - } - - #[test] - fn allocations() { - run_btree_test(|mut btree| { - // Insert entries until the root node is full. - let mut i = 0; - loop { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - let root = btree.load_node(btree.root_addr); - if root.is_full() { - break; - } - i += 1; - } - - // Only need a single allocation to store up to `CAPACITY` elements. - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - - assert_eq!(btree.insert(b(&[255]), b(&[])), None); - - // The node had to be split into three nodes. - assert_eq!(btree.allocator.num_allocated_chunks(), 3); - }); - } - - #[test] - fn allocations_2() { - run_btree_test(|mut btree| { - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - - assert_eq!(btree.insert(b(&[]), b(&[])), None); - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - - assert_eq!(btree.remove(&b(&[])), Some(b(&[]))); - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - }); - } - - #[test] - fn pop_last_single_entry() { - run_btree_test(|mut btree| { - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - - assert_eq!(btree.insert(b(&[]), b(&[])), None); - assert!(!btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - - assert_eq!(btree.pop_last(), Some((b(&[]), b(&[])))); - assert!(btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - }); - } - - #[test] - fn pop_first_single_entry() { - run_btree_test(|mut btree| { - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - - assert_eq!(btree.insert(b(&[]), b(&[])), None); - assert!(!btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - - assert_eq!(btree.pop_first(), Some((b(&[]), b(&[])))); - assert!(btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - }); - } - - #[test] - fn insert_same_key_multiple() { - run_btree_test(|mut btree| { - assert_eq!(btree.insert(b(&[1]), b(&[2])), None); - for i in 2..10 { - assert_eq!(btree.insert(b(&[1]), b(&[i + 1])), Some(b(&[i]))); - } - assert_eq!(btree.get(&b(&[1])), Some(b(&[10]))); - }); - } - - #[test] - fn insert_split_node() { - run_btree_test(|mut btree| { - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - - // Should now split a node. - assert_eq!(btree.insert(b(&[12]), b(&[])), None); - - // The result should look like this: - // [6] - // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - - for i in 1..=12 { - assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - } - }); - } - - #[test] - fn insert_split_multiple_nodes() { - run_btree_test(|mut btree| { - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - // Should now split a node. - assert_eq!(btree.insert(b(&[12]), b(&[])), None); - - // The result should look like this: - // [6] - // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(6)]); - assert_eq!(root.children_len(), 2); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![e(1), e(2), e(3), e(4), e(5)] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![e(7), e(8), e(9), e(10), e(11), e(12)] - ); - - for i in 1..=12 { - assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - } - - // Insert more to cause more splitting. - assert_eq!(btree.insert(b(&[13]), b(&[])), None); - assert_eq!(btree.insert(b(&[14]), b(&[])), None); - assert_eq!(btree.insert(b(&[15]), b(&[])), None); - assert_eq!(btree.insert(b(&[16]), b(&[])), None); - assert_eq!(btree.insert(b(&[17]), b(&[])), None); - // Should cause another split - assert_eq!(btree.insert(b(&[18]), b(&[])), None); - - for i in 1..=18 { - assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - } - - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(6), e(12)],); - assert_eq!(root.children_len(), 3); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![e(1), e(2), e(3), e(4), e(5)] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![e(7), e(8), e(9), e(10), e(11)] - ); - - let child_2 = btree.load_node(root.child(2)); - assert_eq!(child_2.node_type(), NodeType::Leaf); - assert_eq!( - child_2.entries(btree.memory()), - vec![e(13), e(14), e(15), e(16), e(17), e(18)] - ); - }); - } - - #[test] - fn remove_simple() { - run_btree_test(|mut btree| { - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - assert_eq!(btree.remove(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - assert_eq!(btree.get(&b(&[1, 2, 3])), None); - }); - } - - #[test] - fn pop_last_simple() { - run_btree_test(|mut btree| { - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - assert_eq!(btree.pop_last().unwrap().1, b(&[4, 5, 6])); - assert_eq!(btree.get(&b(&[1, 2, 3])), None); - }); - } - - #[test] - fn pop_first_simple() { - run_btree_test(|mut btree| { - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - assert_eq!(btree.pop_first().map(|e| e.1), Some(b(&[4, 5, 6]))); - assert_eq!(btree.get(&b(&[1, 2, 3])), None); - }); - } - - #[test] - fn pop_on_empty_tree_simple() { - run_btree_test( - |mut btree: BTreeMap, Blob<10>, Rc>>>| { - assert_eq!(btree.pop_last(), None); - assert_eq!(btree.pop_first(), None); - }, - ); - } - - #[test] - fn last_key_value_empty_tree_simple() { - run_btree_test( - |btree: BTreeMap, Blob<10>, Rc>>>| { - assert_eq!(btree.last_key_value(), None); - }, - ); - } - - #[test] - fn first_key_value_empty_tree_simple() { - run_btree_test( - |btree: BTreeMap, Blob<10>, Rc>>>| { - assert_eq!(btree.first_key_value(), None); - }, - ); - } - - #[test] - fn remove_case_2a_and_2c() { - run_btree_test(|mut btree| { - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - // Should now split a node. - assert_eq!(btree.insert(b(&[0]), b(&[])), None); - - // The result should look like this: - // [6] - // / \ - // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] - - for i in 0..=11 { - assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - } - - // Remove node 6. Triggers case 2.a - assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); - - // The result should look like this: - // [5] - // / \ - // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(5)]); - assert_eq!(root.children_len(), 2); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![e(0), e(1), e(2), e(3), e(4)] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![e(7), e(8), e(9), e(10), e(11)] - ); - - // There are three allocated nodes. - assert_eq!(btree.allocator.num_allocated_chunks(), 3); - - // Remove node 5. Triggers case 2c - assert_eq!(btree.remove(&b(&[5])), Some(b(&[]))); - - // Reload the btree to verify that we saved it correctly. - let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); - - // The result should look like this: - // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11] - let root = btree.load_node(btree.root_addr); - assert_eq!( - root.entries(btree.memory()), - vec![e(0), e(1), e(2), e(3), e(4), e(7), e(8), e(9), e(10), e(11)] - ); - - // There is only one node allocated. - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - }); - } - - #[test] - fn remove_case_2b() { - run_btree_test(|mut btree| { - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - // Should now split a node. - assert_eq!(btree.insert(b(&[12]), b(&[])), None); - - // The result should look like this: - // [6] - // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - - for i in 1..=12 { - assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - } - - // Remove node 6. Triggers case 2.b - assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); - - // The result should look like this: - // [7] - // / \ - // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(7)]); - assert_eq!(root.children_len(), 2); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![e(1), e(2), e(3), e(4), e(5)] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![e(8), e(9), e(10), e(11), e(12)] - ); - - // Remove node 7. Triggers case 2.c - assert_eq!(btree.remove(&b(&[7])), Some(b(&[]))); - // The result should look like this: - // - // [1, 2, 3, 4, 5, 8, 9, 10, 11, 12] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Leaf); - assert_eq!( - root.entries(btree.memory()), - vec![ - e(1), - e(2), - e(3), - e(4), - e(5), - e(8), - e(9), - e(10), - e(11), - e(12) - ] - ); - }); - } - - #[test] - fn remove_case_3a_right() { - run_btree_test(|mut btree| { - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - - // Should now split a node. - assert_eq!(btree.insert(b(&[12]), b(&[])), None); - - // The result should look like this: - // [6] - // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - - // Remove node 3. Triggers case 3.a - assert_eq!(btree.remove(&b(&[3])), Some(b(&[]))); - - // The result should look like this: - // [7] - // / \ - // [1, 2, 4, 5, 6] [8, 9, 10, 11, 12] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(7)]); - assert_eq!(root.children_len(), 2); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![e(1), e(2), e(4), e(5), e(6)] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![e(8), e(9), e(10), e(11), e(12)] - ); - - // There are three allocated nodes. - assert_eq!(btree.allocator.num_allocated_chunks(), 3); - }); - } - - #[test] - fn remove_case_3a_left() { - run_btree_test(|mut btree| { - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - // Should now split a node. - assert_eq!(btree.insert(b(&[0]), b(&[])), None); - - // The result should look like this: - // [6] - // / \ - // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] - - // Remove node 8. Triggers case 3.a left - assert_eq!(btree.remove(&b(&[8])), Some(b(&[]))); - - // The result should look like this: - // [5] - // / \ - // [0, 1, 2, 3, 4] [6, 7, 9, 10, 11] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(5)]); - assert_eq!(root.children_len(), 2); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![e(0), e(1), e(2), e(3), e(4)] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![e(6), e(7), e(9), e(10), e(11)] - ); - - // There are three allocated nodes. - assert_eq!(btree.allocator.num_allocated_chunks(), 3); - }); - } - - #[test] - fn remove_case_3b_merge_into_right() { - run_btree_test(|mut btree| { - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - // Should now split a node. - assert_eq!(btree.insert(b(&[12]), b(&[])), None); - - // The result should look like this: - // [6] - // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - - for i in 1..=12 { - assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - } - - // Remove node 6. Triggers case 2.b - assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); - // The result should look like this: - // [7] - // / \ - // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(7)]); - assert_eq!(root.children_len(), 2); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![e(1), e(2), e(3), e(4), e(5)] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![e(8), e(9), e(10), e(11), e(12)] - ); - - // There are three allocated nodes. - assert_eq!(btree.allocator.num_allocated_chunks(), 3); - - // Remove node 3. Triggers case 3.b - assert_eq!(btree.remove(&b(&[3])), Some(b(&[]))); - - // Reload the btree to verify that we saved it correctly. - let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); - - // The result should look like this: - // - // [1, 2, 4, 5, 7, 8, 9, 10, 11, 12] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Leaf); - assert_eq!( - root.entries(btree.memory()), - vec![ - e(1), - e(2), - e(4), - e(5), - e(7), - e(8), - e(9), - e(10), - e(11), - e(12) - ] - ); - - // There is only one allocated node remaining. - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - }); - } - - #[test] - fn remove_case_3b_merge_into_left() { - let mem = make_memory(); - let mut btree = BTreeMap::new(mem.clone()); - - for i in 1..=11 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - - // Should now split a node. - assert_eq!(btree.insert(b(&[12]), b(&[])), None); - - // The result should look like this: - // [6] - // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - - for i in 1..=12 { - assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - } - - // Remove node 6. Triggers case 2.b - assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); - - // The result should look like this: - // [7] - // / \ - // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![e(7)]); - assert_eq!(root.children_len(), 2); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![e(1), e(2), e(3), e(4), e(5)] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![e(8), e(9), e(10), e(11), e(12)] - ); - - // There are three allocated nodes. - assert_eq!(btree.allocator.num_allocated_chunks(), 3); - - // Remove node 10. Triggers case 3.b where we merge the right into the left. - assert_eq!(btree.remove(&b(&[10])), Some(b(&[]))); - - // Reload the btree to verify that we saved it correctly. - let btree = BTreeMap::, Blob<10>, _>::load(mem); - - // The result should look like this: - // - // [1, 2, 3, 4, 5, 7, 8, 9, 11, 12] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Leaf); - assert_eq!( - root.entries(btree.memory()), - vec![e(1), e(2), e(3), e(4), e(5), e(7), e(8), e(9), e(11), e(12)] - ); - - // There is only one allocated node remaining. - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - } - - #[test] - fn many_insertions() { - let mem = make_memory(); - let mut btree = BTreeMap::new(mem.clone()); - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.insert(b(&[i, j]), b(&[i, j])), None); - } - } - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.get(&b(&[i, j])), Some(b(&[i, j]))); - } - } - - let mut btree = BTreeMap::load(mem); - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.remove(&b(&[i, j])), Some(b(&[i, j]))); - } - } - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.get(&b(&[i, j])), None); - } - } - - // We've deallocated everything. - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - } - - #[test] - fn many_insertions_2() { - let mem = make_memory(); - let mut btree = BTreeMap::new(mem.clone()); - - for j in (0..=10).rev() { - for i in (0..=255).rev() { - assert_eq!(btree.insert(b(&[i, j]), b(&[i, j])), None); - } - } - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.get(&b(&[i, j])), Some(b(&[i, j]))); - } - } - - let mut btree = BTreeMap::load(mem); - - for j in (0..=10).rev() { - for i in (0..=255).rev() { - assert_eq!(btree.remove(&b(&[i, j])), Some(b(&[i, j]))); - } - } - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.get(&b(&[i, j])), None); - } - } - - // We've deallocated everything. - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - } - - #[test] - fn pop_first_many_entries() { - let mem = make_memory(); - let mut std_btree = std::collections::BTreeMap::new(); - let mut btree = BTreeMap::new(mem.clone()); - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!( - btree.insert(b(&[i, j]), b(&[i, j])), - std_btree.insert(b(&[i, j]), b(&[i, j])) - ); - } - } - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.get(&b(&[i, j])), std_btree.get(&b(&[i, j])).cloned()); - } - } - - let mut btree = BTreeMap::load(mem); - - for _ in 0..=10 { - for _ in 0..=255 { - assert_eq!(btree.pop_first(), std_btree.pop_first()); - } - } - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.get(&b(&[i, j])), None); - assert_eq!(std_btree.get(&b(&[i, j])), None); - } - } - - // We've deallocated everything. - assert!(std_btree.is_empty()); - assert!(btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - } - - #[test] - fn pop_last_many_entries() { - let mem = make_memory(); - let mut std_btree = std::collections::BTreeMap::new(); - let mut btree = BTreeMap::new(mem.clone()); - - for j in (0..=10).rev() { - for i in (0..=255).rev() { - assert_eq!( - btree.insert(b(&[i, j]), b(&[i, j])), - std_btree.insert(b(&[i, j]), b(&[i, j])) - ); - } - } - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.get(&b(&[i, j])), std_btree.get(&b(&[i, j])).cloned()); - } - } - - let mut btree = BTreeMap::load(mem); - - for _ in (0..=10).rev() { - for _ in (0..=255).rev() { - assert_eq!(btree.pop_last(), std_btree.pop_last()); - } - } - - for j in 0..=10 { - for i in 0..=255 { - assert_eq!(btree.get(&b(&[i, j])), None); - assert_eq!(std_btree.get(&b(&[i, j])), None); - } - } - - // We've deallocated everything. - assert!(std_btree.is_empty()); - assert!(btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - } - - #[test] - fn reloading() { - run_btree_test(|mut btree| { - // The btree is initially empty. - assert_eq!(btree.len(), 0); - assert!(btree.is_empty()); - - // Add an entry into the btree. - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.len(), 1); - assert!(!btree.is_empty()); - - // Reload the btree. The element should still be there, and `len()` - // should still be `1`. - let btree = BTreeMap::load(btree.into_memory()); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - assert_eq!(btree.len(), 1); - assert!(!btree.is_empty()); - - // Remove an element. Length should be zero. - let mut btree = BTreeMap::load(btree.into_memory()); - assert_eq!(btree.remove(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - assert_eq!(btree.len(), 0); - assert!(btree.is_empty()); - - // Reload. Btree should still be empty. - let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); - assert_eq!(btree.get(&b(&[1, 2, 3])), None); - assert_eq!(btree.len(), 0); - assert!(btree.is_empty()); - }); - } - - #[test] - fn len() { - run_btree_test(|mut btree| { - for i in 0..1000u32 { - assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); - } - - assert_eq!(btree.len(), 1000); - assert!(!btree.is_empty()); - - for i in 0..1000u32 { - assert_eq!(btree.remove(&b(&i.to_le_bytes())), Some(b(&[]))); - } - - assert_eq!(btree.len(), 0); - assert!(btree.is_empty()); - }); - } - - #[test] - fn pop_first_len() { - run_btree_test(|mut btree| { - for i in 0..1000u32 { - assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); - } - - assert_eq!(btree.len(), 1000); - assert!(!btree.is_empty()); - - for i in 0..1000u32 { - assert_eq!(btree.pop_first().unwrap().1, b(&i.to_le_bytes())); - } - - assert_eq!(btree.len(), 0); - assert!(btree.is_empty()); - }); - } - - #[test] - fn pop_last_len() { - run_btree_test(|mut btree| { - for i in 0..1000u32 { - assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); - } - - assert_eq!(btree.len(), 1000); - assert!(!btree.is_empty()); - - for i in (0..1000u32).rev() { - assert_eq!(btree.pop_last().unwrap().1, b(&i.to_le_bytes())); - } - - assert_eq!(btree.len(), 0); - assert!(btree.is_empty()); - }); - } - - #[test] - fn contains_key() { - run_btree_test(|mut btree| { - // Insert even numbers from 0 to 1000. - for i in (0..1000u32).step_by(2) { - assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); - } - - // Contains key should return true on all the even numbers and false on all the odd - // numbers. - for i in 0..1000u32 { - assert_eq!(btree.contains_key(&b(&i.to_le_bytes())), i % 2 == 0); - } - }); - } - - #[test] - fn range_empty() { - run_btree_test(|btree| { - // Test prefixes that don't exist in the map. - assert_eq!( - btree - .range(b(&[0])..) - .collect::, Blob<10>)>>(), - vec![] - ); - assert_eq!(btree.range(b(&[1, 2, 3, 4])..).collect::>(), vec![]); - }); - } - - // Tests the case where the prefix is larger than all the entries in a leaf node. - #[test] - fn range_leaf_prefix_greater_than_all_entries() { - run_btree_test(|mut btree| { - btree.insert(b(&[0]), b(&[])); - - // Test a prefix that's larger than the value in the leaf node. Should be empty. - assert_eq!(btree.range(b(&[1])..).collect::>(), vec![]); - }); - } - - // Tests the case where the prefix is larger than all the entries in an internal node. - #[test] - fn range_internal_prefix_greater_than_all_entries() { - run_btree_test(|mut btree| { - for i in 1..=12 { - assert_eq!(btree.insert(b(&[i]), b(&[])), None); - } - - // The result should look like this: - // [6] - // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - - // Test a prefix that's larger than the key in the internal node. - assert_eq!( - btree.range(b(&[7])..b(&[8])).collect::>(), - vec![(b(&[7]), b(&[]))] - ); - }); - } - - #[test] - fn range_various_prefixes() { - run_btree_test(|mut btree| { - btree.insert(b(&[0, 1]), b(&[])); - btree.insert(b(&[0, 2]), b(&[])); - btree.insert(b(&[0, 3]), b(&[])); - btree.insert(b(&[0, 4]), b(&[])); - btree.insert(b(&[1, 1]), b(&[])); - btree.insert(b(&[1, 2]), b(&[])); - btree.insert(b(&[1, 3]), b(&[])); - btree.insert(b(&[1, 4]), b(&[])); - btree.insert(b(&[2, 1]), b(&[])); - btree.insert(b(&[2, 2]), b(&[])); - btree.insert(b(&[2, 3]), b(&[])); - btree.insert(b(&[2, 4]), b(&[])); - - // The result should look like this: - // [(1, 2)] - // / \ - // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 1)] [(1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4)] - - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![(b(&[1, 2]), vec![])]); - assert_eq!(root.children_len(), 2); - - // Tests a prefix that's smaller than the key in the internal node. - assert_eq!( - btree.range(b(&[0])..b(&[1])).collect::>(), - vec![ - (b(&[0, 1]), b(&[])), - (b(&[0, 2]), b(&[])), - (b(&[0, 3]), b(&[])), - (b(&[0, 4]), b(&[])), - ] - ); - - // Tests a prefix that crosses several nodes. - assert_eq!( - btree.range(b(&[1])..b(&[2])).collect::>(), - vec![ - (b(&[1, 1]), b(&[])), - (b(&[1, 2]), b(&[])), - (b(&[1, 3]), b(&[])), - (b(&[1, 4]), b(&[])), - ] - ); - - // Tests a prefix that's larger than the key in the internal node. - assert_eq!( - btree.range(b(&[2])..b(&[3])).collect::>(), - vec![ - (b(&[2, 1]), b(&[])), - (b(&[2, 2]), b(&[])), - (b(&[2, 3]), b(&[])), - (b(&[2, 4]), b(&[])), - ] - ); - }); - } - - #[test] - fn range_various_prefixes_2() { - run_btree_test(|mut btree| { - btree.insert(b(&[0, 1]), b(&[])); - btree.insert(b(&[0, 2]), b(&[])); - btree.insert(b(&[0, 3]), b(&[])); - btree.insert(b(&[0, 4]), b(&[])); - btree.insert(b(&[1, 2]), b(&[])); - btree.insert(b(&[1, 4]), b(&[])); - btree.insert(b(&[1, 6]), b(&[])); - btree.insert(b(&[1, 8]), b(&[])); - btree.insert(b(&[1, 10]), b(&[])); - btree.insert(b(&[2, 1]), b(&[])); - btree.insert(b(&[2, 2]), b(&[])); - btree.insert(b(&[2, 3]), b(&[])); - btree.insert(b(&[2, 4]), b(&[])); - btree.insert(b(&[2, 5]), b(&[])); - btree.insert(b(&[2, 6]), b(&[])); - btree.insert(b(&[2, 7]), b(&[])); - btree.insert(b(&[2, 8]), b(&[])); - btree.insert(b(&[2, 9]), b(&[])); - - // The result should look like this: - // [(1, 4), (2, 3)] - // / | \ - // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2)] | [(2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9)] - // | - // [(1, 6), (1, 8), (1, 10), (2, 1), (2, 2)] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!( - root.entries(btree.memory()), - vec![(b(&[1, 4]), vec![]), (b(&[2, 3]), vec![])] - ); - assert_eq!(root.children_len(), 3); - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![ - (b(&[0, 1]), vec![]), - (b(&[0, 2]), vec![]), - (b(&[0, 3]), vec![]), - (b(&[0, 4]), vec![]), - (b(&[1, 2]), vec![]), - ] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![ - (b(&[1, 6]), vec![]), - (b(&[1, 8]), vec![]), - (b(&[1, 10]), vec![]), - (b(&[2, 1]), vec![]), - (b(&[2, 2]), vec![]), - ] - ); - - let child_2 = btree.load_node(root.child(2)); - assert_eq!( - child_2.entries(btree.memory()), - vec![ - (b(&[2, 4]), vec![]), - (b(&[2, 5]), vec![]), - (b(&[2, 6]), vec![]), - (b(&[2, 7]), vec![]), - (b(&[2, 8]), vec![]), - (b(&[2, 9]), vec![]), - ] - ); - - // Tests a prefix that doesn't exist, but is in the middle of the root node. - assert_eq!( - btree.range(b(&[1, 5])..b(&[1, 6])).collect::>(), - vec![] - ); - - // Tests a prefix beginning in the middle of the tree and crossing several nodes. - assert_eq!( - btree.range(b(&[1, 5])..=b(&[2, 6])).collect::>(), - vec![ - (b(&[1, 6]), b(&[])), - (b(&[1, 8]), b(&[])), - (b(&[1, 10]), b(&[])), - (b(&[2, 1]), b(&[])), - (b(&[2, 2]), b(&[])), - (b(&[2, 3]), b(&[])), - (b(&[2, 4]), b(&[])), - (b(&[2, 5]), b(&[])), - (b(&[2, 6]), b(&[])), - ] - ); - - // Tests a prefix that crosses several nodes. - assert_eq!( - btree.range(b(&[1])..b(&[2])).collect::>(), - vec![ - (b(&[1, 2]), b(&[])), - (b(&[1, 4]), b(&[])), - (b(&[1, 6]), b(&[])), - (b(&[1, 8]), b(&[])), - (b(&[1, 10]), b(&[])), - ] - ); - - // Tests a prefix that starts from a leaf node, then iterates through the root and right - // sibling. - assert_eq!( - btree.range(b(&[2])..).collect::>(), - vec![ - (b(&[2, 1]), b(&[])), - (b(&[2, 2]), b(&[])), - (b(&[2, 3]), b(&[])), - (b(&[2, 4]), b(&[])), - (b(&[2, 5]), b(&[])), - (b(&[2, 6]), b(&[])), - (b(&[2, 7]), b(&[])), - (b(&[2, 8]), b(&[])), - (b(&[2, 9]), b(&[])), - ] - ); - }); - } - - #[test] - fn range_large() { - run_btree_test(|mut btree| { - // Insert 1000 elements with prefix 0 and another 1000 elements with prefix 1. - for prefix in 0..=1 { - for i in 0..1000u32 { - assert_eq!( - btree.insert( - // The key is the prefix followed by the integer's encoding. - // The encoding is big-endian so that the byte representation of the - // integers are sorted. - b([vec![prefix], i.to_be_bytes().to_vec()] - .into_iter() - .flatten() - .collect::>() - .as_slice()), - b(&[]) - ), - None - ); - } - } - - // Getting the range with a prefix should return all 1000 elements with that prefix. - for prefix in 0..=1 { - let mut i: u32 = 0; - for (key, _) in btree.range(b(&[prefix])..b(&[prefix + 1])) { - assert_eq!( - key, - b(&[vec![prefix], i.to_be_bytes().to_vec()] - .into_iter() - .flatten() - .collect::>()) - ); - i += 1; - } - assert_eq!(i, 1000); - } - }); - } - - #[test] - fn range_various_prefixes_with_offset() { - run_btree_test(|mut btree| { - btree.insert(b(&[0, 1]), b(&[])); - btree.insert(b(&[0, 2]), b(&[])); - btree.insert(b(&[0, 3]), b(&[])); - btree.insert(b(&[0, 4]), b(&[])); - btree.insert(b(&[1, 1]), b(&[])); - btree.insert(b(&[1, 2]), b(&[])); - btree.insert(b(&[1, 3]), b(&[])); - btree.insert(b(&[1, 4]), b(&[])); - btree.insert(b(&[2, 1]), b(&[])); - btree.insert(b(&[2, 2]), b(&[])); - btree.insert(b(&[2, 3]), b(&[])); - btree.insert(b(&[2, 4]), b(&[])); - - // The result should look like this: - // [(1, 2)] - // / \ - // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 1)] [(1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4)] - - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![(b(&[1, 2]), vec![])]); - assert_eq!(root.children_len(), 2); - - assert_eq!( - btree.range(b(&[0])..b(&[1])).collect::>(), - vec![ - (b(&[0, 1]), b(&[])), - (b(&[0, 2]), b(&[])), - (b(&[0, 3]), b(&[])), - (b(&[0, 4]), b(&[])), - ] - ); - - // Tests an offset that has a keys somewhere in the range of keys of an internal node. - assert_eq!( - btree.range(b(&[1, 3])..b(&[2])).collect::>(), - vec![(b(&[1, 3]), b(&[])), (b(&[1, 4]), b(&[])),] - ); - - // Tests an offset that's larger than the key in the internal node. - assert_eq!(btree.range(b(&[2, 5])..).collect::>(), vec![]); - }); - } - - #[test] - fn range_various_prefixes_with_offset_2() { - run_btree_test(|mut btree| { - btree.insert(b(&[0, 1]), b(&[])); - btree.insert(b(&[0, 2]), b(&[])); - btree.insert(b(&[0, 3]), b(&[])); - btree.insert(b(&[0, 4]), b(&[])); - btree.insert(b(&[1, 2]), b(&[])); - btree.insert(b(&[1, 4]), b(&[])); - btree.insert(b(&[1, 6]), b(&[])); - btree.insert(b(&[1, 8]), b(&[])); - btree.insert(b(&[1, 10]), b(&[])); - btree.insert(b(&[2, 1]), b(&[])); - btree.insert(b(&[2, 2]), b(&[])); - btree.insert(b(&[2, 3]), b(&[])); - btree.insert(b(&[2, 4]), b(&[])); - btree.insert(b(&[2, 5]), b(&[])); - btree.insert(b(&[2, 6]), b(&[])); - btree.insert(b(&[2, 7]), b(&[])); - btree.insert(b(&[2, 8]), b(&[])); - btree.insert(b(&[2, 9]), b(&[])); - - // The result should look like this: - // [(1, 4), (2, 3)] - // / | \ - // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2)] | [(2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9)] - // | - // [(1, 6), (1, 8), (1, 10), (2, 1), (2, 2)] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!( - root.entries(btree.memory()), - vec![(b(&[1, 4]), vec![]), (b(&[2, 3]), vec![])] - ); - assert_eq!(root.children_len(), 3); - - let child_0 = btree.load_node(root.child(0)); - assert_eq!(child_0.node_type(), NodeType::Leaf); - assert_eq!( - child_0.entries(btree.memory()), - vec![ - (b(&[0, 1]), vec![]), - (b(&[0, 2]), vec![]), - (b(&[0, 3]), vec![]), - (b(&[0, 4]), vec![]), - (b(&[1, 2]), vec![]), - ] - ); - - let child_1 = btree.load_node(root.child(1)); - assert_eq!(child_1.node_type(), NodeType::Leaf); - assert_eq!( - child_1.entries(btree.memory()), - vec![ - (b(&[1, 6]), vec![]), - (b(&[1, 8]), vec![]), - (b(&[1, 10]), vec![]), - (b(&[2, 1]), vec![]), - (b(&[2, 2]), vec![]), - ] - ); - - let child_2 = btree.load_node(root.child(2)); - assert_eq!( - child_2.entries(btree.memory()), - vec![ - (b(&[2, 4]), vec![]), - (b(&[2, 5]), vec![]), - (b(&[2, 6]), vec![]), - (b(&[2, 7]), vec![]), - (b(&[2, 8]), vec![]), - (b(&[2, 9]), vec![]), - ] - ); - - // Tests a offset that crosses several nodes. - assert_eq!( - btree.range(b(&[1, 4])..b(&[2])).collect::>(), - vec![ - (b(&[1, 4]), b(&[])), - (b(&[1, 6]), b(&[])), - (b(&[1, 8]), b(&[])), - (b(&[1, 10]), b(&[])), - ] - ); - - // Tests a offset that starts from a leaf node, then iterates through the root and right - // sibling. - assert_eq!( - btree.range(b(&[2, 2])..b(&[3])).collect::>(), - vec![ - (b(&[2, 2]), b(&[])), - (b(&[2, 3]), b(&[])), - (b(&[2, 4]), b(&[])), - (b(&[2, 5]), b(&[])), - (b(&[2, 6]), b(&[])), - (b(&[2, 7]), b(&[])), - (b(&[2, 8]), b(&[])), - (b(&[2, 9]), b(&[])), - ] - ); - }); - } - - #[test] - #[should_panic(expected = "max_key_size must be <= 4")] - fn v1_rejects_increases_in_max_key_size() { - let mem = make_memory(); - let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); - let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(btree.into_memory()); - } - - #[test] - fn v2_handles_increases_in_max_key_size_and_max_value_size() { - let mem = make_memory(); - let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::init(mem); - btree.insert( - [1u8; 4].as_slice().try_into().unwrap(), - [1u8; 4].as_slice().try_into().unwrap(), - ); - - // Reinitialize the BTree with larger keys and value sizes. - let mut btree: BTreeMap, Blob<5>, _> = BTreeMap::init(btree.into_memory()); - btree.insert( - [2u8; 5].as_slice().try_into().unwrap(), - [2u8; 5].as_slice().try_into().unwrap(), - ); - - // Still able to retrieve all the entries inserted. - assert_eq!( - btree.get(&([1u8; 4].as_slice().try_into().unwrap())), - Some([1u8; 4].as_slice().try_into().unwrap()) - ); - - assert_eq!( - btree.get(&([2u8; 5].as_slice().try_into().unwrap())), - Some([2u8; 5].as_slice().try_into().unwrap()) - ); - } - - #[test] - fn accepts_small_or_equal_key_sizes() { - let mem = make_memory(); - let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); - // Smaller key size - let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); - // Equal key size - let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); - } - - #[test] - #[should_panic(expected = "max_value_size must be <= 3")] - fn v1_rejects_larger_value_sizes() { - let mem = make_memory(); - let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); - let _btree: BTreeMap, Blob<4>, _> = BTreeMap::init_v1(btree.into_memory()); - } - - #[test] - fn accepts_small_or_equal_value_sizes() { - let mem = make_memory(); - let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); - // Smaller key size - let btree: BTreeMap, Blob<2>, _> = BTreeMap::init(btree.into_memory()); - // Equal key size - let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); - } - - #[test] - fn bruteforce_range_search() { - run_btree_test(|mut stable_map| { - use std::collections::BTreeMap; - const NKEYS: u64 = 60; - let mut std_map = BTreeMap::new(); - - for k in 0..NKEYS { - std_map.insert(k, k); - stable_map.insert(k, k); - } - - assert_eq!( - std_map.range(..).map(|(k, v)| (*k, *v)).collect::>(), - stable_map.range(..).collect::>() - ); - - for l in 0..=NKEYS { - assert_eq!( - std_map - .range(l..) - .map(|(k, v)| (*k, *v)) - .collect::>(), - stable_map.range(l..).collect::>() - ); - - assert_eq!( - std_map - .range(..l) - .map(|(k, v)| (*k, *v)) - .collect::>(), - stable_map.range(..l).collect::>() - ); - - assert_eq!( - std_map - .range(..=l) - .map(|(k, v)| (*k, *v)) - .collect::>(), - stable_map.range(..=l).collect::>() - ); - - for r in l + 1..=NKEYS { - for lbound in [Bound::Included(l), Bound::Excluded(l)] { - for rbound in [Bound::Included(r), Bound::Excluded(r)] { - let range = (lbound, rbound); - assert_eq!( - std_map - .range(range) - .map(|(k, v)| (*k, *v)) - .collect::>(), - stable_map.range(range).collect::>(), - "range: {range:?}" - ); - } - } - } - } - }); - } - - #[test] - fn test_iter_upper_bound() { - run_btree_test(|mut btree| { - for k in 0..100u64 { - btree.insert(k, ()); - for i in 0..=k { - assert_eq!( - Some((i, ())), - btree.iter_upper_bound(&(i + 1)).next(), - "failed to get an upper bound for key {}", - i + 1 - ); - } - assert_eq!( - None, - btree.iter_upper_bound(&0).next(), - "key 0 must not have an upper bound" - ); - } - }); - } - - // A buggy implementation of storable where the max_size is smaller than the serialized size. - #[derive(Clone, Ord, PartialOrd, Eq, PartialEq)] - struct BuggyStruct; - impl crate::Storable for BuggyStruct { - fn to_bytes(&self) -> Cow<[u8]> { - Cow::Borrowed(&[1, 2, 3, 4]) - } - - fn from_bytes(_: Cow<[u8]>) -> Self { - unimplemented!(); - } - - const BOUND: StorableBound = StorableBound::Bounded { - max_size: 1, - is_fixed_size: false, - }; - } - - #[test] - #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - fn v1_panics_if_key_is_bigger_than_max_size() { - let mut btree = BTreeMap::init_v1(make_memory()); - btree.insert(BuggyStruct, ()); - } - - #[test] - #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - fn v2_panics_if_key_is_bigger_than_max_size() { - let mut btree = BTreeMap::init(make_memory()); - btree.insert(BuggyStruct, ()); - } - - #[test] - #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - fn v1_panics_if_value_is_bigger_than_max_size() { - let mut btree = BTreeMap::init(make_memory()); - btree.insert((), BuggyStruct); - } - - #[test] - #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - fn v2_panics_if_value_is_bigger_than_max_size() { - let mut btree = BTreeMap::init(make_memory()); - btree.insert((), BuggyStruct); - } - - // To generate the memory dump file for the current version: - // cargo test create_btreemap_dump_file -- --include-ignored - #[test] - #[ignore] - fn create_btreemap_dump_file() { - let mem = make_memory(); - let mut btree = BTreeMap::init_v1(mem.clone()); - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - - use std::io::prelude::*; - let mut file = - std::fs::File::create(format!("dumps/btreemap_v{LAYOUT_VERSION}.dump")).unwrap(); - file.write_all(&mem.borrow()).unwrap(); - } - - #[test] - fn produces_layout_identical_to_layout_version_1_with_packed_headers() { - let mem = make_memory(); - let mut btree = BTreeMap::init_v1(mem.clone()); - assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - - let btreemap_v1 = include_bytes!("../dumps/btreemap_v1_packed_headers.dump"); - assert_eq!(*mem.borrow(), btreemap_v1); - } - - #[test] - fn read_write_header_is_identical_to_read_write_struct() { - #[repr(C, packed)] - struct BTreePackedHeader { - magic: [u8; 3], - version: u8, - max_key_size: u32, - max_value_size: u32, - root_addr: Address, - length: u64, - _buffer: [u8; 24], - } - let packed_header = BTreePackedHeader { - magic: *MAGIC, - version: LAYOUT_VERSION, - root_addr: Address::from(0xDEADBEEF), - max_key_size: 0x12345678, - max_value_size: 0x87654321, - length: 0xA1B2D3C4, - _buffer: [0; 24], - }; - - let packed_mem = make_memory(); - crate::write_struct(&packed_header, Address::from(0), &packed_mem); - - let v1_header = BTreeHeader { - version: Version::V1(DerivedPageSize { - max_key_size: 0x12345678, - max_value_size: 0x87654321, - }), - root_addr: Address::from(0xDEADBEEF), - length: 0xA1B2D3C4, - }; - - let v1_mem = make_memory(); - BTreeMap::, Vec<_>, RefCell>>::write_header(&v1_header, &v1_mem); - - assert_eq!(packed_mem, v1_mem); - - let packed_header: BTreePackedHeader = crate::read_struct(Address::from(0), &v1_mem); - let v1_header = BTreeMap::, Vec<_>, RefCell>>::read_header(&v1_mem); - assert!(packed_header.magic == *MAGIC); - assert!(packed_header.version == LAYOUT_VERSION); - match v1_header.version { - Version::V1(DerivedPageSize { - max_key_size, - max_value_size, - }) => { - assert!(packed_header.max_key_size == max_key_size); - assert!(packed_header.max_value_size == max_value_size); - } - _ => unreachable!("version must be v1"), - }; - - assert!(packed_header.root_addr == v1_header.root_addr); - assert!(packed_header.length == v1_header.length); - } - - #[test] - fn migrate_from_bounded_to_unbounded_and_back() { - // A type that is bounded. - #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] - struct T; - impl Storable for T { - fn to_bytes(&self) -> Cow<[u8]> { - Cow::Owned(vec![1, 2, 3]) - } - - fn from_bytes(bytes: Cow<[u8]>) -> Self { - assert_eq!(bytes.to_vec(), vec![1, 2, 3]); - T - } - - const BOUND: StorableBound = StorableBound::Bounded { - max_size: 3, - is_fixed_size: true, - }; - } - - // Same as the above type, but unbounded. - #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] - struct T2; - impl Storable for T2 { - fn to_bytes(&self) -> Cow<[u8]> { - Cow::Owned(vec![1, 2, 3]) - } - - fn from_bytes(bytes: Cow<[u8]>) -> Self { - assert_eq!(bytes.to_vec(), vec![1, 2, 3]); - T2 - } - - const BOUND: StorableBound = StorableBound::Unbounded; - } - - // Create a v1 btreemap with the bounded type. - let mem = make_memory(); - let mut btree: BTreeMap = BTreeMap::new_v1(mem); - btree.insert(T, T); - - // Migrate to v2 and the unbounded type. - let btree: BTreeMap = BTreeMap::init(btree.into_memory()); - btree.save_header(); - - // Reload the BTree again and try to read the value. - let btree: BTreeMap = BTreeMap::init(btree.into_memory()); - assert_eq!(btree.get(&T2), Some(T2)); - - // Reload the BTree again with bounded type. - let btree: BTreeMap = BTreeMap::init(btree.into_memory()); - assert_eq!(btree.get(&T), Some(T)); - } - - #[test] - fn test_clear_new_bounded_type() { - let mem = make_memory(); - let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::new(mem.clone()); - - btree.insert( - [1u8; 4].as_slice().try_into().unwrap(), - [1u8; 4].as_slice().try_into().unwrap(), - ); - - assert_ne!(btree.len(), 0); - assert_ne!(btree.allocator.num_allocated_chunks(), 0); - assert_ne!(btree.root_addr, NULL); - - btree.clear_new(); - - let header_actual = BTreeMap::, Blob<4>, _>::read_header(&mem); - - BTreeMap::, Blob<4>, _>::new(mem.clone()); - - let header_expected = BTreeMap::, Blob<4>, _>::read_header(&mem); - - assert_eq!(header_actual, header_expected); - } - - #[test] - fn test_clear_new_unbounded_type() { - let mem = make_memory(); - let mut btree: BTreeMap = BTreeMap::new(mem.clone()); - btree.insert("asd".into(), "bce".into()); - - assert_ne!(btree.len(), 0); - assert_ne!(btree.allocator.num_allocated_chunks(), 0); - assert_ne!(btree.root_addr, NULL); - - btree.clear_new(); - - let header_actual = BTreeMap::::read_header(&mem); - - BTreeMap::::new(mem.clone()); - - let header_expected = BTreeMap::::read_header(&mem); - - assert_eq!(header_actual, header_expected); - } - - #[test] - fn deallocating_node_with_overflows() { - let mem = make_memory(); - let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); - - // No allocated chunks yet. - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - - // Insert and remove an entry that's large and requires overflow pages. - btree.insert(vec![0; 10_000], vec![]); - - // At least two chunks should be allocated. - // One for the node itself and at least one overflow page. - assert!(btree.allocator.num_allocated_chunks() >= 2); - btree.remove(&vec![0; 10_000]); - - // All chunks have been deallocated. - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - } - - #[test] - fn repeatedly_deallocating_nodes_with_overflows() { - let mem = make_memory(); - let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); - - // No allocated chunks yet. - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - - for _ in 0..100 { - for i in 0..100 { - btree.insert(vec![i; 10_000], vec![]); - } - - for i in 0..100 { - btree.remove(&vec![i; 10_000]); - } - } - - // All chunks have been deallocated. - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - } - - #[test] - fn deallocating_root_does_not_leak_memory() { - let mem = make_memory(); - let mut btree: BTreeMap, _, _> = BTreeMap::new(mem.clone()); - - for i in 1..=11 { - // Large keys are stored so that each node overflows. - assert_eq!(btree.insert(vec![i; 10_000], ()), None); - } - - // Should now split a node. - assert_eq!(btree.insert(vec![0; 10_000], ()), None); - - // The btree should look like this: - // [6] - // / \ - // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.keys(), vec![vec![6; 10_000]]); - assert_eq!(root.children_len(), 2); - - // Remove the element in the root. - btree.remove(&vec![6; 10_000]); - - // The btree should look like this: - // [5] - // / \ - // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.keys(), vec![vec![5; 10_000]]); - assert_eq!(root.children_len(), 2); - - // Remove the element in the root. This triggers the case where the root - // node is deallocated and the children are merged into a single node. - btree.remove(&vec![5; 10_000]); - - // The btree should look like this: - // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11] - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Leaf); - assert_eq!( - root.keys(), - vec![ - vec![0; 10_000], - vec![1; 10_000], - vec![2; 10_000], - vec![3; 10_000], - vec![4; 10_000], - vec![7; 10_000], - vec![8; 10_000], - vec![9; 10_000], - vec![10; 10_000], - vec![11; 10_000], - ] - ); - - // Delete everything else. - for i in 0..=11 { - btree.remove(&vec![i; 10_000]); - } - - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - } + // #[test] + // fn insert_overwrite_key_in_full_root_node() { + // run_btree_test(|mut btree| { + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + + // // We now have a root that is full and looks like this: + // // + // // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + // let root = btree.load_node(btree.root_addr); + // assert!(root.is_full()); + + // // Overwrite an element in the root. It should NOT cause the node to be split. + // assert_eq!(btree.insert(b(&[6]), b(&[4, 5, 6])), Some(b(&[]))); + + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Leaf); + // assert_eq!(btree.get(&b(&[6])), Some(b(&[4, 5, 6]))); + // assert_eq!(root.entries_len(), 11); + // }); + // } + + // #[test] + // fn allocations() { + // run_btree_test(|mut btree| { + // // Insert entries until the root node is full. + // let mut i = 0; + // loop { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // let root = btree.load_node(btree.root_addr); + // if root.is_full() { + // break; + // } + // i += 1; + // } + + // // Only need a single allocation to store up to `CAPACITY` elements. + // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + + // assert_eq!(btree.insert(b(&[255]), b(&[])), None); + + // // The node had to be split into three nodes. + // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + // }); + // } + + // #[test] + // fn allocations_2() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + // assert_eq!(btree.insert(b(&[]), b(&[])), None); + // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + + // assert_eq!(btree.remove(&b(&[])), Some(b(&[]))); + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // }); + // } + + // #[test] + // fn pop_last_single_entry() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + // assert_eq!(btree.insert(b(&[]), b(&[])), None); + // assert!(!btree.is_empty()); + // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + + // assert_eq!(btree.pop_last(), Some((b(&[]), b(&[])))); + // assert!(btree.is_empty()); + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // }); + // } + + // #[test] + // fn pop_first_single_entry() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + // assert_eq!(btree.insert(b(&[]), b(&[])), None); + // assert!(!btree.is_empty()); + // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + + // assert_eq!(btree.pop_first(), Some((b(&[]), b(&[])))); + // assert!(btree.is_empty()); + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // }); + // } + + // #[test] + // fn insert_same_key_multiple() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(b(&[1]), b(&[2])), None); + // for i in 2..10 { + // assert_eq!(btree.insert(b(&[1]), b(&[i + 1])), Some(b(&[i]))); + // } + // assert_eq!(btree.get(&b(&[1])), Some(b(&[10]))); + // }); + // } + + // #[test] + // fn insert_split_node() { + // run_btree_test(|mut btree| { + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + + // // Should now split a node. + // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + + // // The result should look like this: + // // [6] + // // / \ + // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + + // for i in 1..=12 { + // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); + // } + // }); + // } + + // #[test] + // fn insert_split_multiple_nodes() { + // run_btree_test(|mut btree| { + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + // // Should now split a node. + // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + + // // The result should look like this: + // // [6] + // // / \ + // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![e(6)]); + // assert_eq!(root.children_len(), 2); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![e(1), e(2), e(3), e(4), e(5)] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![e(7), e(8), e(9), e(10), e(11), e(12)] + // ); + + // for i in 1..=12 { + // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); + // } + + // // Insert more to cause more splitting. + // assert_eq!(btree.insert(b(&[13]), b(&[])), None); + // assert_eq!(btree.insert(b(&[14]), b(&[])), None); + // assert_eq!(btree.insert(b(&[15]), b(&[])), None); + // assert_eq!(btree.insert(b(&[16]), b(&[])), None); + // assert_eq!(btree.insert(b(&[17]), b(&[])), None); + // // Should cause another split + // assert_eq!(btree.insert(b(&[18]), b(&[])), None); + + // for i in 1..=18 { + // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); + // } + + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![e(6), e(12)],); + // assert_eq!(root.children_len(), 3); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![e(1), e(2), e(3), e(4), e(5)] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![e(7), e(8), e(9), e(10), e(11)] + // ); + + // let child_2 = btree.load_node(root.child(2)); + // assert_eq!(child_2.node_type(), NodeType::Leaf); + // assert_eq!( + // child_2.entries(btree.memory()), + // vec![e(13), e(14), e(15), e(16), e(17), e(18)] + // ); + // }); + // } + + // #[test] + // fn remove_simple() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); + // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + // assert_eq!(btree.remove(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + // assert_eq!(btree.get(&b(&[1, 2, 3])), None); + // }); + // } + + // #[test] + // fn pop_last_simple() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); + // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + // assert_eq!(btree.pop_last().unwrap().1, b(&[4, 5, 6])); + // assert_eq!(btree.get(&b(&[1, 2, 3])), None); + // }); + // } + + // #[test] + // fn pop_first_simple() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); + // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + // assert_eq!(btree.pop_first().map(|e| e.1), Some(b(&[4, 5, 6]))); + // assert_eq!(btree.get(&b(&[1, 2, 3])), None); + // }); + // } + + // #[test] + // fn pop_on_empty_tree_simple() { + // run_btree_test( + // |mut btree: BTreeMap, Blob<10>, Rc>>>| { + // assert_eq!(btree.pop_last(), None); + // assert_eq!(btree.pop_first(), None); + // }, + // ); + // } + + // #[test] + // fn last_key_value_empty_tree_simple() { + // run_btree_test( + // |btree: BTreeMap, Blob<10>, Rc>>>| { + // assert_eq!(btree.last_key_value(), None); + // }, + // ); + // } + + // #[test] + // fn first_key_value_empty_tree_simple() { + // run_btree_test( + // |btree: BTreeMap, Blob<10>, Rc>>>| { + // assert_eq!(btree.first_key_value(), None); + // }, + // ); + // } + + // #[test] + // fn remove_case_2a_and_2c() { + // run_btree_test(|mut btree| { + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + // // Should now split a node. + // assert_eq!(btree.insert(b(&[0]), b(&[])), None); + + // // The result should look like this: + // // [6] + // // / \ + // // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] + + // for i in 0..=11 { + // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); + // } + + // // Remove node 6. Triggers case 2.a + // assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); + + // // The result should look like this: + // // [5] + // // / \ + // // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![e(5)]); + // assert_eq!(root.children_len(), 2); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![e(0), e(1), e(2), e(3), e(4)] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![e(7), e(8), e(9), e(10), e(11)] + // ); + + // // There are three allocated nodes. + // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + + // // Remove node 5. Triggers case 2c + // assert_eq!(btree.remove(&b(&[5])), Some(b(&[]))); + + // // Reload the btree to verify that we saved it correctly. + // let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); + + // // The result should look like this: + // // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11] + // let root = btree.load_node(btree.root_addr); + // assert_eq!( + // root.entries(btree.memory()), + // vec![e(0), e(1), e(2), e(3), e(4), e(7), e(8), e(9), e(10), e(11)] + // ); + + // // There is only one node allocated. + // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + // }); + // } + + // #[test] + // fn remove_case_2b() { + // run_btree_test(|mut btree| { + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + // // Should now split a node. + // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + + // // The result should look like this: + // // [6] + // // / \ + // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + + // for i in 1..=12 { + // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); + // } + + // // Remove node 6. Triggers case 2.b + // assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); + + // // The result should look like this: + // // [7] + // // / \ + // // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![e(7)]); + // assert_eq!(root.children_len(), 2); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![e(1), e(2), e(3), e(4), e(5)] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![e(8), e(9), e(10), e(11), e(12)] + // ); + + // // Remove node 7. Triggers case 2.c + // assert_eq!(btree.remove(&b(&[7])), Some(b(&[]))); + // // The result should look like this: + // // + // // [1, 2, 3, 4, 5, 8, 9, 10, 11, 12] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Leaf); + // assert_eq!( + // root.entries(btree.memory()), + // vec![ + // e(1), + // e(2), + // e(3), + // e(4), + // e(5), + // e(8), + // e(9), + // e(10), + // e(11), + // e(12) + // ] + // ); + // }); + // } + + // #[test] + // fn remove_case_3a_right() { + // run_btree_test(|mut btree| { + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + + // // Should now split a node. + // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + + // // The result should look like this: + // // [6] + // // / \ + // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + + // // Remove node 3. Triggers case 3.a + // assert_eq!(btree.remove(&b(&[3])), Some(b(&[]))); + + // // The result should look like this: + // // [7] + // // / \ + // // [1, 2, 4, 5, 6] [8, 9, 10, 11, 12] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![e(7)]); + // assert_eq!(root.children_len(), 2); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![e(1), e(2), e(4), e(5), e(6)] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![e(8), e(9), e(10), e(11), e(12)] + // ); + + // // There are three allocated nodes. + // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + // }); + // } + + // #[test] + // fn remove_case_3a_left() { + // run_btree_test(|mut btree| { + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + // // Should now split a node. + // assert_eq!(btree.insert(b(&[0]), b(&[])), None); + + // // The result should look like this: + // // [6] + // // / \ + // // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] + + // // Remove node 8. Triggers case 3.a left + // assert_eq!(btree.remove(&b(&[8])), Some(b(&[]))); + + // // The result should look like this: + // // [5] + // // / \ + // // [0, 1, 2, 3, 4] [6, 7, 9, 10, 11] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![e(5)]); + // assert_eq!(root.children_len(), 2); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![e(0), e(1), e(2), e(3), e(4)] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![e(6), e(7), e(9), e(10), e(11)] + // ); + + // // There are three allocated nodes. + // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + // }); + // } + + // #[test] + // fn remove_case_3b_merge_into_right() { + // run_btree_test(|mut btree| { + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + // // Should now split a node. + // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + + // // The result should look like this: + // // [6] + // // / \ + // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + + // for i in 1..=12 { + // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); + // } + + // // Remove node 6. Triggers case 2.b + // assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); + // // The result should look like this: + // // [7] + // // / \ + // // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![e(7)]); + // assert_eq!(root.children_len(), 2); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![e(1), e(2), e(3), e(4), e(5)] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![e(8), e(9), e(10), e(11), e(12)] + // ); + + // // There are three allocated nodes. + // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + + // // Remove node 3. Triggers case 3.b + // assert_eq!(btree.remove(&b(&[3])), Some(b(&[]))); + + // // Reload the btree to verify that we saved it correctly. + // let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); + + // // The result should look like this: + // // + // // [1, 2, 4, 5, 7, 8, 9, 10, 11, 12] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Leaf); + // assert_eq!( + // root.entries(btree.memory()), + // vec![ + // e(1), + // e(2), + // e(4), + // e(5), + // e(7), + // e(8), + // e(9), + // e(10), + // e(11), + // e(12) + // ] + // ); + + // // There is only one allocated node remaining. + // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + // }); + // } + + // #[test] + // fn remove_case_3b_merge_into_left() { + // let mem = make_memory(); + // let mut btree = BTreeMap::new(mem.clone()); + + // for i in 1..=11 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + + // // Should now split a node. + // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + + // // The result should look like this: + // // [6] + // // / \ + // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + + // for i in 1..=12 { + // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); + // } + + // // Remove node 6. Triggers case 2.b + // assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); + + // // The result should look like this: + // // [7] + // // / \ + // // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![e(7)]); + // assert_eq!(root.children_len(), 2); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![e(1), e(2), e(3), e(4), e(5)] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![e(8), e(9), e(10), e(11), e(12)] + // ); + + // // There are three allocated nodes. + // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + + // // Remove node 10. Triggers case 3.b where we merge the right into the left. + // assert_eq!(btree.remove(&b(&[10])), Some(b(&[]))); + + // // Reload the btree to verify that we saved it correctly. + // let btree = BTreeMap::, Blob<10>, _>::load(mem); + + // // The result should look like this: + // // + // // [1, 2, 3, 4, 5, 7, 8, 9, 11, 12] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Leaf); + // assert_eq!( + // root.entries(btree.memory()), + // vec![e(1), e(2), e(3), e(4), e(5), e(7), e(8), e(9), e(11), e(12)] + // ); + + // // There is only one allocated node remaining. + // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + // } + + // #[test] + // fn many_insertions() { + // let mem = make_memory(); + // let mut btree = BTreeMap::new(mem.clone()); + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.insert(b(&[i, j]), b(&[i, j])), None); + // } + // } + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.get(&b(&[i, j])), Some(b(&[i, j]))); + // } + // } + + // let mut btree = BTreeMap::load(mem); + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.remove(&b(&[i, j])), Some(b(&[i, j]))); + // } + // } + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.get(&b(&[i, j])), None); + // } + // } + + // // We've deallocated everything. + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // } + + // #[test] + // fn many_insertions_2() { + // let mem = make_memory(); + // let mut btree = BTreeMap::new(mem.clone()); + + // for j in (0..=10).rev() { + // for i in (0..=255).rev() { + // assert_eq!(btree.insert(b(&[i, j]), b(&[i, j])), None); + // } + // } + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.get(&b(&[i, j])), Some(b(&[i, j]))); + // } + // } + + // let mut btree = BTreeMap::load(mem); + + // for j in (0..=10).rev() { + // for i in (0..=255).rev() { + // assert_eq!(btree.remove(&b(&[i, j])), Some(b(&[i, j]))); + // } + // } + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.get(&b(&[i, j])), None); + // } + // } + + // // We've deallocated everything. + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // } + + // #[test] + // fn pop_first_many_entries() { + // let mem = make_memory(); + // let mut std_btree = std::collections::BTreeMap::new(); + // let mut btree = BTreeMap::new(mem.clone()); + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!( + // btree.insert(b(&[i, j]), b(&[i, j])), + // std_btree.insert(b(&[i, j]), b(&[i, j])) + // ); + // } + // } + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.get(&b(&[i, j])), std_btree.get(&b(&[i, j])).cloned()); + // } + // } + + // let mut btree = BTreeMap::load(mem); + + // for _ in 0..=10 { + // for _ in 0..=255 { + // assert_eq!(btree.pop_first(), std_btree.pop_first()); + // } + // } + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.get(&b(&[i, j])), None); + // assert_eq!(std_btree.get(&b(&[i, j])), None); + // } + // } + + // // We've deallocated everything. + // assert!(std_btree.is_empty()); + // assert!(btree.is_empty()); + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // } + + // #[test] + // fn pop_last_many_entries() { + // let mem = make_memory(); + // let mut std_btree = std::collections::BTreeMap::new(); + // let mut btree = BTreeMap::new(mem.clone()); + + // for j in (0..=10).rev() { + // for i in (0..=255).rev() { + // assert_eq!( + // btree.insert(b(&[i, j]), b(&[i, j])), + // std_btree.insert(b(&[i, j]), b(&[i, j])) + // ); + // } + // } + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.get(&b(&[i, j])), std_btree.get(&b(&[i, j])).cloned()); + // } + // } + + // let mut btree = BTreeMap::load(mem); + + // for _ in (0..=10).rev() { + // for _ in (0..=255).rev() { + // assert_eq!(btree.pop_last(), std_btree.pop_last()); + // } + // } + + // for j in 0..=10 { + // for i in 0..=255 { + // assert_eq!(btree.get(&b(&[i, j])), None); + // assert_eq!(std_btree.get(&b(&[i, j])), None); + // } + // } + + // // We've deallocated everything. + // assert!(std_btree.is_empty()); + // assert!(btree.is_empty()); + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // } + + // #[test] + // fn reloading() { + // run_btree_test(|mut btree| { + // // The btree is initially empty. + // assert_eq!(btree.len(), 0); + // assert!(btree.is_empty()); + + // // Add an entry into the btree. + // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); + // assert_eq!(btree.len(), 1); + // assert!(!btree.is_empty()); + + // // Reload the btree. The element should still be there, and `len()` + // // should still be `1`. + // let btree = BTreeMap::load(btree.into_memory()); + // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + // assert_eq!(btree.len(), 1); + // assert!(!btree.is_empty()); + + // // Remove an element. Length should be zero. + // let mut btree = BTreeMap::load(btree.into_memory()); + // assert_eq!(btree.remove(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + // assert_eq!(btree.len(), 0); + // assert!(btree.is_empty()); + + // // Reload. Btree should still be empty. + // let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); + // assert_eq!(btree.get(&b(&[1, 2, 3])), None); + // assert_eq!(btree.len(), 0); + // assert!(btree.is_empty()); + // }); + // } + + // #[test] + // fn len() { + // run_btree_test(|mut btree| { + // for i in 0..1000u32 { + // assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); + // } + + // assert_eq!(btree.len(), 1000); + // assert!(!btree.is_empty()); + + // for i in 0..1000u32 { + // assert_eq!(btree.remove(&b(&i.to_le_bytes())), Some(b(&[]))); + // } + + // assert_eq!(btree.len(), 0); + // assert!(btree.is_empty()); + // }); + // } + + // #[test] + // fn pop_first_len() { + // run_btree_test(|mut btree| { + // for i in 0..1000u32 { + // assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); + // } + + // assert_eq!(btree.len(), 1000); + // assert!(!btree.is_empty()); + + // for i in 0..1000u32 { + // assert_eq!(btree.pop_first().unwrap().1, b(&i.to_le_bytes())); + // } + + // assert_eq!(btree.len(), 0); + // assert!(btree.is_empty()); + // }); + // } + + // #[test] + // fn pop_last_len() { + // run_btree_test(|mut btree| { + // for i in 0..1000u32 { + // assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); + // } + + // assert_eq!(btree.len(), 1000); + // assert!(!btree.is_empty()); + + // for i in (0..1000u32).rev() { + // assert_eq!(btree.pop_last().unwrap().1, b(&i.to_le_bytes())); + // } + + // assert_eq!(btree.len(), 0); + // assert!(btree.is_empty()); + // }); + // } + + // #[test] + // fn contains_key() { + // run_btree_test(|mut btree| { + // // Insert even numbers from 0 to 1000. + // for i in (0..1000u32).step_by(2) { + // assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); + // } + + // // Contains key should return true on all the even numbers and false on all the odd + // // numbers. + // for i in 0..1000u32 { + // assert_eq!(btree.contains_key(&b(&i.to_le_bytes())), i % 2 == 0); + // } + // }); + // } + + // #[test] + // fn range_empty() { + // run_btree_test(|btree| { + // // Test prefixes that don't exist in the map. + // assert_eq!( + // btree + // .range(b(&[0])..) + // .collect::, Blob<10>)>>(), + // vec![] + // ); + // assert_eq!(btree.range(b(&[1, 2, 3, 4])..).collect::>(), vec![]); + // }); + // } + + // // Tests the case where the prefix is larger than all the entries in a leaf node. + // #[test] + // fn range_leaf_prefix_greater_than_all_entries() { + // run_btree_test(|mut btree| { + // btree.insert(b(&[0]), b(&[])); + + // // Test a prefix that's larger than the value in the leaf node. Should be empty. + // assert_eq!(btree.range(b(&[1])..).collect::>(), vec![]); + // }); + // } + + // // Tests the case where the prefix is larger than all the entries in an internal node. + // #[test] + // fn range_internal_prefix_greater_than_all_entries() { + // run_btree_test(|mut btree| { + // for i in 1..=12 { + // assert_eq!(btree.insert(b(&[i]), b(&[])), None); + // } + + // // The result should look like this: + // // [6] + // // / \ + // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + + // // Test a prefix that's larger than the key in the internal node. + // assert_eq!( + // btree.range(b(&[7])..b(&[8])).collect::>(), + // vec![(b(&[7]), b(&[]))] + // ); + // }); + // } + + // #[test] + // fn range_various_prefixes() { + // run_btree_test(|mut btree| { + // btree.insert(b(&[0, 1]), b(&[])); + // btree.insert(b(&[0, 2]), b(&[])); + // btree.insert(b(&[0, 3]), b(&[])); + // btree.insert(b(&[0, 4]), b(&[])); + // btree.insert(b(&[1, 1]), b(&[])); + // btree.insert(b(&[1, 2]), b(&[])); + // btree.insert(b(&[1, 3]), b(&[])); + // btree.insert(b(&[1, 4]), b(&[])); + // btree.insert(b(&[2, 1]), b(&[])); + // btree.insert(b(&[2, 2]), b(&[])); + // btree.insert(b(&[2, 3]), b(&[])); + // btree.insert(b(&[2, 4]), b(&[])); + + // // The result should look like this: + // // [(1, 2)] + // // / \ + // // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 1)] [(1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4)] + + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![(b(&[1, 2]), vec![])]); + // assert_eq!(root.children_len(), 2); + + // // Tests a prefix that's smaller than the key in the internal node. + // assert_eq!( + // btree.range(b(&[0])..b(&[1])).collect::>(), + // vec![ + // (b(&[0, 1]), b(&[])), + // (b(&[0, 2]), b(&[])), + // (b(&[0, 3]), b(&[])), + // (b(&[0, 4]), b(&[])), + // ] + // ); + + // // Tests a prefix that crosses several nodes. + // assert_eq!( + // btree.range(b(&[1])..b(&[2])).collect::>(), + // vec![ + // (b(&[1, 1]), b(&[])), + // (b(&[1, 2]), b(&[])), + // (b(&[1, 3]), b(&[])), + // (b(&[1, 4]), b(&[])), + // ] + // ); + + // // Tests a prefix that's larger than the key in the internal node. + // assert_eq!( + // btree.range(b(&[2])..b(&[3])).collect::>(), + // vec![ + // (b(&[2, 1]), b(&[])), + // (b(&[2, 2]), b(&[])), + // (b(&[2, 3]), b(&[])), + // (b(&[2, 4]), b(&[])), + // ] + // ); + // }); + // } + + // #[test] + // fn range_various_prefixes_2() { + // run_btree_test(|mut btree| { + // btree.insert(b(&[0, 1]), b(&[])); + // btree.insert(b(&[0, 2]), b(&[])); + // btree.insert(b(&[0, 3]), b(&[])); + // btree.insert(b(&[0, 4]), b(&[])); + // btree.insert(b(&[1, 2]), b(&[])); + // btree.insert(b(&[1, 4]), b(&[])); + // btree.insert(b(&[1, 6]), b(&[])); + // btree.insert(b(&[1, 8]), b(&[])); + // btree.insert(b(&[1, 10]), b(&[])); + // btree.insert(b(&[2, 1]), b(&[])); + // btree.insert(b(&[2, 2]), b(&[])); + // btree.insert(b(&[2, 3]), b(&[])); + // btree.insert(b(&[2, 4]), b(&[])); + // btree.insert(b(&[2, 5]), b(&[])); + // btree.insert(b(&[2, 6]), b(&[])); + // btree.insert(b(&[2, 7]), b(&[])); + // btree.insert(b(&[2, 8]), b(&[])); + // btree.insert(b(&[2, 9]), b(&[])); + + // // The result should look like this: + // // [(1, 4), (2, 3)] + // // / | \ + // // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2)] | [(2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9)] + // // | + // // [(1, 6), (1, 8), (1, 10), (2, 1), (2, 2)] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!( + // root.entries(btree.memory()), + // vec![(b(&[1, 4]), vec![]), (b(&[2, 3]), vec![])] + // ); + // assert_eq!(root.children_len(), 3); + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![ + // (b(&[0, 1]), vec![]), + // (b(&[0, 2]), vec![]), + // (b(&[0, 3]), vec![]), + // (b(&[0, 4]), vec![]), + // (b(&[1, 2]), vec![]), + // ] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![ + // (b(&[1, 6]), vec![]), + // (b(&[1, 8]), vec![]), + // (b(&[1, 10]), vec![]), + // (b(&[2, 1]), vec![]), + // (b(&[2, 2]), vec![]), + // ] + // ); + + // let child_2 = btree.load_node(root.child(2)); + // assert_eq!( + // child_2.entries(btree.memory()), + // vec![ + // (b(&[2, 4]), vec![]), + // (b(&[2, 5]), vec![]), + // (b(&[2, 6]), vec![]), + // (b(&[2, 7]), vec![]), + // (b(&[2, 8]), vec![]), + // (b(&[2, 9]), vec![]), + // ] + // ); + + // // Tests a prefix that doesn't exist, but is in the middle of the root node. + // assert_eq!( + // btree.range(b(&[1, 5])..b(&[1, 6])).collect::>(), + // vec![] + // ); + + // // Tests a prefix beginning in the middle of the tree and crossing several nodes. + // assert_eq!( + // btree.range(b(&[1, 5])..=b(&[2, 6])).collect::>(), + // vec![ + // (b(&[1, 6]), b(&[])), + // (b(&[1, 8]), b(&[])), + // (b(&[1, 10]), b(&[])), + // (b(&[2, 1]), b(&[])), + // (b(&[2, 2]), b(&[])), + // (b(&[2, 3]), b(&[])), + // (b(&[2, 4]), b(&[])), + // (b(&[2, 5]), b(&[])), + // (b(&[2, 6]), b(&[])), + // ] + // ); + + // // Tests a prefix that crosses several nodes. + // assert_eq!( + // btree.range(b(&[1])..b(&[2])).collect::>(), + // vec![ + // (b(&[1, 2]), b(&[])), + // (b(&[1, 4]), b(&[])), + // (b(&[1, 6]), b(&[])), + // (b(&[1, 8]), b(&[])), + // (b(&[1, 10]), b(&[])), + // ] + // ); + + // // Tests a prefix that starts from a leaf node, then iterates through the root and right + // // sibling. + // assert_eq!( + // btree.range(b(&[2])..).collect::>(), + // vec![ + // (b(&[2, 1]), b(&[])), + // (b(&[2, 2]), b(&[])), + // (b(&[2, 3]), b(&[])), + // (b(&[2, 4]), b(&[])), + // (b(&[2, 5]), b(&[])), + // (b(&[2, 6]), b(&[])), + // (b(&[2, 7]), b(&[])), + // (b(&[2, 8]), b(&[])), + // (b(&[2, 9]), b(&[])), + // ] + // ); + // }); + // } + + // #[test] + // fn range_large() { + // run_btree_test(|mut btree| { + // // Insert 1000 elements with prefix 0 and another 1000 elements with prefix 1. + // for prefix in 0..=1 { + // for i in 0..1000u32 { + // assert_eq!( + // btree.insert( + // // The key is the prefix followed by the integer's encoding. + // // The encoding is big-endian so that the byte representation of the + // // integers are sorted. + // b([vec![prefix], i.to_be_bytes().to_vec()] + // .into_iter() + // .flatten() + // .collect::>() + // .as_slice()), + // b(&[]) + // ), + // None + // ); + // } + // } + + // // Getting the range with a prefix should return all 1000 elements with that prefix. + // for prefix in 0..=1 { + // let mut i: u32 = 0; + // for (key, _) in btree.range(b(&[prefix])..b(&[prefix + 1])) { + // assert_eq!( + // key, + // b(&[vec![prefix], i.to_be_bytes().to_vec()] + // .into_iter() + // .flatten() + // .collect::>()) + // ); + // i += 1; + // } + // assert_eq!(i, 1000); + // } + // }); + // } + + // #[test] + // fn range_various_prefixes_with_offset() { + // run_btree_test(|mut btree| { + // btree.insert(b(&[0, 1]), b(&[])); + // btree.insert(b(&[0, 2]), b(&[])); + // btree.insert(b(&[0, 3]), b(&[])); + // btree.insert(b(&[0, 4]), b(&[])); + // btree.insert(b(&[1, 1]), b(&[])); + // btree.insert(b(&[1, 2]), b(&[])); + // btree.insert(b(&[1, 3]), b(&[])); + // btree.insert(b(&[1, 4]), b(&[])); + // btree.insert(b(&[2, 1]), b(&[])); + // btree.insert(b(&[2, 2]), b(&[])); + // btree.insert(b(&[2, 3]), b(&[])); + // btree.insert(b(&[2, 4]), b(&[])); + + // // The result should look like this: + // // [(1, 2)] + // // / \ + // // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 1)] [(1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4)] + + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![(b(&[1, 2]), vec![])]); + // assert_eq!(root.children_len(), 2); + + // assert_eq!( + // btree.range(b(&[0])..b(&[1])).collect::>(), + // vec![ + // (b(&[0, 1]), b(&[])), + // (b(&[0, 2]), b(&[])), + // (b(&[0, 3]), b(&[])), + // (b(&[0, 4]), b(&[])), + // ] + // ); + + // // Tests an offset that has a keys somewhere in the range of keys of an internal node. + // assert_eq!( + // btree.range(b(&[1, 3])..b(&[2])).collect::>(), + // vec![(b(&[1, 3]), b(&[])), (b(&[1, 4]), b(&[])),] + // ); + + // // Tests an offset that's larger than the key in the internal node. + // assert_eq!(btree.range(b(&[2, 5])..).collect::>(), vec![]); + // }); + // } + + // #[test] + // fn range_various_prefixes_with_offset_2() { + // run_btree_test(|mut btree| { + // btree.insert(b(&[0, 1]), b(&[])); + // btree.insert(b(&[0, 2]), b(&[])); + // btree.insert(b(&[0, 3]), b(&[])); + // btree.insert(b(&[0, 4]), b(&[])); + // btree.insert(b(&[1, 2]), b(&[])); + // btree.insert(b(&[1, 4]), b(&[])); + // btree.insert(b(&[1, 6]), b(&[])); + // btree.insert(b(&[1, 8]), b(&[])); + // btree.insert(b(&[1, 10]), b(&[])); + // btree.insert(b(&[2, 1]), b(&[])); + // btree.insert(b(&[2, 2]), b(&[])); + // btree.insert(b(&[2, 3]), b(&[])); + // btree.insert(b(&[2, 4]), b(&[])); + // btree.insert(b(&[2, 5]), b(&[])); + // btree.insert(b(&[2, 6]), b(&[])); + // btree.insert(b(&[2, 7]), b(&[])); + // btree.insert(b(&[2, 8]), b(&[])); + // btree.insert(b(&[2, 9]), b(&[])); + + // // The result should look like this: + // // [(1, 4), (2, 3)] + // // / | \ + // // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2)] | [(2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9)] + // // | + // // [(1, 6), (1, 8), (1, 10), (2, 1), (2, 2)] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!( + // root.entries(btree.memory()), + // vec![(b(&[1, 4]), vec![]), (b(&[2, 3]), vec![])] + // ); + // assert_eq!(root.children_len(), 3); + + // let child_0 = btree.load_node(root.child(0)); + // assert_eq!(child_0.node_type(), NodeType::Leaf); + // assert_eq!( + // child_0.entries(btree.memory()), + // vec![ + // (b(&[0, 1]), vec![]), + // (b(&[0, 2]), vec![]), + // (b(&[0, 3]), vec![]), + // (b(&[0, 4]), vec![]), + // (b(&[1, 2]), vec![]), + // ] + // ); + + // let child_1 = btree.load_node(root.child(1)); + // assert_eq!(child_1.node_type(), NodeType::Leaf); + // assert_eq!( + // child_1.entries(btree.memory()), + // vec![ + // (b(&[1, 6]), vec![]), + // (b(&[1, 8]), vec![]), + // (b(&[1, 10]), vec![]), + // (b(&[2, 1]), vec![]), + // (b(&[2, 2]), vec![]), + // ] + // ); + + // let child_2 = btree.load_node(root.child(2)); + // assert_eq!( + // child_2.entries(btree.memory()), + // vec![ + // (b(&[2, 4]), vec![]), + // (b(&[2, 5]), vec![]), + // (b(&[2, 6]), vec![]), + // (b(&[2, 7]), vec![]), + // (b(&[2, 8]), vec![]), + // (b(&[2, 9]), vec![]), + // ] + // ); + + // // Tests a offset that crosses several nodes. + // assert_eq!( + // btree.range(b(&[1, 4])..b(&[2])).collect::>(), + // vec![ + // (b(&[1, 4]), b(&[])), + // (b(&[1, 6]), b(&[])), + // (b(&[1, 8]), b(&[])), + // (b(&[1, 10]), b(&[])), + // ] + // ); + + // // Tests a offset that starts from a leaf node, then iterates through the root and right + // // sibling. + // assert_eq!( + // btree.range(b(&[2, 2])..b(&[3])).collect::>(), + // vec![ + // (b(&[2, 2]), b(&[])), + // (b(&[2, 3]), b(&[])), + // (b(&[2, 4]), b(&[])), + // (b(&[2, 5]), b(&[])), + // (b(&[2, 6]), b(&[])), + // (b(&[2, 7]), b(&[])), + // (b(&[2, 8]), b(&[])), + // (b(&[2, 9]), b(&[])), + // ] + // ); + // }); + // } + + // #[test] + // #[should_panic(expected = "max_key_size must be <= 4")] + // fn v1_rejects_increases_in_max_key_size() { + // let mem = make_memory(); + // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); + // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(btree.into_memory()); + // } + + // #[test] + // fn v2_handles_increases_in_max_key_size_and_max_value_size() { + // let mem = make_memory(); + // let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::init(mem); + // btree.insert( + // [1u8; 4].as_slice().try_into().unwrap(), + // [1u8; 4].as_slice().try_into().unwrap(), + // ); + + // // Reinitialize the BTree with larger keys and value sizes. + // let mut btree: BTreeMap, Blob<5>, _> = BTreeMap::init(btree.into_memory()); + // btree.insert( + // [2u8; 5].as_slice().try_into().unwrap(), + // [2u8; 5].as_slice().try_into().unwrap(), + // ); + + // // Still able to retrieve all the entries inserted. + // assert_eq!( + // btree.get(&([1u8; 4].as_slice().try_into().unwrap())), + // Some([1u8; 4].as_slice().try_into().unwrap()) + // ); + + // assert_eq!( + // btree.get(&([2u8; 5].as_slice().try_into().unwrap())), + // Some([2u8; 5].as_slice().try_into().unwrap()) + // ); + // } + + // #[test] + // fn accepts_small_or_equal_key_sizes() { + // let mem = make_memory(); + // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); + // // Smaller key size + // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); + // // Equal key size + // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); + // } + + // #[test] + // #[should_panic(expected = "max_value_size must be <= 3")] + // fn v1_rejects_larger_value_sizes() { + // let mem = make_memory(); + // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); + // let _btree: BTreeMap, Blob<4>, _> = BTreeMap::init_v1(btree.into_memory()); + // } + + // #[test] + // fn accepts_small_or_equal_value_sizes() { + // let mem = make_memory(); + // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); + // // Smaller key size + // let btree: BTreeMap, Blob<2>, _> = BTreeMap::init(btree.into_memory()); + // // Equal key size + // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); + // } + + // #[test] + // fn bruteforce_range_search() { + // run_btree_test(|mut stable_map| { + // use std::collections::BTreeMap; + // const NKEYS: u64 = 60; + // let mut std_map = BTreeMap::new(); + + // for k in 0..NKEYS { + // std_map.insert(k, k); + // stable_map.insert(k, k); + // } + + // assert_eq!( + // std_map.range(..).map(|(k, v)| (*k, *v)).collect::>(), + // stable_map.range(..).collect::>() + // ); + + // for l in 0..=NKEYS { + // assert_eq!( + // std_map + // .range(l..) + // .map(|(k, v)| (*k, *v)) + // .collect::>(), + // stable_map.range(l..).collect::>() + // ); + + // assert_eq!( + // std_map + // .range(..l) + // .map(|(k, v)| (*k, *v)) + // .collect::>(), + // stable_map.range(..l).collect::>() + // ); + + // assert_eq!( + // std_map + // .range(..=l) + // .map(|(k, v)| (*k, *v)) + // .collect::>(), + // stable_map.range(..=l).collect::>() + // ); + + // for r in l + 1..=NKEYS { + // for lbound in [Bound::Included(l), Bound::Excluded(l)] { + // for rbound in [Bound::Included(r), Bound::Excluded(r)] { + // let range = (lbound, rbound); + // assert_eq!( + // std_map + // .range(range) + // .map(|(k, v)| (*k, *v)) + // .collect::>(), + // stable_map.range(range).collect::>(), + // "range: {range:?}" + // ); + // } + // } + // } + // } + // }); + // } + + // #[test] + // fn test_iter_upper_bound() { + // run_btree_test(|mut btree| { + // for k in 0..100u64 { + // btree.insert(k, ()); + // for i in 0..=k { + // assert_eq!( + // Some((i, ())), + // btree.iter_upper_bound(&(i + 1)).next(), + // "failed to get an upper bound for key {}", + // i + 1 + // ); + // } + // assert_eq!( + // None, + // btree.iter_upper_bound(&0).next(), + // "key 0 must not have an upper bound" + // ); + // } + // }); + // } + + // // A buggy implementation of storable where the max_size is smaller than the serialized size. + // #[derive(Clone, Ord, PartialOrd, Eq, PartialEq)] + // struct BuggyStruct; + // impl crate::Storable for BuggyStruct { + // fn to_bytes(&self) -> Cow<[u8]> { + // Cow::Borrowed(&[1, 2, 3, 4]) + // } + + // fn from_bytes(_: Cow<[u8]>) -> Self { + // unimplemented!(); + // } + + // const BOUND: StorableBound = StorableBound::Bounded { + // max_size: 1, + // is_fixed_size: false, + // }; + // } + + // #[test] + // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] + // fn v1_panics_if_key_is_bigger_than_max_size() { + // let mut btree = BTreeMap::init_v1(make_memory()); + // btree.insert(BuggyStruct, ()); + // } + + // #[test] + // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] + // fn v2_panics_if_key_is_bigger_than_max_size() { + // let mut btree = BTreeMap::init(make_memory()); + // btree.insert(BuggyStruct, ()); + // } + + // #[test] + // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] + // fn v1_panics_if_value_is_bigger_than_max_size() { + // let mut btree = BTreeMap::init(make_memory()); + // btree.insert((), BuggyStruct); + // } + + // #[test] + // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] + // fn v2_panics_if_value_is_bigger_than_max_size() { + // let mut btree = BTreeMap::init(make_memory()); + // btree.insert((), BuggyStruct); + // } + + // // To generate the memory dump file for the current version: + // // cargo test create_btreemap_dump_file -- --include-ignored + // #[test] + // #[ignore] + // fn create_btreemap_dump_file() { + // let mem = make_memory(); + // let mut btree = BTreeMap::init_v1(mem.clone()); + // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); + // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + + // use std::io::prelude::*; + // let mut file = + // std::fs::File::create(format!("dumps/btreemap_v{LAYOUT_VERSION}.dump")).unwrap(); + // file.write_all(&mem.borrow()).unwrap(); + // } + + // #[test] + // fn produces_layout_identical_to_layout_version_1_with_packed_headers() { + // let mem = make_memory(); + // let mut btree = BTreeMap::init_v1(mem.clone()); + // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); + // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + + // let btreemap_v1 = include_bytes!("../dumps/btreemap_v1_packed_headers.dump"); + // assert_eq!(*mem.borrow(), btreemap_v1); + // } + + // #[test] + // fn read_write_header_is_identical_to_read_write_struct() { + // #[repr(C, packed)] + // struct BTreePackedHeader { + // magic: [u8; 3], + // version: u8, + // max_key_size: u32, + // max_value_size: u32, + // root_addr: Address, + // length: u64, + // _buffer: [u8; 24], + // } + // let packed_header = BTreePackedHeader { + // magic: *MAGIC, + // version: LAYOUT_VERSION, + // root_addr: Address::from(0xDEADBEEF), + // max_key_size: 0x12345678, + // max_value_size: 0x87654321, + // length: 0xA1B2D3C4, + // _buffer: [0; 24], + // }; + + // let packed_mem = make_memory(); + // crate::write_struct(&packed_header, Address::from(0), &packed_mem); + + // let v1_header = BTreeHeader { + // version: Version::V1(DerivedPageSize { + // max_key_size: 0x12345678, + // max_value_size: 0x87654321, + // }), + // root_addr: Address::from(0xDEADBEEF), + // length: 0xA1B2D3C4, + // }; + + // let v1_mem = make_memory(); + // BTreeMap::, Vec<_>, RefCell>>::write_header(&v1_header, &v1_mem); + + // assert_eq!(packed_mem, v1_mem); + + // let packed_header: BTreePackedHeader = crate::read_struct(Address::from(0), &v1_mem); + // let v1_header = BTreeMap::, Vec<_>, RefCell>>::read_header(&v1_mem); + // assert!(packed_header.magic == *MAGIC); + // assert!(packed_header.version == LAYOUT_VERSION); + // match v1_header.version { + // Version::V1(DerivedPageSize { + // max_key_size, + // max_value_size, + // }) => { + // assert!(packed_header.max_key_size == max_key_size); + // assert!(packed_header.max_value_size == max_value_size); + // } + // _ => unreachable!("version must be v1"), + // }; + + // assert!(packed_header.root_addr == v1_header.root_addr); + // assert!(packed_header.length == v1_header.length); + // } + + // #[test] + // fn migrate_from_bounded_to_unbounded_and_back() { + // // A type that is bounded. + // #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] + // struct T; + // impl Storable for T { + // fn to_bytes(&self) -> Cow<[u8]> { + // Cow::Owned(vec![1, 2, 3]) + // } + + // fn from_bytes(bytes: Cow<[u8]>) -> Self { + // assert_eq!(bytes.to_vec(), vec![1, 2, 3]); + // T + // } + + // const BOUND: StorableBound = StorableBound::Bounded { + // max_size: 3, + // is_fixed_size: true, + // }; + // } + + // // Same as the above type, but unbounded. + // #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] + // struct T2; + // impl Storable for T2 { + // fn to_bytes(&self) -> Cow<[u8]> { + // Cow::Owned(vec![1, 2, 3]) + // } + + // fn from_bytes(bytes: Cow<[u8]>) -> Self { + // assert_eq!(bytes.to_vec(), vec![1, 2, 3]); + // T2 + // } + + // const BOUND: StorableBound = StorableBound::Unbounded; + // } + + // // Create a v1 btreemap with the bounded type. + // let mem = make_memory(); + // let mut btree: BTreeMap = BTreeMap::new_v1(mem); + // btree.insert(T, T); + + // // Migrate to v2 and the unbounded type. + // let btree: BTreeMap = BTreeMap::init(btree.into_memory()); + // btree.save_header(); + + // // Reload the BTree again and try to read the value. + // let btree: BTreeMap = BTreeMap::init(btree.into_memory()); + // assert_eq!(btree.get(&T2), Some(T2)); + + // // Reload the BTree again with bounded type. + // let btree: BTreeMap = BTreeMap::init(btree.into_memory()); + // assert_eq!(btree.get(&T), Some(T)); + // } + + // #[test] + // fn test_clear_new_bounded_type() { + // let mem = make_memory(); + // let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::new(mem.clone()); + + // btree.insert( + // [1u8; 4].as_slice().try_into().unwrap(), + // [1u8; 4].as_slice().try_into().unwrap(), + // ); + + // assert_ne!(btree.len(), 0); + // assert_ne!(btree.allocator.num_allocated_chunks(), 0); + // assert_ne!(btree.root_addr, NULL); + + // btree.clear_new(); + + // let header_actual = BTreeMap::, Blob<4>, _>::read_header(&mem); + + // BTreeMap::, Blob<4>, _>::new(mem.clone()); + + // let header_expected = BTreeMap::, Blob<4>, _>::read_header(&mem); + + // assert_eq!(header_actual, header_expected); + // } + + // #[test] + // fn test_clear_new_unbounded_type() { + // let mem = make_memory(); + // let mut btree: BTreeMap = BTreeMap::new(mem.clone()); + // btree.insert("asd".into(), "bce".into()); + + // assert_ne!(btree.len(), 0); + // assert_ne!(btree.allocator.num_allocated_chunks(), 0); + // assert_ne!(btree.root_addr, NULL); + + // btree.clear_new(); + + // let header_actual = BTreeMap::::read_header(&mem); + + // BTreeMap::::new(mem.clone()); + + // let header_expected = BTreeMap::::read_header(&mem); + + // assert_eq!(header_actual, header_expected); + // } + + // #[test] + // fn deallocating_node_with_overflows() { + // let mem = make_memory(); + // let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); + + // // No allocated chunks yet. + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + // // Insert and remove an entry that's large and requires overflow pages. + // btree.insert(vec![0; 10_000], vec![]); + + // // At least two chunks should be allocated. + // // One for the node itself and at least one overflow page. + // assert!(btree.allocator.num_allocated_chunks() >= 2); + // btree.remove(&vec![0; 10_000]); + + // // All chunks have been deallocated. + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // } + + // #[test] + // fn repeatedly_deallocating_nodes_with_overflows() { + // let mem = make_memory(); + // let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); + + // // No allocated chunks yet. + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + // for _ in 0..100 { + // for i in 0..100 { + // btree.insert(vec![i; 10_000], vec![]); + // } + + // for i in 0..100 { + // btree.remove(&vec![i; 10_000]); + // } + // } + + // // All chunks have been deallocated. + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // } + + // #[test] + // fn deallocating_root_does_not_leak_memory() { + // let mem = make_memory(); + // let mut btree: BTreeMap, _, _> = BTreeMap::new(mem.clone()); + + // for i in 1..=11 { + // // Large keys are stored so that each node overflows. + // assert_eq!(btree.insert(vec![i; 10_000], ()), None); + // } + + // // Should now split a node. + // assert_eq!(btree.insert(vec![0; 10_000], ()), None); + + // // The btree should look like this: + // // [6] + // // / \ + // // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.keys(), vec![vec![6; 10_000]]); + // assert_eq!(root.children_len(), 2); + + // // Remove the element in the root. + // btree.remove(&vec![6; 10_000]); + + // // The btree should look like this: + // // [5] + // // / \ + // // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.keys(), vec![vec![5; 10_000]]); + // assert_eq!(root.children_len(), 2); + + // // Remove the element in the root. This triggers the case where the root + // // node is deallocated and the children are merged into a single node. + // btree.remove(&vec![5; 10_000]); + + // // The btree should look like this: + // // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11] + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Leaf); + // assert_eq!( + // root.keys(), + // vec![ + // vec![0; 10_000], + // vec![1; 10_000], + // vec![2; 10_000], + // vec![3; 10_000], + // vec![4; 10_000], + // vec![7; 10_000], + // vec![8; 10_000], + // vec![9; 10_000], + // vec![10; 10_000], + // vec![11; 10_000], + // ] + // ); + + // // Delete everything else. + // for i in 0..=11 { + // btree.remove(&vec![i; 10_000]); + // } + + // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + // } } From 6f4509b3939ac9bd376874397f6a6fad8179a5ba Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 08:52:10 +0200 Subject: [PATCH 04/66] . --- src/btreemap.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index e429fa3a..174354a8 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1220,22 +1220,22 @@ mod test { } #[test] - fn test_insert_and_get() { + fn test_init_preserves_data() { run_btree_test(|mut btree| { assert_eq!(btree.insert(k(1), v(2)), None); assert_eq!(btree.get(&k(1)), Some(v(2))); + + // Reload the btree, verfiy data still exists. + let btree = BTreeMap::init(btree.into_memory()); + assert_eq!(btree.get(&k(1)), Some(v(2))); }); } #[test] - fn test_init_preserves_data() { + fn test_insert_and_get() { run_btree_test(|mut btree| { assert_eq!(btree.insert(k(1), v(2)), None); assert_eq!(btree.get(&k(1)), Some(v(2))); - - // Reload the btree, verfiy data still exists. - let btree = BTreeMap::init(btree.into_memory()); - assert_eq!(btree.get(&k(1)), Some(v(2))); }); } From 3898e3337f3661f2f31c4dda6119950ee3536b1f Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 08:53:12 +0200 Subject: [PATCH 05/66] . --- src/btreemap.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 174354a8..bb2e066a 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1220,7 +1220,7 @@ mod test { } #[test] - fn test_init_preserves_data() { + fn init_preserves_data() { run_btree_test(|mut btree| { assert_eq!(btree.insert(k(1), v(2)), None); assert_eq!(btree.get(&k(1)), Some(v(2))); @@ -1232,7 +1232,7 @@ mod test { } #[test] - fn test_insert_and_get() { + fn insert_and_get() { run_btree_test(|mut btree| { assert_eq!(btree.insert(k(1), v(2)), None); assert_eq!(btree.get(&k(1)), Some(v(2))); @@ -1240,7 +1240,7 @@ mod test { } #[test] - fn test_insert_overwrites_previous_value() { + fn insert_overwrites_previous_value() { run_btree_test(|mut btree| { assert_eq!(btree.insert(k(1), v(2)), None); assert_eq!(btree.insert(k(1), v(3)), Some(v(2))); @@ -1249,7 +1249,7 @@ mod test { } #[test] - fn test_insert_get_multiple_entries() { + fn insert_get_multiple_entries() { run_btree_test(|mut btree| { assert_eq!(btree.insert(k(1), v(10)), None); assert_eq!(btree.insert(k(2), v(20)), None); From 24b5f4d7fbeda1bac31c2a852319728f710227fe Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 08:54:17 +0200 Subject: [PATCH 06/66] . --- src/btreemap.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index bb2e066a..3bd5d593 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1222,29 +1222,29 @@ mod test { #[test] fn init_preserves_data() { run_btree_test(|mut btree| { - assert_eq!(btree.insert(k(1), v(2)), None); - assert_eq!(btree.get(&k(1)), Some(v(2))); + assert_eq!(btree.insert(k(1), v(20)), None); + assert_eq!(btree.get(&k(1)), Some(v(20))); // Reload the btree, verfiy data still exists. let btree = BTreeMap::init(btree.into_memory()); - assert_eq!(btree.get(&k(1)), Some(v(2))); + assert_eq!(btree.get(&k(1)), Some(v(20))); }); } #[test] fn insert_and_get() { run_btree_test(|mut btree| { - assert_eq!(btree.insert(k(1), v(2)), None); - assert_eq!(btree.get(&k(1)), Some(v(2))); + assert_eq!(btree.insert(k(1), v(20)), None); + assert_eq!(btree.get(&k(1)), Some(v(20))); }); } #[test] fn insert_overwrites_previous_value() { run_btree_test(|mut btree| { - assert_eq!(btree.insert(k(1), v(2)), None); - assert_eq!(btree.insert(k(1), v(3)), Some(v(2))); - assert_eq!(btree.get(&k(1)), Some(v(3))); + assert_eq!(btree.insert(k(1), v(20)), None); + assert_eq!(btree.insert(k(1), v(30)), Some(v(20))); + assert_eq!(btree.get(&k(1)), Some(v(30))); }); } @@ -1287,8 +1287,8 @@ mod test { assert_eq!(right_child.key(median_index), &k(12)); // Overwrite the value of the median key. - assert_eq!(btree.insert(k(12), v(123)), Some(v(0))); - assert_eq!(btree.get(&k(12)), Some(v(123))); + assert_eq!(btree.insert(k(12), v(100)), Some(v(0))); + assert_eq!(btree.get(&k(12)), Some(v(100))); // The child has not been split and is still full. let right_child = btree.load_node(root.child(1)); From 558b174db6da641f2fa703b2af36d8563d487b1f Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 09:02:05 +0200 Subject: [PATCH 07/66] encode/decode --- src/btreemap.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 3bd5d593..6f130544 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1185,6 +1185,22 @@ mod test { Blob::<10>::try_from(&make_buffer::<10>(i)[..]).unwrap() } + /// Encodes an object into a byte vector. + fn encode(object: T) -> Vec + where + T: Storable, + { + object.to_bytes_checked().into_owned() + } + + /// Decodes a byte vector into an object. + fn decode(bytes: Vec) -> T + where + T: Storable, + { + T::from_bytes(Cow::Owned(bytes)) + } + /// A helper method to succinctly create an entry. fn e(x: u8) -> (Blob<10>, Vec) { (b(&[x]), vec![]) @@ -1274,10 +1290,7 @@ mod test { let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!( - root.entries(btree.memory()), - vec![(k(6), v(0).as_slice().to_vec())] - ); + assert_eq!(root.entries(btree.memory()), vec![(k(6), encode(v(0)))]); assert_eq!(root.children_len(), 2); // The right child should now be full, with the median key being "12" From 429b518b28df4ff607fedc27a07f6e7c35f1d47b Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 11:04:16 +0200 Subject: [PATCH 08/66] . --- src/btreemap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 6f130544..c01128ec 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1248,7 +1248,7 @@ mod test { } #[test] - fn insert_and_get() { + fn insert_get() { run_btree_test(|mut btree| { assert_eq!(btree.insert(k(1), v(20)), None); assert_eq!(btree.get(&k(1)), Some(v(20))); From 1cd24bb903177f0724f3a0cc97a522ca43dc3793 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 11:07:38 +0200 Subject: [PATCH 09/66] . --- src/btreemap.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index c01128ec..fd573ea6 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1175,14 +1175,17 @@ mod test { buf } + type Key = Blob<10>; + type Value = Blob<20>; + /// Creates a key from a u32. - fn k(i: u32) -> Blob<10> { + fn k(i: u32) -> Key { Blob::<10>::try_from(&make_buffer::<10>(i)[..]).unwrap() } /// Creates a value from a u32. - fn v(i: u32) -> Blob<10> { - Blob::<10>::try_from(&make_buffer::<10>(i)[..]).unwrap() + fn v(i: u32) -> Value { + Blob::<20>::try_from(&make_buffer::<20>(i)[..]).unwrap() } /// Encodes an object into a byte vector. @@ -1201,11 +1204,13 @@ mod test { T::from_bytes(Cow::Owned(bytes)) } + // TODO: remove obsolete code. /// A helper method to succinctly create an entry. fn e(x: u8) -> (Blob<10>, Vec) { (b(&[x]), vec![]) } + // TODO: remove obsolete code. /// A helper method to succinctly create a blob. pub(crate) fn b(x: &[u8]) -> Blob<10> { Blob::<10>::try_from(x).unwrap() @@ -1241,7 +1246,7 @@ mod test { assert_eq!(btree.insert(k(1), v(20)), None); assert_eq!(btree.get(&k(1)), Some(v(20))); - // Reload the btree, verfiy data still exists. + // Reload the btree, verify data still exists. let btree = BTreeMap::init(btree.into_memory()); assert_eq!(btree.get(&k(1)), Some(v(20))); }); From ce441c4a7b10feb570d97cd637ea116645d6206e Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 11:08:08 +0200 Subject: [PATCH 10/66] . --- src/btreemap.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index fd573ea6..b1ed7599 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1189,18 +1189,12 @@ mod test { } /// Encodes an object into a byte vector. - fn encode(object: T) -> Vec - where - T: Storable, - { + fn encode(object: T) -> Vec { object.to_bytes_checked().into_owned() } /// Decodes a byte vector into an object. - fn decode(bytes: Vec) -> T - where - T: Storable, - { + fn decode(bytes: Vec) -> T { T::from_bytes(Cow::Owned(bytes)) } From 66d2bf67cd068abc75d7e7aa7dbe2d6fdf2ad87c Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 11:09:45 +0200 Subject: [PATCH 11/66] . --- src/btreemap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index b1ed7599..c8710c86 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1180,12 +1180,12 @@ mod test { /// Creates a key from a u32. fn k(i: u32) -> Key { - Blob::<10>::try_from(&make_buffer::<10>(i)[..]).unwrap() + Key::try_from(&make_buffer::<10>(i)[..]).unwrap() } /// Creates a value from a u32. fn v(i: u32) -> Value { - Blob::<20>::try_from(&make_buffer::<20>(i)[..]).unwrap() + Value::try_from(&make_buffer::<20>(i)[..]).unwrap() } /// Encodes an object into a byte vector. From e62375a25f880f71851a9cd44b296cb8cdc17c8c Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 11:14:37 +0200 Subject: [PATCH 12/66] . --- src/btreemap.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index c8710c86..0eef86f7 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1285,7 +1285,7 @@ mod test { // The result should look like this: // [6] // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, (12), 13, 14, 15, 16, 17] let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Internal); @@ -1296,11 +1296,12 @@ mod test { let right_child = btree.load_node(root.child(1)); assert!(right_child.is_full()); let median_index = right_child.entries_len() / 2; - assert_eq!(right_child.key(median_index), &k(12)); + let expected_median_key = k(12); + assert_eq!(right_child.key(median_index), &expected_median_key); // Overwrite the value of the median key. - assert_eq!(btree.insert(k(12), v(100)), Some(v(0))); - assert_eq!(btree.get(&k(12)), Some(v(100))); + assert_eq!(btree.insert(expected_median_key, v(100)), Some(v(0))); + assert_eq!(btree.get(&expected_median_key), Some(v(100))); // The child has not been split and is still full. let right_child = btree.load_node(root.child(1)); From c7b506be47eb2459a5d01e47f0942dc614a4c2f5 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 11:44:12 +0200 Subject: [PATCH 13/66] generalize test_init_preserves_data --- src/btreemap.rs | 184 +++++++++++++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 72 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 0eef86f7..1f12cb04 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1157,16 +1157,20 @@ where mod test { use super::*; use crate::{ - storable::{Blob, Bound as StorableBound}, + storable::{Blob, Bound as StorableBound, Storable}, VectorMemory, }; + use std::borrow::Cow; use std::cell::RefCell; + use std::convert::TryFrom; use std::rc::Rc; + /// Creates a new shared memory instance. pub(crate) fn make_memory() -> Rc>> { Rc::new(RefCell::new(Vec::new())) } + /// Returns a fixed‑size buffer for the given u32. fn make_buffer(i: u32) -> [u8; N] { let mut buf = [0u8; N]; let bytes = i.to_le_bytes(); @@ -1175,17 +1179,31 @@ mod test { buf } - type Key = Blob<10>; - type Value = Blob<20>; + /// A trait to construct a value from a u32. + trait Make { + fn make(i: u32) -> Self; + } + + impl Make for u32 { + fn make(i: u32) -> Self { + i + } + } + + impl Make for Blob { + fn make(i: u32) -> Self { + Blob::try_from(&make_buffer::(i)[..]).unwrap() + } + } /// Creates a key from a u32. - fn k(i: u32) -> Key { - Key::try_from(&make_buffer::<10>(i)[..]).unwrap() + fn k(i: u32) -> T { + T::make(i) } /// Creates a value from a u32. - fn v(i: u32) -> Value { - Value::try_from(&make_buffer::<20>(i)[..]).unwrap() + fn v(i: u32) -> T { + T::make(i) } /// Encodes an object into a byte vector. @@ -1210,7 +1228,7 @@ mod test { Blob::<10>::try_from(x).unwrap() } - /// A test runner that runs the test using both V1 and V2 btrees. + /// A test runner that runs the test using V1, migrated V2, and direct V2. pub fn run_btree_test(f: F) where K: Storable + Ord + Clone, @@ -1234,81 +1252,103 @@ mod test { f(tree_v2); } - #[test] - fn init_preserves_data() { + /// Test that data is preserved after reloading the BTreeMap. + fn init_preserves_data() + where + K: Storable + Ord + Clone + Make, + V: Storable + Make + std::fmt::Debug + PartialEq, + { run_btree_test(|mut btree| { - assert_eq!(btree.insert(k(1), v(20)), None); - assert_eq!(btree.get(&k(1)), Some(v(20))); + assert_eq!(btree.insert(K::make(1), V::make(20)), None); + assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); - // Reload the btree, verify data still exists. - let btree = BTreeMap::init(btree.into_memory()); - assert_eq!(btree.get(&k(1)), Some(v(20))); + // Reload the btree, verify the entry remains. + let btree = BTreeMap::::init(btree.into_memory()); + assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); }); } #[test] - fn insert_get() { - run_btree_test(|mut btree| { - assert_eq!(btree.insert(k(1), v(20)), None); - assert_eq!(btree.get(&k(1)), Some(v(20))); - }); + fn test_init_preserves_data() { + init_preserves_data::>(); + init_preserves_data::, Blob<20>>(); } - #[test] - fn insert_overwrites_previous_value() { - run_btree_test(|mut btree| { - assert_eq!(btree.insert(k(1), v(20)), None); - assert_eq!(btree.insert(k(1), v(30)), Some(v(20))); - assert_eq!(btree.get(&k(1)), Some(v(30))); - }); - } + // #[test] + // fn test_init_preserves_data() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(k(1), v(20)), None); + // assert_eq!(btree.get(&k(1)), Some(v(20))); - #[test] - fn insert_get_multiple_entries() { - run_btree_test(|mut btree| { - assert_eq!(btree.insert(k(1), v(10)), None); - assert_eq!(btree.insert(k(2), v(20)), None); - assert_eq!(btree.insert(b(&[]), v(30)), None); - assert_eq!(btree.get(&k(1)), Some(v(10))); - assert_eq!(btree.get(&k(2)), Some(v(20))); - assert_eq!(btree.get(&b(&[])), Some(v(30))); - }); - } + // // Reload the btree, verify data still exists. + // let btree = BTreeMap::init(btree.into_memory()); + // assert_eq!(btree.get(&k(1)), Some(v(20))); + // }); + // } - #[test] - fn insert_overwrite_median_key_in_full_child_node() { - run_btree_test(|mut btree| { - for i in 1..=17 { - assert_eq!(btree.insert(k(i), v(0)), None); - } + // #[test] + // fn insert_get() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(k(1), v(20)), None); + // assert_eq!(btree.get(&k(1)), Some(v(20))); + // }); + // } - // The result should look like this: - // [6] - // / \ - // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, (12), 13, 14, 15, 16, 17] - - let root = btree.load_node(btree.root_addr); - assert_eq!(root.node_type(), NodeType::Internal); - assert_eq!(root.entries(btree.memory()), vec![(k(6), encode(v(0)))]); - assert_eq!(root.children_len(), 2); - - // The right child should now be full, with the median key being "12" - let right_child = btree.load_node(root.child(1)); - assert!(right_child.is_full()); - let median_index = right_child.entries_len() / 2; - let expected_median_key = k(12); - assert_eq!(right_child.key(median_index), &expected_median_key); - - // Overwrite the value of the median key. - assert_eq!(btree.insert(expected_median_key, v(100)), Some(v(0))); - assert_eq!(btree.get(&expected_median_key), Some(v(100))); - - // The child has not been split and is still full. - let right_child = btree.load_node(root.child(1)); - assert_eq!(right_child.node_type(), NodeType::Leaf); - assert!(right_child.is_full()); - }); - } + // #[test] + // fn insert_overwrites_previous_value() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(k(1), v(20)), None); + // assert_eq!(btree.insert(k(1), v(30)), Some(v(20))); + // assert_eq!(btree.get(&k(1)), Some(v(30))); + // }); + // } + + // #[test] + // fn insert_get_multiple_entries() { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(k(1), v(10)), None); + // assert_eq!(btree.insert(k(2), v(20)), None); + // assert_eq!(btree.insert(b(&[]), v(30)), None); + // assert_eq!(btree.get(&k(1)), Some(v(10))); + // assert_eq!(btree.get(&k(2)), Some(v(20))); + // assert_eq!(btree.get(&b(&[])), Some(v(30))); + // }); + // } + + // #[test] + // fn insert_overwrite_median_key_in_full_child_node() { + // run_btree_test(|mut btree| { + // for i in 1..=17 { + // assert_eq!(btree.insert(k(i), v(0)), None); + // } + + // // The result should look like this: + // // [6] + // // / \ + // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, (12), 13, 14, 15, 16, 17] + + // let root = btree.load_node(btree.root_addr); + // assert_eq!(root.node_type(), NodeType::Internal); + // assert_eq!(root.entries(btree.memory()), vec![(k(6), encode(v(0)))]); + // assert_eq!(root.children_len(), 2); + + // // The right child should now be full, with the median key being "12" + // let right_child = btree.load_node(root.child(1)); + // assert!(right_child.is_full()); + // let median_index = right_child.entries_len() / 2; + // let expected_median_key = k(12); + // assert_eq!(right_child.key(median_index), &expected_median_key); + + // // Overwrite the value of the median key. + // assert_eq!(btree.insert(expected_median_key, v(100)), Some(v(0))); + // assert_eq!(btree.get(&expected_median_key), Some(v(100))); + + // // The child has not been split and is still full. + // let right_child = btree.load_node(root.child(1)); + // assert_eq!(right_child.node_type(), NodeType::Leaf); + // assert!(right_child.is_full()); + // }); + // } // #[test] // fn insert_overwrite_key_in_full_root_node() { From d10116dc173206795ba214a6f9395523fb43b48f Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 14:03:10 +0200 Subject: [PATCH 14/66] apply_type_grid --- src/btreemap.rs | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 1f12cb04..da637f2b 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1160,6 +1160,7 @@ mod test { storable::{Blob, Bound as StorableBound, Storable}, VectorMemory, }; + use core::panic; use std::borrow::Cow; use std::cell::RefCell; use std::convert::TryFrom; @@ -1196,13 +1197,7 @@ mod test { } } - /// Creates a key from a u32. - fn k(i: u32) -> T { - T::make(i) - } - - /// Creates a value from a u32. - fn v(i: u32) -> T { + fn make(i: u32) -> T { T::make(i) } @@ -1228,6 +1223,31 @@ mod test { Blob::<10>::try_from(x).unwrap() } + /// Asserts that keys from consecutive IDs are strictly increasing. + /// + /// This is important for the B-tree structure to maintain its properties. + fn verify_monotonic_keys() { + for i in 0..10 { + assert!(T::make(i) < T::make(i + 1)); + } + } + + /// Macro that verifies the monotonicity for a given key type and then runs the test function. + macro_rules! verify_and_run { + ($Key:ty, $Value:ty, $f:ident) => {{ + verify_monotonic_keys::<$Key>(); + $f::<$Key, $Value>(); + }}; + } + + /// Macro to apply a test function to a predefined grid of key/value types. + macro_rules! apply_type_grid { + ($f:ident) => {{ + verify_and_run!(u32, Blob<20>, $f); + verify_and_run!(Blob<10>, Blob<20>, $f); + }}; + } + /// A test runner that runs the test using V1, migrated V2, and direct V2. pub fn run_btree_test(f: F) where @@ -1259,19 +1279,18 @@ mod test { V: Storable + Make + std::fmt::Debug + PartialEq, { run_btree_test(|mut btree| { - assert_eq!(btree.insert(K::make(1), V::make(20)), None); - assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); + assert_eq!(btree.insert(make::(1), make::(20)), None); + assert_eq!(btree.get(&make::(1)), Some(make::(20))); // Reload the btree, verify the entry remains. let btree = BTreeMap::::init(btree.into_memory()); - assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); + assert_eq!(btree.get(&make::(1)), Some(make::(20))); }); } #[test] fn test_init_preserves_data() { - init_preserves_data::>(); - init_preserves_data::, Blob<20>>(); + apply_type_grid!(init_preserves_data); } // #[test] From fadbee02477b703fbf1fa11a2eb14d7cb97f0a9f Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 14:22:12 +0200 Subject: [PATCH 15/66] btree_test! --- src/btreemap.rs | 69 ++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index da637f2b..3f457605 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1211,11 +1211,11 @@ mod test { T::from_bytes(Cow::Owned(bytes)) } - // TODO: remove obsolete code. - /// A helper method to succinctly create an entry. - fn e(x: u8) -> (Blob<10>, Vec) { - (b(&[x]), vec![]) - } + // // TODO: remove obsolete code. + // /// A helper method to succinctly create an entry. + // fn e(x: u8) -> (Blob<10>, Vec) { + // (b(&[x]), vec![]) + // } // TODO: remove obsolete code. /// A helper method to succinctly create a blob. @@ -1232,22 +1232,6 @@ mod test { } } - /// Macro that verifies the monotonicity for a given key type and then runs the test function. - macro_rules! verify_and_run { - ($Key:ty, $Value:ty, $f:ident) => {{ - verify_monotonic_keys::<$Key>(); - $f::<$Key, $Value>(); - }}; - } - - /// Macro to apply a test function to a predefined grid of key/value types. - macro_rules! apply_type_grid { - ($f:ident) => {{ - verify_and_run!(u32, Blob<20>, $f); - verify_and_run!(Blob<10>, Blob<20>, $f); - }}; - } - /// A test runner that runs the test using V1, migrated V2, and direct V2. pub fn run_btree_test(f: F) where @@ -1272,6 +1256,23 @@ mod test { f(tree_v2); } + /// Macro that verifies the monotonicity for a given key type and then runs the test function. + macro_rules! verify_and_run { + ($Key:ty, $Value:ty, $runner_fn:ident) => {{ + verify_monotonic_keys::<$Key>(); + $runner_fn::<$Key, $Value>(); + }}; + } + + /// Macro to apply a test function to a predefined grid of key/value types. + macro_rules! btree_test { + ($runner_fn:ident) => {{ + // (Key, Value, Test function). + verify_and_run!(u32, Blob<20>, $runner_fn); + verify_and_run!(Blob<10>, Blob<20>, $runner_fn); + }}; + } + /// Test that data is preserved after reloading the BTreeMap. fn init_preserves_data() where @@ -1279,20 +1280,36 @@ mod test { V: Storable + Make + std::fmt::Debug + PartialEq, { run_btree_test(|mut btree| { - assert_eq!(btree.insert(make::(1), make::(20)), None); - assert_eq!(btree.get(&make::(1)), Some(make::(20))); + assert_eq!(btree.insert(K::make(1), V::make(20)), None); + assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); - // Reload the btree, verify the entry remains. + // Reload the BTreeMap and verify the entry. let btree = BTreeMap::::init(btree.into_memory()); - assert_eq!(btree.get(&make::(1)), Some(make::(20))); + assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); }); } #[test] fn test_init_preserves_data() { - apply_type_grid!(init_preserves_data); + btree_test!(init_preserves_data); } + // /// Test that data is preserved after reloading the BTreeMap. + // fn init_preserves_data() + // where + // K: Storable + Ord + Clone + Make, + // V: Storable + Make + std::fmt::Debug + PartialEq, + // { + // run_btree_test(|mut btree| { + // assert_eq!(btree.insert(make::(1), make::(20)), None); + // assert_eq!(btree.get(&make::(1)), Some(make::(20))); + + // // Reload the btree, verify the entry remains. + // let btree = BTreeMap::::init(btree.into_memory()); + // assert_eq!(btree.get(&make::(1)), Some(make::(20))); + // }); + // } + // #[test] // fn test_init_preserves_data() { // run_btree_test(|mut btree| { From a12882bafaf84deaa3970f00b664f866f56d775c Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 14:32:45 +0200 Subject: [PATCH 16/66] . --- src/btreemap.rs | 111 ++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 66 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 3f457605..332ecccf 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1197,10 +1197,6 @@ mod test { } } - fn make(i: u32) -> T { - T::make(i) - } - /// Encodes an object into a byte vector. fn encode(object: T) -> Vec { object.to_bytes_checked().into_owned() @@ -1266,14 +1262,15 @@ mod test { /// Macro to apply a test function to a predefined grid of key/value types. macro_rules! btree_test { - ($runner_fn:ident) => {{ - // (Key, Value, Test function). - verify_and_run!(u32, Blob<20>, $runner_fn); - verify_and_run!(Blob<10>, Blob<20>, $runner_fn); - }}; + ($name:ident, $runner_fn:ident) => { + #[test] + fn $name() { + verify_and_run!(u32, Blob<20>, $runner_fn); + verify_and_run!(Blob<10>, Blob<20>, $runner_fn); + } + }; } - /// Test that data is preserved after reloading the BTreeMap. fn init_preserves_data() where K: Storable + Ord + Clone + Make, @@ -1289,65 +1286,47 @@ mod test { }); } - #[test] - fn test_init_preserves_data() { - btree_test!(init_preserves_data); - } - - // /// Test that data is preserved after reloading the BTreeMap. - // fn init_preserves_data() - // where - // K: Storable + Ord + Clone + Make, - // V: Storable + Make + std::fmt::Debug + PartialEq, - // { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(make::(1), make::(20)), None); - // assert_eq!(btree.get(&make::(1)), Some(make::(20))); - - // // Reload the btree, verify the entry remains. - // let btree = BTreeMap::::init(btree.into_memory()); - // assert_eq!(btree.get(&make::(1)), Some(make::(20))); - // }); - // } + btree_test!(test_init_preserves_data, init_preserves_data); - // #[test] - // fn test_init_preserves_data() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(k(1), v(20)), None); - // assert_eq!(btree.get(&k(1)), Some(v(20))); + fn insert_get() + where + K: Storable + Ord + Clone + Make, + V: Storable + Make + std::fmt::Debug + PartialEq, + { + run_btree_test(|mut btree| { + assert_eq!(btree.insert(K::make(1), V::make(20)), None); + assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); + }); + } - // // Reload the btree, verify data still exists. - // let btree = BTreeMap::init(btree.into_memory()); - // assert_eq!(btree.get(&k(1)), Some(v(20))); - // }); - // } + btree_test!(test_insert_get, insert_get); - // #[test] - // fn insert_get() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(k(1), v(20)), None); - // assert_eq!(btree.get(&k(1)), Some(v(20))); - // }); - // } + fn insert_overwrites_previous_value() + where + K: Storable + Ord + Clone + Make, + V: Storable + Make + std::fmt::Debug + PartialEq, + { + run_btree_test(|mut btree| { + assert_eq!(btree.insert(K::make(1), V::make(20)), None); + assert_eq!(btree.insert(K::make(1), V::make(30)), Some(V::make(20))); + assert_eq!(btree.get(&K::make(1)), Some(V::make(30))); + }); + } - // #[test] - // fn insert_overwrites_previous_value() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(k(1), v(20)), None); - // assert_eq!(btree.insert(k(1), v(30)), Some(v(20))); - // assert_eq!(btree.get(&k(1)), Some(v(30))); - // }); - // } + btree_test!( + test_insert_overwrites_previous_value, + insert_overwrites_previous_value + ); // #[test] // fn insert_get_multiple_entries() { // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(k(1), v(10)), None); - // assert_eq!(btree.insert(k(2), v(20)), None); - // assert_eq!(btree.insert(b(&[]), v(30)), None); - // assert_eq!(btree.get(&k(1)), Some(v(10))); - // assert_eq!(btree.get(&k(2)), Some(v(20))); - // assert_eq!(btree.get(&b(&[])), Some(v(30))); + // assert_eq!(btree.insert(K::make(1), V::make(10)), None); + // assert_eq!(btree.insert(K::make(2), V::make(20)), None); + // assert_eq!(btree.insert(b(&[]), V::make(30)), None); + // assert_eq!(btree.get(&K::make(1)), Some(V::make(10))); + // assert_eq!(btree.get(&K::make(2)), Some(V::make(20))); + // assert_eq!(btree.get(&b(&[])), Some(V::make(30))); // }); // } @@ -1355,7 +1334,7 @@ mod test { // fn insert_overwrite_median_key_in_full_child_node() { // run_btree_test(|mut btree| { // for i in 1..=17 { - // assert_eq!(btree.insert(k(i), v(0)), None); + // assert_eq!(btree.insert(K::make(i), V::make(0)), None); // } // // The result should look like this: @@ -1365,19 +1344,19 @@ mod test { // let root = btree.load_node(btree.root_addr); // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![(k(6), encode(v(0)))]); + // assert_eq!(root.entries(btree.memory()), vec![(K::make(6), encode(V::make(0)))]); // assert_eq!(root.children_len(), 2); // // The right child should now be full, with the median key being "12" // let right_child = btree.load_node(root.child(1)); // assert!(right_child.is_full()); // let median_index = right_child.entries_len() / 2; - // let expected_median_key = k(12); + // let expected_median_key = K::make(12); // assert_eq!(right_child.key(median_index), &expected_median_key); // // Overwrite the value of the median key. - // assert_eq!(btree.insert(expected_median_key, v(100)), Some(v(0))); - // assert_eq!(btree.get(&expected_median_key), Some(v(100))); + // assert_eq!(btree.insert(expected_median_key, V::make(100)), Some(V::make(0))); + // assert_eq!(btree.get(&expected_median_key), Some(V::make(100))); // // The child has not been split and is still full. // let right_child = btree.load_node(root.child(1)); From 528dca2fc5ab325c45bfaa77c77ab3ef02f4bbf9 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 14:39:00 +0200 Subject: [PATCH 17/66] . --- src/btreemap.rs | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 332ecccf..0a7913cc 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1183,18 +1183,26 @@ mod test { /// A trait to construct a value from a u32. trait Make { fn make(i: u32) -> Self; + fn default() -> Self; } impl Make for u32 { fn make(i: u32) -> Self { i } + fn default() -> Self { + 0 + } } impl Make for Blob { fn make(i: u32) -> Self { Blob::try_from(&make_buffer::(i)[..]).unwrap() } + fn default() -> Self { + let x: &[u8] = &[]; + Blob::try_from(x).unwrap() + } } /// Encodes an object into a byte vector. @@ -1318,17 +1326,25 @@ mod test { insert_overwrites_previous_value ); - // #[test] - // fn insert_get_multiple_entries() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(K::make(1), V::make(10)), None); - // assert_eq!(btree.insert(K::make(2), V::make(20)), None); - // assert_eq!(btree.insert(b(&[]), V::make(30)), None); - // assert_eq!(btree.get(&K::make(1)), Some(V::make(10))); - // assert_eq!(btree.get(&K::make(2)), Some(V::make(20))); - // assert_eq!(btree.get(&b(&[])), Some(V::make(30))); - // }); - // } + fn insert_get_multiple_entries() + where + K: Storable + Ord + Clone + Make, + V: Storable + Make + std::fmt::Debug + PartialEq, + { + run_btree_test(|mut btree| { + assert_eq!(btree.insert(K::make(1), V::make(10)), None); + assert_eq!(btree.insert(K::make(2), V::make(20)), None); + assert_eq!(btree.insert(K::default(), V::make(30)), None); + assert_eq!(btree.get(&K::make(1)), Some(V::make(10))); + assert_eq!(btree.get(&K::make(2)), Some(V::make(20))); + assert_eq!(btree.get(&K::default()), Some(V::make(30))); + }); + } + + btree_test!( + test_insert_get_multiple_entries, + insert_get_multiple_entries + ); // #[test] // fn insert_overwrite_median_key_in_full_child_node() { From 2b027a5ae99737b6bb40170be8f0f72e252d4e37 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 14:41:19 +0200 Subject: [PATCH 18/66] . --- src/btreemap.rs | 84 ++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 0a7913cc..8b7b570b 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1298,7 +1298,7 @@ mod test { fn insert_get() where - K: Storable + Ord + Clone + Make, + K: Storable + Ord + Clone + Make + std::fmt::Debug, V: Storable + Make + std::fmt::Debug + PartialEq, { run_btree_test(|mut btree| { @@ -1311,7 +1311,7 @@ mod test { fn insert_overwrites_previous_value() where - K: Storable + Ord + Clone + Make, + K: Storable + Ord + Clone + Make + std::fmt::Debug, V: Storable + Make + std::fmt::Debug + PartialEq, { run_btree_test(|mut btree| { @@ -1328,7 +1328,7 @@ mod test { fn insert_get_multiple_entries() where - K: Storable + Ord + Clone + Make, + K: Storable + Ord + Clone + Make + std::fmt::Debug, V: Storable + Make + std::fmt::Debug + PartialEq, { run_btree_test(|mut btree| { @@ -1346,40 +1346,54 @@ mod test { insert_get_multiple_entries ); - // #[test] - // fn insert_overwrite_median_key_in_full_child_node() { - // run_btree_test(|mut btree| { - // for i in 1..=17 { - // assert_eq!(btree.insert(K::make(i), V::make(0)), None); - // } - - // // The result should look like this: - // // [6] - // // / \ - // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, (12), 13, 14, 15, 16, 17] + fn insert_overwrite_median_key_in_full_child_node() + where + K: Storable + Ord + Clone + Make + std::fmt::Debug, + V: Storable + Make + std::fmt::Debug + PartialEq, + { + run_btree_test(|mut btree| { + for i in 1..=17 { + assert_eq!(btree.insert(K::make(i), V::default()), None); + } - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![(K::make(6), encode(V::make(0)))]); - // assert_eq!(root.children_len(), 2); + // The result should look like this: + // [6] + // / \ + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, (12), 13, 14, 15, 16, 17] + + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!( + root.entries(btree.memory()), + vec![(K::make(6), encode(V::default()))] + ); + assert_eq!(root.children_len(), 2); + + // The right child should now be full, with the median key being "12" + let right_child = btree.load_node(root.child(1)); + assert!(right_child.is_full()); + let median_index = right_child.entries_len() / 2; + let expected_median_key = K::make(12); + assert_eq!(right_child.key(median_index), &expected_median_key); + + // Overwrite the value of the median key. + assert_eq!( + btree.insert(expected_median_key.clone(), V::make(123)), + Some(V::default()) + ); + assert_eq!(btree.get(&expected_median_key), Some(V::make(123))); + + // The child has not been split and is still full. + let right_child = btree.load_node(root.child(1)); + assert_eq!(right_child.node_type(), NodeType::Leaf); + assert!(right_child.is_full()); + }); + } - // // The right child should now be full, with the median key being "12" - // let right_child = btree.load_node(root.child(1)); - // assert!(right_child.is_full()); - // let median_index = right_child.entries_len() / 2; - // let expected_median_key = K::make(12); - // assert_eq!(right_child.key(median_index), &expected_median_key); - - // // Overwrite the value of the median key. - // assert_eq!(btree.insert(expected_median_key, V::make(100)), Some(V::make(0))); - // assert_eq!(btree.get(&expected_median_key), Some(V::make(100))); - - // // The child has not been split and is still full. - // let right_child = btree.load_node(root.child(1)); - // assert_eq!(right_child.node_type(), NodeType::Leaf); - // assert!(right_child.is_full()); - // }); - // } + btree_test!( + test_insert_overwrite_median_key_in_full_child_node, + insert_overwrite_median_key_in_full_child_node + ); // #[test] // fn insert_overwrite_key_in_full_root_node() { From 97c36398af885be6b47de53c772e8feb164ae889 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 14:44:55 +0200 Subject: [PATCH 19/66] . --- src/btreemap.rs | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 8b7b570b..d7c90b5a 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1279,11 +1279,15 @@ mod test { }; } - fn init_preserves_data() - where - K: Storable + Ord + Clone + Make, - V: Storable + Make + std::fmt::Debug + PartialEq, - { + // Define a trait for keys that need the full set of bounds. + trait TestKey: Storable + Ord + Clone + Make + std::fmt::Debug {} + impl TestKey for T where T: Storable + Ord + Clone + Make + std::fmt::Debug {} + + // Define a trait for values that need the full set of bounds. + trait TestValue: Storable + Make + std::fmt::Debug + PartialEq {} + impl TestValue for T where T: Storable + Make + std::fmt::Debug + PartialEq {} + + fn init_preserves_data() { run_btree_test(|mut btree| { assert_eq!(btree.insert(K::make(1), V::make(20)), None); assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); @@ -1296,11 +1300,7 @@ mod test { btree_test!(test_init_preserves_data, init_preserves_data); - fn insert_get() - where - K: Storable + Ord + Clone + Make + std::fmt::Debug, - V: Storable + Make + std::fmt::Debug + PartialEq, - { + fn insert_get() { run_btree_test(|mut btree| { assert_eq!(btree.insert(K::make(1), V::make(20)), None); assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); @@ -1309,11 +1309,7 @@ mod test { btree_test!(test_insert_get, insert_get); - fn insert_overwrites_previous_value() - where - K: Storable + Ord + Clone + Make + std::fmt::Debug, - V: Storable + Make + std::fmt::Debug + PartialEq, - { + fn insert_overwrites_previous_value() { run_btree_test(|mut btree| { assert_eq!(btree.insert(K::make(1), V::make(20)), None); assert_eq!(btree.insert(K::make(1), V::make(30)), Some(V::make(20))); @@ -1326,11 +1322,7 @@ mod test { insert_overwrites_previous_value ); - fn insert_get_multiple_entries() - where - K: Storable + Ord + Clone + Make + std::fmt::Debug, - V: Storable + Make + std::fmt::Debug + PartialEq, - { + fn insert_get_multiple_entries() { run_btree_test(|mut btree| { assert_eq!(btree.insert(K::make(1), V::make(10)), None); assert_eq!(btree.insert(K::make(2), V::make(20)), None); @@ -1346,11 +1338,7 @@ mod test { insert_get_multiple_entries ); - fn insert_overwrite_median_key_in_full_child_node() - where - K: Storable + Ord + Clone + Make + std::fmt::Debug, - V: Storable + Make + std::fmt::Debug + PartialEq, - { + fn insert_overwrite_median_key_in_full_child_node() { run_btree_test(|mut btree| { for i in 1..=17 { assert_eq!(btree.insert(K::make(i), V::default()), None); From 0dacc9e5355f6d1871081490e12e8b0a76d37e37 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 14:47:05 +0200 Subject: [PATCH 20/66] +1 test --- src/btreemap.rs | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index d7c90b5a..b1db21d6 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1383,28 +1383,32 @@ mod test { insert_overwrite_median_key_in_full_child_node ); - // #[test] - // fn insert_overwrite_key_in_full_root_node() { - // run_btree_test(|mut btree| { - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } + fn insert_overwrite_key_in_full_root_node() { + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(K::make(i), V::default()), None); + } - // // We now have a root that is full and looks like this: - // // - // // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - // let root = btree.load_node(btree.root_addr); - // assert!(root.is_full()); + // We now have a root that is full and looks like this: + // + // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + let root = btree.load_node(btree.root_addr); + assert!(root.is_full()); - // // Overwrite an element in the root. It should NOT cause the node to be split. - // assert_eq!(btree.insert(b(&[6]), b(&[4, 5, 6])), Some(b(&[]))); + // Overwrite an element in the root. It should NOT cause the node to be split. + assert_eq!(btree.insert(K::make(6), V::make(456)), Some(V::default())); - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Leaf); - // assert_eq!(btree.get(&b(&[6])), Some(b(&[4, 5, 6]))); - // assert_eq!(root.entries_len(), 11); - // }); - // } + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Leaf); + assert_eq!(btree.get(&K::make(6)), Some(V::make(456))); + assert_eq!(root.entries_len(), 11); + }); + } + + btree_test!( + test_insert_overwrite_key_in_full_root_node, + insert_overwrite_key_in_full_root_node + ); // #[test] // fn allocations() { From 2f825bb03c282ffb3e1c75de85a10c18b4383584 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 14:53:47 +0200 Subject: [PATCH 21/66] . --- src/btreemap.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index b1db21d6..e604f851 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1260,21 +1260,23 @@ mod test { f(tree_v2); } - /// Macro that verifies the monotonicity for a given key type and then runs the test function. - macro_rules! verify_and_run { - ($Key:ty, $Value:ty, $runner_fn:ident) => {{ - verify_monotonic_keys::<$Key>(); - $runner_fn::<$Key, $Value>(); - }}; - } - /// Macro to apply a test function to a predefined grid of key/value types. macro_rules! btree_test { ($name:ident, $runner_fn:ident) => { #[test] fn $name() { - verify_and_run!(u32, Blob<20>, $runner_fn); - verify_and_run!(Blob<10>, Blob<20>, $runner_fn); + { + type K = u32; + type V = Blob<20>; + verify_monotonic_keys::(); + $runner_fn::(); + } + { + type K = Blob<10>; + type V = Blob<20>; + verify_monotonic_keys::(); + $runner_fn::(); + } } }; } From 218cf02f3888d5a9f4d3ab1daffe34dfe42960dd Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 15:03:25 +0200 Subject: [PATCH 22/66] . --- src/btreemap.rs | 75 +++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index e604f851..2f5548cb 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1326,12 +1326,13 @@ mod test { fn insert_get_multiple_entries() { run_btree_test(|mut btree| { - assert_eq!(btree.insert(K::make(1), V::make(10)), None); - assert_eq!(btree.insert(K::make(2), V::make(20)), None); - assert_eq!(btree.insert(K::default(), V::make(30)), None); - assert_eq!(btree.get(&K::make(1)), Some(V::make(10))); - assert_eq!(btree.get(&K::make(2)), Some(V::make(20))); - assert_eq!(btree.get(&K::default()), Some(V::make(30))); + let n = 10_000; + for i in 0..n { + assert_eq!(btree.insert(K::make(i), V::make(10 * i)), None); + } + for i in 0..n { + assert_eq!(btree.get(&K::make(i)), Some(V::make(10 * i))); + } }); } @@ -1412,42 +1413,44 @@ mod test { insert_overwrite_key_in_full_root_node ); - // #[test] - // fn allocations() { - // run_btree_test(|mut btree| { - // // Insert entries until the root node is full. - // let mut i = 0; - // loop { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // let root = btree.load_node(btree.root_addr); - // if root.is_full() { - // break; - // } - // i += 1; - // } + fn allocations() { + run_btree_test(|mut btree| { + // Insert entries until the root node is full. + let mut i = 0; + loop { + assert_eq!(btree.insert(K::make(i), V::default()), None); + let root = btree.load_node(btree.root_addr); + if root.is_full() { + break; + } + i += 1; + } - // // Only need a single allocation to store up to `CAPACITY` elements. - // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + // Only need a single allocation to store up to `CAPACITY` elements. + assert_eq!(btree.allocator.num_allocated_chunks(), 1); - // assert_eq!(btree.insert(b(&[255]), b(&[])), None); + assert_eq!(btree.insert(K::make(255), V::default()), None); - // // The node had to be split into three nodes. - // assert_eq!(btree.allocator.num_allocated_chunks(), 3); - // }); - // } + // The node had to be split into three nodes. + assert_eq!(btree.allocator.num_allocated_chunks(), 3); + }); + } - // #[test] - // fn allocations_2() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + btree_test!(test_allocations, allocations); - // assert_eq!(btree.insert(b(&[]), b(&[])), None); - // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + fn allocations_2() { + run_btree_test(|mut btree| { + assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // assert_eq!(btree.remove(&b(&[])), Some(b(&[]))); - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // }); - // } + assert_eq!(btree.insert(K::make(1), V::make(20)), None); + assert_eq!(btree.allocator.num_allocated_chunks(), 1); + + assert_eq!(btree.remove(&K::make(1)), Some(V::make(20))); + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + }); + } + + btree_test!(test_allocations_2, allocations_2); // #[test] // fn pop_last_single_entry() { From 0cea0ef3b54368541b812126e6414e2b1c30631a Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 16:17:39 +0200 Subject: [PATCH 23/66] . --- src/btreemap.rs | 611 ++++++++++++++++++++++++++---------------------- 1 file changed, 334 insertions(+), 277 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 2f5548cb..ec7f0e75 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1183,14 +1183,14 @@ mod test { /// A trait to construct a value from a u32. trait Make { fn make(i: u32) -> Self; - fn default() -> Self; + fn empty() -> Self; } impl Make for u32 { fn make(i: u32) -> Self { i } - fn default() -> Self { + fn empty() -> Self { 0 } } @@ -1199,7 +1199,7 @@ mod test { fn make(i: u32) -> Self { Blob::try_from(&make_buffer::(i)[..]).unwrap() } - fn default() -> Self { + fn empty() -> Self { let x: &[u8] = &[]; Blob::try_from(x).unwrap() } @@ -1290,61 +1290,62 @@ mod test { impl TestValue for T where T: Storable + Make + std::fmt::Debug + PartialEq {} fn init_preserves_data() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - assert_eq!(btree.insert(K::make(1), V::make(20)), None); - assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); + assert_eq!(btree.insert(key(1), value(20)), None); + assert_eq!(btree.get(&key(1)), Some(value(20))); // Reload the BTreeMap and verify the entry. let btree = BTreeMap::::init(btree.into_memory()); - assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); + assert_eq!(btree.get(&key(1)), Some(value(20))); }); } - btree_test!(test_init_preserves_data, init_preserves_data); fn insert_get() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - assert_eq!(btree.insert(K::make(1), V::make(20)), None); - assert_eq!(btree.get(&K::make(1)), Some(V::make(20))); + assert_eq!(btree.insert(key(1), value(20)), None); + assert_eq!(btree.get(&key(1)), Some(value(20))); }); } - btree_test!(test_insert_get, insert_get); fn insert_overwrites_previous_value() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - assert_eq!(btree.insert(K::make(1), V::make(20)), None); - assert_eq!(btree.insert(K::make(1), V::make(30)), Some(V::make(20))); - assert_eq!(btree.get(&K::make(1)), Some(V::make(30))); + assert_eq!(btree.insert(key(1), value(20)), None); + assert_eq!(btree.insert(key(1), value(30)), Some(value(20))); + assert_eq!(btree.get(&key(1)), Some(value(30))); }); } - btree_test!( test_insert_overwrites_previous_value, insert_overwrites_previous_value ); fn insert_get_multiple_entries() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { let n = 10_000; for i in 0..n { - assert_eq!(btree.insert(K::make(i), V::make(10 * i)), None); + assert_eq!(btree.insert(key(i), value(i)), None); } for i in 0..n { - assert_eq!(btree.get(&K::make(i)), Some(V::make(10 * i))); + assert_eq!(btree.get(&key(i)), Some(value(i))); } }); } - btree_test!( test_insert_get_multiple_entries, insert_get_multiple_entries ); fn insert_overwrite_median_key_in_full_child_node() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { for i in 1..=17 { - assert_eq!(btree.insert(K::make(i), V::default()), None); + assert_eq!(btree.insert(key(i), value(0)), None); } // The result should look like this: @@ -1356,7 +1357,7 @@ mod test { assert_eq!(root.node_type(), NodeType::Internal); assert_eq!( root.entries(btree.memory()), - vec![(K::make(6), encode(V::default()))] + vec![(key(6), encode(value(0)))] ); assert_eq!(root.children_len(), 2); @@ -1364,15 +1365,15 @@ mod test { let right_child = btree.load_node(root.child(1)); assert!(right_child.is_full()); let median_index = right_child.entries_len() / 2; - let expected_median_key = K::make(12); + let expected_median_key = key(12); assert_eq!(right_child.key(median_index), &expected_median_key); // Overwrite the value of the median key. assert_eq!( - btree.insert(expected_median_key.clone(), V::make(123)), - Some(V::default()) + btree.insert(expected_median_key.clone(), value(123)), + Some(value(0)) ); - assert_eq!(btree.get(&expected_median_key), Some(V::make(123))); + assert_eq!(btree.get(&expected_median_key), Some(value(123))); // The child has not been split and is still full. let right_child = btree.load_node(root.child(1)); @@ -1380,16 +1381,16 @@ mod test { assert!(right_child.is_full()); }); } - btree_test!( test_insert_overwrite_median_key_in_full_child_node, insert_overwrite_median_key_in_full_child_node ); fn insert_overwrite_key_in_full_root_node() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { for i in 1..=11 { - assert_eq!(btree.insert(K::make(i), V::default()), None); + assert_eq!(btree.insert(key(i), value(0)), None); } // We now have a root that is full and looks like this: @@ -1399,26 +1400,26 @@ mod test { assert!(root.is_full()); // Overwrite an element in the root. It should NOT cause the node to be split. - assert_eq!(btree.insert(K::make(6), V::make(456)), Some(V::default())); + assert_eq!(btree.insert(key(6), value(456)), Some(value(0))); let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Leaf); - assert_eq!(btree.get(&K::make(6)), Some(V::make(456))); + assert_eq!(btree.get(&key(6)), Some(value(456))); assert_eq!(root.entries_len(), 11); }); } - btree_test!( test_insert_overwrite_key_in_full_root_node, insert_overwrite_key_in_full_root_node ); fn allocations() { + let (key, _value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { // Insert entries until the root node is full. let mut i = 0; loop { - assert_eq!(btree.insert(K::make(i), V::default()), None); + assert_eq!(btree.insert(key(i), V::empty()), None); let root = btree.load_node(btree.root_addr); if root.is_full() { break; @@ -1429,295 +1430,313 @@ mod test { // Only need a single allocation to store up to `CAPACITY` elements. assert_eq!(btree.allocator.num_allocated_chunks(), 1); - assert_eq!(btree.insert(K::make(255), V::default()), None); + assert_eq!(btree.insert(key(255), V::empty()), None); // The node had to be split into three nodes. assert_eq!(btree.allocator.num_allocated_chunks(), 3); }); } - btree_test!(test_allocations, allocations); fn allocations_2() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); - assert_eq!(btree.insert(K::make(1), V::make(20)), None); + assert_eq!(btree.insert(key(1), value(20)), None); assert_eq!(btree.allocator.num_allocated_chunks(), 1); - assert_eq!(btree.remove(&K::make(1)), Some(V::make(20))); + assert_eq!(btree.remove(&key(1)), Some(value(20))); assert_eq!(btree.allocator.num_allocated_chunks(), 0); }); } - btree_test!(test_allocations_2, allocations_2); - // #[test] - // fn pop_last_single_entry() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + fn pop_last_single_entry() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // assert_eq!(btree.insert(b(&[]), b(&[])), None); - // assert!(!btree.is_empty()); - // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + assert_eq!(btree.insert(key(1), value(20)), None); + assert!(!btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 1); - // assert_eq!(btree.pop_last(), Some((b(&[]), b(&[])))); - // assert!(btree.is_empty()); - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // }); - // } + assert_eq!(btree.pop_last(), Some((key(1), value(20)))); + assert!(btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + }); + } + btree_test!(test_pop_last_single_entry, pop_last_single_entry); - // #[test] - // fn pop_first_single_entry() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + fn pop_first_single_entry() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // assert_eq!(btree.insert(b(&[]), b(&[])), None); - // assert!(!btree.is_empty()); - // assert_eq!(btree.allocator.num_allocated_chunks(), 1); + assert_eq!(btree.insert(key(1), value(20)), None); + assert!(!btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 1); - // assert_eq!(btree.pop_first(), Some((b(&[]), b(&[])))); - // assert!(btree.is_empty()); - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // }); - // } + assert_eq!(btree.pop_first(), Some((key(1), value(20)))); + assert!(btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + }); + } + btree_test!(test_pop_first_single_entry, pop_first_single_entry); - // #[test] - // fn insert_same_key_multiple() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(b(&[1]), b(&[2])), None); - // for i in 2..10 { - // assert_eq!(btree.insert(b(&[1]), b(&[i + 1])), Some(b(&[i]))); - // } - // assert_eq!(btree.get(&b(&[1])), Some(b(&[10]))); - // }); - // } + fn insert_same_key_multiple() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + let n = 10; + assert_eq!(btree.insert(key(1), value(2)), None); + for i in 2..n { + assert_eq!(btree.insert(key(1), value(i + 1)), Some(value(i))); + } + assert_eq!(btree.get(&key(1)), Some(value(n))); + }); + } + btree_test!(test_insert_same_key_multiple, insert_same_key_multiple); - // #[test] - // fn insert_split_node() { - // run_btree_test(|mut btree| { - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } + fn insert_split_node() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(key(i), value(10)), None); + } - // // Should now split a node. - // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + // Should now split a node. + let root = btree.load_node(btree.root_addr); + assert!(root.is_full()); + assert_eq!(btree.insert(key(12), value(10)), None); - // // The result should look like this: - // // [6] - // // / \ - // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + // The result should look like this: + // [6] + // / \ + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - // for i in 1..=12 { - // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - // } - // }); - // } + for i in 1..=12 { + assert_eq!(btree.get(&key(i)), Some(value(10))); + } + }); + } + btree_test!(test_insert_split_node, insert_split_node); - // #[test] - // fn insert_split_multiple_nodes() { - // run_btree_test(|mut btree| { - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } - // // Should now split a node. - // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + fn insert_split_multiple_nodes() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + let e = |i: u32| (key(i), encode(value(0))); - // // The result should look like this: - // // [6] - // // / \ - // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(key(i), value(0)), None); + } + // Should now split a node. + assert_eq!(btree.insert(key(12), value(0)), None); - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![e(6)]); - // assert_eq!(root.children_len(), 2); + // The result should look like this: + // [6] + // / \ + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![e(1), e(2), e(3), e(4), e(5)] - // ); + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.entries(btree.memory()), vec![e(6)]); + assert_eq!(root.children_len(), 2); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![e(7), e(8), e(9), e(10), e(11), e(12)] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![e(1), e(2), e(3), e(4), e(5)] + ); - // for i in 1..=12 { - // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - // } + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![e(7), e(8), e(9), e(10), e(11), e(12)] + ); - // // Insert more to cause more splitting. - // assert_eq!(btree.insert(b(&[13]), b(&[])), None); - // assert_eq!(btree.insert(b(&[14]), b(&[])), None); - // assert_eq!(btree.insert(b(&[15]), b(&[])), None); - // assert_eq!(btree.insert(b(&[16]), b(&[])), None); - // assert_eq!(btree.insert(b(&[17]), b(&[])), None); - // // Should cause another split - // assert_eq!(btree.insert(b(&[18]), b(&[])), None); + for i in 1..=12 { + assert_eq!(btree.get(&key(i)), Some(value(0))); + } - // for i in 1..=18 { - // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - // } + // Insert more to cause more splitting. + assert_eq!(btree.insert(key(13), value(0)), None); + assert_eq!(btree.insert(key(14), value(0)), None); + assert_eq!(btree.insert(key(15), value(0)), None); + assert_eq!(btree.insert(key(16), value(0)), None); + assert_eq!(btree.insert(key(17), value(0)), None); + // Should cause another split + assert_eq!(btree.insert(key(18), value(0)), None); + + for i in 1..=18 { + assert_eq!(btree.get(&key(i)), Some(value(0))); + } - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![e(6), e(12)],); - // assert_eq!(root.children_len(), 3); + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.entries(btree.memory()), vec![e(6), e(12)],); + assert_eq!(root.children_len(), 3); - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![e(1), e(2), e(3), e(4), e(5)] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![e(1), e(2), e(3), e(4), e(5)] + ); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![e(7), e(8), e(9), e(10), e(11)] - // ); + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![e(7), e(8), e(9), e(10), e(11)] + ); - // let child_2 = btree.load_node(root.child(2)); - // assert_eq!(child_2.node_type(), NodeType::Leaf); - // assert_eq!( - // child_2.entries(btree.memory()), - // vec![e(13), e(14), e(15), e(16), e(17), e(18)] - // ); - // }); - // } + let child_2 = btree.load_node(root.child(2)); + assert_eq!(child_2.node_type(), NodeType::Leaf); + assert_eq!( + child_2.entries(btree.memory()), + vec![e(13), e(14), e(15), e(16), e(17), e(18)] + ); + }); + } + btree_test!( + test_insert_split_multiple_nodes, + insert_split_multiple_nodes + ); - // #[test] - // fn remove_simple() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - // assert_eq!(btree.remove(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - // assert_eq!(btree.get(&b(&[1, 2, 3])), None); - // }); - // } + fn remove_simple() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + assert_eq!(btree.insert(key(1), value(2)), None); + assert_eq!(btree.get(&key(1)), Some(value(2))); + assert_eq!(btree.remove(&key(1)), Some(value(2))); + assert_eq!(btree.get(&key(1)), None); + }); + } + btree_test!(test_remove_simple, remove_simple); - // #[test] - // fn pop_last_simple() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - // assert_eq!(btree.pop_last().unwrap().1, b(&[4, 5, 6])); - // assert_eq!(btree.get(&b(&[1, 2, 3])), None); - // }); - // } + fn pop_last_simple() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + assert_eq!(btree.insert(key(1), value(1)), None); + assert_eq!(btree.get(&key(1)), Some(value(1))); + assert_eq!(btree.pop_last().unwrap().1, value(1)); + assert_eq!(btree.get(&key(1)), None); + }); + } + btree_test!(test_pop_last_simple, pop_last_simple); - // #[test] - // fn pop_first_simple() { - // run_btree_test(|mut btree| { - // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - // assert_eq!(btree.pop_first().map(|e| e.1), Some(b(&[4, 5, 6]))); - // assert_eq!(btree.get(&b(&[1, 2, 3])), None); - // }); - // } + fn pop_first_simple() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + assert_eq!(btree.insert(key(1), value(1)), None); + assert_eq!(btree.get(&key(1)), Some(value(1))); + assert_eq!(btree.pop_first().map(|e| e.1), Some(value(1))); + assert_eq!(btree.get(&key(1)), None); + }); + } + btree_test!(test_pop_first_simple, pop_first_simple); - // #[test] - // fn pop_on_empty_tree_simple() { - // run_btree_test( - // |mut btree: BTreeMap, Blob<10>, Rc>>>| { - // assert_eq!(btree.pop_last(), None); - // assert_eq!(btree.pop_first(), None); - // }, - // ); - // } + fn pop_on_empty_tree_simple() { + run_btree_test(|mut btree: BTreeMap| { + assert_eq!(btree.pop_last(), None); + assert_eq!(btree.pop_first(), None); + }); + } + btree_test!(test_pop_on_empty_tree_simple, pop_on_empty_tree_simple); - // #[test] - // fn last_key_value_empty_tree_simple() { - // run_btree_test( - // |btree: BTreeMap, Blob<10>, Rc>>>| { - // assert_eq!(btree.last_key_value(), None); - // }, - // ); - // } + fn last_key_value_empty_tree_simple() { + run_btree_test(|btree: BTreeMap| { + assert_eq!(btree.last_key_value(), None); + }); + } + btree_test!( + test_last_key_value_empty_tree_simple, + last_key_value_empty_tree_simple + ); - // #[test] - // fn first_key_value_empty_tree_simple() { - // run_btree_test( - // |btree: BTreeMap, Blob<10>, Rc>>>| { - // assert_eq!(btree.first_key_value(), None); - // }, - // ); - // } + fn first_key_value_empty_tree_simple() { + run_btree_test(|btree: BTreeMap| { + assert_eq!(btree.first_key_value(), None); + }); + } + btree_test!( + test_first_key_value_empty_tree_simple, + first_key_value_empty_tree_simple + ); - // #[test] - // fn remove_case_2a_and_2c() { - // run_btree_test(|mut btree| { - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } - // // Should now split a node. - // assert_eq!(btree.insert(b(&[0]), b(&[])), None); + fn remove_case_2a_and_2c() { + let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let e = |i: u32| (key(i), encode(V::empty())); - // // The result should look like this: - // // [6] - // // / \ - // // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(key(i), V::empty()), None); + } + // Should now split a node. + assert_eq!(btree.insert(key(0), V::empty()), None); - // for i in 0..=11 { - // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - // } + // The result should look like this: + // [6] + // / \ + // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] - // // Remove node 6. Triggers case 2.a - // assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); + for i in 0..=11 { + assert_eq!(btree.get(&key(i)), Some(V::empty())); + } - // // The result should look like this: - // // [5] - // // / \ - // // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![e(5)]); - // assert_eq!(root.children_len(), 2); + // Remove node 6. Triggers case 2.a + assert_eq!(btree.remove(&key(6)), Some(V::empty())); - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![e(0), e(1), e(2), e(3), e(4)] - // ); + // The result should look like this: + // [5] + // / \ + // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.entries(btree.memory()), vec![e(5)]); + assert_eq!(root.children_len(), 2); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![e(7), e(8), e(9), e(10), e(11)] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![e(0), e(1), e(2), e(3), e(4)] + ); - // // There are three allocated nodes. - // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![e(7), e(8), e(9), e(10), e(11)] + ); - // // Remove node 5. Triggers case 2c - // assert_eq!(btree.remove(&b(&[5])), Some(b(&[]))); + // There are three allocated nodes. + assert_eq!(btree.allocator.num_allocated_chunks(), 3); - // // Reload the btree to verify that we saved it correctly. - // let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); + // Remove node 5. Triggers case 2c + assert_eq!(btree.remove(&key(5)), Some(V::empty())); - // // The result should look like this: - // // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11] - // let root = btree.load_node(btree.root_addr); - // assert_eq!( - // root.entries(btree.memory()), - // vec![e(0), e(1), e(2), e(3), e(4), e(7), e(8), e(9), e(10), e(11)] - // ); + // Reload the btree to verify that we saved it correctly. + let btree = BTreeMap::::load(btree.into_memory()); - // // There is only one node allocated. - // assert_eq!(btree.allocator.num_allocated_chunks(), 1); - // }); - // } + // The result should look like this: + // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11] + let root = btree.load_node(btree.root_addr); + assert_eq!( + root.entries(btree.memory()), + vec![e(0), e(1), e(2), e(3), e(4), e(7), e(8), e(9), e(10), e(11)] + ); + + // There is only one node allocated. + assert_eq!(btree.allocator.num_allocated_chunks(), 1); + }); + } + btree_test!(test_remove_case_2a_and_2c, remove_case_2a_and_2c); // #[test] - // fn remove_case_2b() { + // fn remove_case_2b() { // run_btree_test(|mut btree| { // for i in 1..=11 { // assert_eq!(btree.insert(b(&[i]), b(&[])), None); @@ -1784,9 +1803,10 @@ mod test { // ); // }); // } + // btree_test!(test_, ); // #[test] - // fn remove_case_3a_right() { + // fn remove_case_3a_right() { // run_btree_test(|mut btree| { // for i in 1..=11 { // assert_eq!(btree.insert(b(&[i]), b(&[])), None); @@ -1830,9 +1850,10 @@ mod test { // assert_eq!(btree.allocator.num_allocated_chunks(), 3); // }); // } + // btree_test!(test_, ); // #[test] - // fn remove_case_3a_left() { + // fn remove_case_3a_left() { // run_btree_test(|mut btree| { // for i in 1..=11 { // assert_eq!(btree.insert(b(&[i]), b(&[])), None); @@ -1875,9 +1896,10 @@ mod test { // assert_eq!(btree.allocator.num_allocated_chunks(), 3); // }); // } + // btree_test!(test_, ); // #[test] - // fn remove_case_3b_merge_into_right() { + // fn remove_case_3b_merge_into_right() { // run_btree_test(|mut btree| { // for i in 1..=11 { // assert_eq!(btree.insert(b(&[i]), b(&[])), None); @@ -1953,9 +1975,10 @@ mod test { // assert_eq!(btree.allocator.num_allocated_chunks(), 1); // }); // } + // btree_test!(test_, ); // #[test] - // fn remove_case_3b_merge_into_left() { + // fn remove_case_3b_merge_into_left() { // let mem = make_memory(); // let mut btree = BTreeMap::new(mem.clone()); @@ -2023,9 +2046,10 @@ mod test { // // There is only one allocated node remaining. // assert_eq!(btree.allocator.num_allocated_chunks(), 1); // } + // btree_test!(test_, ); // #[test] - // fn many_insertions() { + // fn many_insertions() { // let mem = make_memory(); // let mut btree = BTreeMap::new(mem.clone()); @@ -2058,9 +2082,10 @@ mod test { // // We've deallocated everything. // assert_eq!(btree.allocator.num_allocated_chunks(), 0); // } + // btree_test!(test_, ); // #[test] - // fn many_insertions_2() { + // fn many_insertions_2() { // let mem = make_memory(); // let mut btree = BTreeMap::new(mem.clone()); @@ -2093,9 +2118,10 @@ mod test { // // We've deallocated everything. // assert_eq!(btree.allocator.num_allocated_chunks(), 0); // } + // btree_test!(test_, ); // #[test] - // fn pop_first_many_entries() { + // fn pop_first_many_entries() { // let mem = make_memory(); // let mut std_btree = std::collections::BTreeMap::new(); // let mut btree = BTreeMap::new(mem.clone()); @@ -2135,9 +2161,10 @@ mod test { // assert!(btree.is_empty()); // assert_eq!(btree.allocator.num_allocated_chunks(), 0); // } + // btree_test!(test_, ); // #[test] - // fn pop_last_many_entries() { + // fn pop_last_many_entries() { // let mem = make_memory(); // let mut std_btree = std::collections::BTreeMap::new(); // let mut btree = BTreeMap::new(mem.clone()); @@ -2177,9 +2204,10 @@ mod test { // assert!(btree.is_empty()); // assert_eq!(btree.allocator.num_allocated_chunks(), 0); // } + // btree_test!(test_, ); // #[test] - // fn reloading() { + // fn reloading() { // run_btree_test(|mut btree| { // // The btree is initially empty. // assert_eq!(btree.len(), 0); @@ -2210,9 +2238,10 @@ mod test { // assert!(btree.is_empty()); // }); // } + // btree_test!(test_, ); // #[test] - // fn len() { + // fn len() { // run_btree_test(|mut btree| { // for i in 0..1000u32 { // assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); @@ -2229,9 +2258,10 @@ mod test { // assert!(btree.is_empty()); // }); // } + // btree_test!(test_, ); // #[test] - // fn pop_first_len() { + // fn pop_first_len() { // run_btree_test(|mut btree| { // for i in 0..1000u32 { // assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); @@ -2248,9 +2278,10 @@ mod test { // assert!(btree.is_empty()); // }); // } + // btree_test!(test_, ); // #[test] - // fn pop_last_len() { + // fn pop_last_len() { // run_btree_test(|mut btree| { // for i in 0..1000u32 { // assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); @@ -2267,9 +2298,10 @@ mod test { // assert!(btree.is_empty()); // }); // } + // btree_test!(test_, ); // #[test] - // fn contains_key() { + // fn contains_key() { // run_btree_test(|mut btree| { // // Insert even numbers from 0 to 1000. // for i in (0..1000u32).step_by(2) { @@ -2283,9 +2315,10 @@ mod test { // } // }); // } + // btree_test!(test_, ); // #[test] - // fn range_empty() { + // fn range_empty() { // run_btree_test(|btree| { // // Test prefixes that don't exist in the map. // assert_eq!( @@ -2300,7 +2333,7 @@ mod test { // // Tests the case where the prefix is larger than all the entries in a leaf node. // #[test] - // fn range_leaf_prefix_greater_than_all_entries() { + // fn range_leaf_prefix_greater_than_all_entries() { // run_btree_test(|mut btree| { // btree.insert(b(&[0]), b(&[])); @@ -2311,7 +2344,7 @@ mod test { // // Tests the case where the prefix is larger than all the entries in an internal node. // #[test] - // fn range_internal_prefix_greater_than_all_entries() { + // fn range_internal_prefix_greater_than_all_entries() { // run_btree_test(|mut btree| { // for i in 1..=12 { // assert_eq!(btree.insert(b(&[i]), b(&[])), None); @@ -2329,9 +2362,10 @@ mod test { // ); // }); // } + // btree_test!(test_, ); // #[test] - // fn range_various_prefixes() { + // fn range_various_prefixes() { // run_btree_test(|mut btree| { // btree.insert(b(&[0, 1]), b(&[])); // btree.insert(b(&[0, 2]), b(&[])); @@ -2390,9 +2424,10 @@ mod test { // ); // }); // } + // btree_test!(test_, ); // #[test] - // fn range_various_prefixes_2() { + // fn range_various_prefixes_2() { // run_btree_test(|mut btree| { // btree.insert(b(&[0, 1]), b(&[])); // btree.insert(b(&[0, 2]), b(&[])); @@ -2517,9 +2552,10 @@ mod test { // ); // }); // } + // btree_test!(test_, ); // #[test] - // fn range_large() { + // fn range_large() { // run_btree_test(|mut btree| { // // Insert 1000 elements with prefix 0 and another 1000 elements with prefix 1. // for prefix in 0..=1 { @@ -2558,6 +2594,7 @@ mod test { // } // }); // } + // btree_test!(test_, ); // #[test] // fn range_various_prefixes_with_offset() { @@ -2605,6 +2642,7 @@ mod test { // assert_eq!(btree.range(b(&[2, 5])..).collect::>(), vec![]); // }); // } + // btree_test!(test_, ); // #[test] // fn range_various_prefixes_with_offset_2() { @@ -2709,6 +2747,7 @@ mod test { // ); // }); // } + // btree_test!(test_, ); // #[test] // #[should_panic(expected = "max_key_size must be <= 4")] @@ -2717,6 +2756,7 @@ mod test { // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(btree.into_memory()); // } + // btree_test!(test_, ); // #[test] // fn v2_handles_increases_in_max_key_size_and_max_value_size() { @@ -2745,6 +2785,7 @@ mod test { // Some([2u8; 5].as_slice().try_into().unwrap()) // ); // } + // btree_test!(test_, ); // #[test] // fn accepts_small_or_equal_key_sizes() { @@ -2755,6 +2796,7 @@ mod test { // // Equal key size // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); // } + // btree_test!(test_, ); // #[test] // #[should_panic(expected = "max_value_size must be <= 3")] @@ -2763,6 +2805,7 @@ mod test { // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); // let _btree: BTreeMap, Blob<4>, _> = BTreeMap::init_v1(btree.into_memory()); // } + // btree_test!(test_, ); // #[test] // fn accepts_small_or_equal_value_sizes() { @@ -2773,6 +2816,7 @@ mod test { // // Equal key size // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); // } + // btree_test!(test_, ); // #[test] // fn bruteforce_range_search() { @@ -2834,6 +2878,7 @@ mod test { // } // }); // } + // btree_test!(test_, ); // #[test] // fn test_iter_upper_bound() { @@ -2874,6 +2919,7 @@ mod test { // is_fixed_size: false, // }; // } + // btree_test!(test_, ); // #[test] // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] @@ -2881,6 +2927,7 @@ mod test { // let mut btree = BTreeMap::init_v1(make_memory()); // btree.insert(BuggyStruct, ()); // } + // btree_test!(test_, ); // #[test] // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] @@ -2888,6 +2935,7 @@ mod test { // let mut btree = BTreeMap::init(make_memory()); // btree.insert(BuggyStruct, ()); // } + // btree_test!(test_, ); // #[test] // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] @@ -2895,6 +2943,7 @@ mod test { // let mut btree = BTreeMap::init(make_memory()); // btree.insert((), BuggyStruct); // } + // btree_test!(test_, ); // #[test] // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] @@ -2918,6 +2967,7 @@ mod test { // std::fs::File::create(format!("dumps/btreemap_v{LAYOUT_VERSION}.dump")).unwrap(); // file.write_all(&mem.borrow()).unwrap(); // } + // btree_test!(test_, ); // #[test] // fn produces_layout_identical_to_layout_version_1_with_packed_headers() { @@ -2929,6 +2979,7 @@ mod test { // let btreemap_v1 = include_bytes!("../dumps/btreemap_v1_packed_headers.dump"); // assert_eq!(*mem.borrow(), btreemap_v1); // } + // btree_test!(test_, ); // #[test] // fn read_write_header_is_identical_to_read_write_struct() { @@ -2987,6 +3038,7 @@ mod test { // assert!(packed_header.root_addr == v1_header.root_addr); // assert!(packed_header.length == v1_header.length); // } + // btree_test!(test_, ); // #[test] // fn migrate_from_bounded_to_unbounded_and_back() { @@ -3042,6 +3094,7 @@ mod test { // let btree: BTreeMap = BTreeMap::init(btree.into_memory()); // assert_eq!(btree.get(&T), Some(T)); // } + // btree_test!(test_, ); // #[test] // fn test_clear_new_bounded_type() { @@ -3067,6 +3120,7 @@ mod test { // assert_eq!(header_actual, header_expected); // } + // btree_test!(test_, ); // #[test] // fn test_clear_new_unbounded_type() { @@ -3088,6 +3142,7 @@ mod test { // assert_eq!(header_actual, header_expected); // } + // btree_test!(test_, ); // #[test] // fn deallocating_node_with_overflows() { @@ -3108,6 +3163,7 @@ mod test { // // All chunks have been deallocated. // assert_eq!(btree.allocator.num_allocated_chunks(), 0); // } + // btree_test!(test_, ); // #[test] // fn repeatedly_deallocating_nodes_with_overflows() { @@ -3130,6 +3186,7 @@ mod test { // // All chunks have been deallocated. // assert_eq!(btree.allocator.num_allocated_chunks(), 0); // } + // btree_test!(test_, ); // #[test] // fn deallocating_root_does_not_leak_memory() { From 79fe79cb41a5ac5002974d37ba32560a996f7e3e Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 16:30:27 +0200 Subject: [PATCH 24/66] . --- src/btreemap.rs | 543 +++++++++++++++++++++++++----------------------- 1 file changed, 278 insertions(+), 265 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index ec7f0e75..c4aab5aa 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1735,318 +1735,331 @@ mod test { } btree_test!(test_remove_case_2a_and_2c, remove_case_2a_and_2c); - // #[test] - // fn remove_case_2b() { - // run_btree_test(|mut btree| { - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } - // // Should now split a node. - // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + fn remove_case_2b() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + let e = |i: u32| (key(i), encode(V::empty())); + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(key(i), V::empty()), None); + } + // Should now split a node. + assert_eq!(btree.insert(key(12), V::empty()), None); - // // The result should look like this: - // // [6] - // // / \ - // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + // The result should look like this: + // [6] + // / \ + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - // for i in 1..=12 { - // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - // } + for i in 1..=12 { + assert_eq!(btree.get(&key(i)), Some(V::empty())); + } - // // Remove node 6. Triggers case 2.b - // assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); + // Remove node 6. Triggers case 2.b + assert_eq!(btree.remove(&key(6)), Some(V::empty())); - // // The result should look like this: - // // [7] - // // / \ - // // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![e(7)]); - // assert_eq!(root.children_len(), 2); + // The result should look like this: + // [7] + // / \ + // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.entries(btree.memory()), vec![e(7)]); + assert_eq!(root.children_len(), 2); - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![e(1), e(2), e(3), e(4), e(5)] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![e(1), e(2), e(3), e(4), e(5)] + ); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![e(8), e(9), e(10), e(11), e(12)] - // ); + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![e(8), e(9), e(10), e(11), e(12)] + ); - // // Remove node 7. Triggers case 2.c - // assert_eq!(btree.remove(&b(&[7])), Some(b(&[]))); - // // The result should look like this: - // // - // // [1, 2, 3, 4, 5, 8, 9, 10, 11, 12] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Leaf); - // assert_eq!( - // root.entries(btree.memory()), - // vec![ - // e(1), - // e(2), - // e(3), - // e(4), - // e(5), - // e(8), - // e(9), - // e(10), - // e(11), - // e(12) - // ] - // ); - // }); - // } - // btree_test!(test_, ); + // Remove node 7. Triggers case 2.c + assert_eq!(btree.remove(&key(7)), Some(V::empty())); + // The result should look like this: + // + // [1, 2, 3, 4, 5, 8, 9, 10, 11, 12] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Leaf); + assert_eq!( + root.entries(btree.memory()), + vec![ + e(1), + e(2), + e(3), + e(4), + e(5), + e(8), + e(9), + e(10), + e(11), + e(12) + ] + ); - // #[test] - // fn remove_case_3a_right() { - // run_btree_test(|mut btree| { - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } + assert_eq!(btree.allocator.num_allocated_chunks(), 1); + }); + } + btree_test!(test_remove_case_2b, remove_case_2b); - // // Should now split a node. - // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + fn remove_case_3a_right() { + let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let e = |i: u32| (key(i), encode(V::empty())); + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(key(i), V::empty()), None); + } - // // The result should look like this: - // // [6] - // // / \ - // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + // Should now split a node. + assert_eq!(btree.insert(key(12), V::empty()), None); - // // Remove node 3. Triggers case 3.a - // assert_eq!(btree.remove(&b(&[3])), Some(b(&[]))); + // The result should look like this: + // [6] + // / \ + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - // // The result should look like this: - // // [7] - // // / \ - // // [1, 2, 4, 5, 6] [8, 9, 10, 11, 12] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![e(7)]); - // assert_eq!(root.children_len(), 2); + // Remove node 3. Triggers case 3.a + assert_eq!(btree.remove(&key(3)), Some(V::empty())); - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![e(1), e(2), e(4), e(5), e(6)] - // ); + // The result should look like this: + // [7] + // / \ + // [1, 2, 4, 5, 6] [8, 9, 10, 11, 12] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.entries(btree.memory()), vec![e(7)]); + assert_eq!(root.children_len(), 2); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![e(8), e(9), e(10), e(11), e(12)] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![e(1), e(2), e(4), e(5), e(6)] + ); - // // There are three allocated nodes. - // assert_eq!(btree.allocator.num_allocated_chunks(), 3); - // }); - // } - // btree_test!(test_, ); + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![e(8), e(9), e(10), e(11), e(12)] + ); - // #[test] - // fn remove_case_3a_left() { - // run_btree_test(|mut btree| { - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } - // // Should now split a node. - // assert_eq!(btree.insert(b(&[0]), b(&[])), None); + // There are three allocated nodes. + assert_eq!(btree.allocator.num_allocated_chunks(), 3); + }); + } + btree_test!(test_remove_case_3a_right, remove_case_3a_right); - // // The result should look like this: - // // [6] - // // / \ - // // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] + fn remove_case_3a_left() { + let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let e = |i: u32| (key(i), encode(V::empty())); + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(key(i), V::empty()), None); + } + // Should now split a node. + assert_eq!(btree.insert(key(0), V::empty()), None); - // // Remove node 8. Triggers case 3.a left - // assert_eq!(btree.remove(&b(&[8])), Some(b(&[]))); + // The result should look like this: + // [6] + // / \ + // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] - // // The result should look like this: - // // [5] - // // / \ - // // [0, 1, 2, 3, 4] [6, 7, 9, 10, 11] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![e(5)]); - // assert_eq!(root.children_len(), 2); + // Remove node 8. Triggers case 3.a left + assert_eq!(btree.remove(&key(8)), Some(V::empty())); - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![e(0), e(1), e(2), e(3), e(4)] - // ); + // The result should look like this: + // [5] + // / \ + // [0, 1, 2, 3, 4] [6, 7, 9, 10, 11] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.entries(btree.memory()), vec![e(5)]); + assert_eq!(root.children_len(), 2); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![e(6), e(7), e(9), e(10), e(11)] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![e(0), e(1), e(2), e(3), e(4)] + ); - // // There are three allocated nodes. - // assert_eq!(btree.allocator.num_allocated_chunks(), 3); - // }); - // } - // btree_test!(test_, ); + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![e(6), e(7), e(9), e(10), e(11)] + ); - // #[test] - // fn remove_case_3b_merge_into_right() { - // run_btree_test(|mut btree| { - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } - // // Should now split a node. - // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + // There are three allocated nodes. + assert_eq!(btree.allocator.num_allocated_chunks(), 3); + }); + } + btree_test!(test_remove_case_3a_left, remove_case_3a_left); - // // The result should look like this: - // // [6] - // // / \ - // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + fn remove_case_3b_merge_into_right() { + let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let e = |i: u32| (key(i), encode(V::empty())); + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(key(i), V::empty()), None); + } + // Should now split a node. + assert_eq!(btree.insert(key(12), V::empty()), None); - // for i in 1..=12 { - // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - // } + // The result should look like this: + // [6] + // / \ + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - // // Remove node 6. Triggers case 2.b - // assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); - // // The result should look like this: - // // [7] - // // / \ - // // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![e(7)]); - // assert_eq!(root.children_len(), 2); + for i in 1..=12 { + assert_eq!(btree.get(&key(i)), Some(V::empty())); + } - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![e(1), e(2), e(3), e(4), e(5)] - // ); + // Remove node 6. Triggers case 2.b + assert_eq!(btree.remove(&key(6)), Some(V::empty())); + // The result should look like this: + // [7] + // / \ + // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.entries(btree.memory()), vec![e(7)]); + assert_eq!(root.children_len(), 2); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![e(8), e(9), e(10), e(11), e(12)] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![e(1), e(2), e(3), e(4), e(5)] + ); - // // There are three allocated nodes. - // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![e(8), e(9), e(10), e(11), e(12)] + ); - // // Remove node 3. Triggers case 3.b - // assert_eq!(btree.remove(&b(&[3])), Some(b(&[]))); + // There are three allocated nodes. + assert_eq!(btree.allocator.num_allocated_chunks(), 3); - // // Reload the btree to verify that we saved it correctly. - // let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); + // Remove node 3. Triggers case 3.b + assert_eq!(btree.remove(&key(3)), Some(V::empty())); - // // The result should look like this: - // // - // // [1, 2, 4, 5, 7, 8, 9, 10, 11, 12] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Leaf); - // assert_eq!( - // root.entries(btree.memory()), - // vec![ - // e(1), - // e(2), - // e(4), - // e(5), - // e(7), - // e(8), - // e(9), - // e(10), - // e(11), - // e(12) - // ] - // ); + // Reload the btree to verify that we saved it correctly. + let btree = BTreeMap::::load(btree.into_memory()); - // // There is only one allocated node remaining. - // assert_eq!(btree.allocator.num_allocated_chunks(), 1); - // }); - // } - // btree_test!(test_, ); + // The result should look like this: + // + // [1, 2, 4, 5, 7, 8, 9, 10, 11, 12] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Leaf); + assert_eq!( + root.entries(btree.memory()), + vec![ + e(1), + e(2), + e(4), + e(5), + e(7), + e(8), + e(9), + e(10), + e(11), + e(12) + ] + ); - // #[test] - // fn remove_case_3b_merge_into_left() { - // let mem = make_memory(); - // let mut btree = BTreeMap::new(mem.clone()); + // There is only one allocated node remaining. + assert_eq!(btree.allocator.num_allocated_chunks(), 1); + }); + } + btree_test!( + test_remove_case_3b_merge_into_right, + remove_case_3b_merge_into_right + ); - // for i in 1..=11 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } + fn remove_case_3b_merge_into_left() { + let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let e = |i: u32| (key(i), encode(V::empty())); - // // Should now split a node. - // assert_eq!(btree.insert(b(&[12]), b(&[])), None); + run_btree_test(|mut btree| { + for i in 1..=11 { + assert_eq!(btree.insert(key(i), V::empty()), None); + } - // // The result should look like this: - // // [6] - // // / \ - // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + // Should now split a node. + assert_eq!(btree.insert(key(12), V::empty()), None); - // for i in 1..=12 { - // assert_eq!(btree.get(&b(&[i])), Some(b(&[]))); - // } + // The result should look like this: + // [6] + // / \ + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - // // Remove node 6. Triggers case 2.b - // assert_eq!(btree.remove(&b(&[6])), Some(b(&[]))); + for i in 1..=12 { + assert_eq!(btree.get(&key(i)), Some(V::empty())); + } - // // The result should look like this: - // // [7] - // // / \ - // // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![e(7)]); - // assert_eq!(root.children_len(), 2); + // Remove node 6. Triggers case 2.b + assert_eq!(btree.remove(&key(6)), Some(V::empty())); - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![e(1), e(2), e(3), e(4), e(5)] - // ); + // The result should look like this: + // [7] + // / \ + // [1, 2, 3, 4, 5] [8, 9, 10, 11, 12] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.entries(btree.memory()), vec![e(7)]); + assert_eq!(root.children_len(), 2); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![e(8), e(9), e(10), e(11), e(12)] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![e(1), e(2), e(3), e(4), e(5)] + ); + + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![e(8), e(9), e(10), e(11), e(12)] + ); - // // There are three allocated nodes. - // assert_eq!(btree.allocator.num_allocated_chunks(), 3); + // There are three allocated nodes. + assert_eq!(btree.allocator.num_allocated_chunks(), 3); - // // Remove node 10. Triggers case 3.b where we merge the right into the left. - // assert_eq!(btree.remove(&b(&[10])), Some(b(&[]))); + // Remove node 10. Triggers case 3.b where we merge the right into the left. + assert_eq!(btree.remove(&key(10)), Some(V::empty())); - // // Reload the btree to verify that we saved it correctly. - // let btree = BTreeMap::, Blob<10>, _>::load(mem); + // Reload the btree to verify that we saved it correctly. + let btree = BTreeMap::::load(btree.into_memory()); - // // The result should look like this: - // // - // // [1, 2, 3, 4, 5, 7, 8, 9, 11, 12] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Leaf); - // assert_eq!( - // root.entries(btree.memory()), - // vec![e(1), e(2), e(3), e(4), e(5), e(7), e(8), e(9), e(11), e(12)] - // ); + // The result should look like this: + // + // [1, 2, 3, 4, 5, 7, 8, 9, 11, 12] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Leaf); + assert_eq!( + root.entries(btree.memory()), + vec![e(1), e(2), e(3), e(4), e(5), e(7), e(8), e(9), e(11), e(12)] + ); - // // There is only one allocated node remaining. - // assert_eq!(btree.allocator.num_allocated_chunks(), 1); - // } - // btree_test!(test_, ); + // There is only one allocated node remaining. + assert_eq!(btree.allocator.num_allocated_chunks(), 1); + }); + } + btree_test!( + test_remove_case_3b_merge_into_left, + remove_case_3b_merge_into_left + ); // #[test] // fn many_insertions() { From 2ab1b2d7fbe73ad9904a029608848de793601dc9 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 16:35:42 +0200 Subject: [PATCH 25/66] . --- src/btreemap.rs | 51 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index c4aab5aa..0480a046 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1166,11 +1166,6 @@ mod test { use std::convert::TryFrom; use std::rc::Rc; - /// Creates a new shared memory instance. - pub(crate) fn make_memory() -> Rc>> { - Rc::new(RefCell::new(Vec::new())) - } - /// Returns a fixed‑size buffer for the given u32. fn make_buffer(i: u32) -> [u8; N] { let mut buf = [0u8; N]; @@ -1236,6 +1231,11 @@ mod test { } } + /// Creates a new shared memory instance. + pub(crate) fn make_memory() -> Rc>> { + Rc::new(RefCell::new(Vec::new())) + } + /// A test runner that runs the test using V1, migrated V2, and direct V2. pub fn run_btree_test(f: F) where @@ -1522,15 +1522,14 @@ mod test { btree_test!(test_insert_split_node, insert_split_node); fn insert_split_multiple_nodes() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); - let e = |i: u32| (key(i), encode(value(0))); - + let key = |i| K::make(i); + let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { - assert_eq!(btree.insert(key(i), value(0)), None); + assert_eq!(btree.insert(key(i), V::empty()), None); } // Should now split a node. - assert_eq!(btree.insert(key(12), value(0)), None); + assert_eq!(btree.insert(key(12), V::empty()), None); // The result should look like this: // [6] @@ -1557,20 +1556,20 @@ mod test { ); for i in 1..=12 { - assert_eq!(btree.get(&key(i)), Some(value(0))); + assert_eq!(btree.get(&key(i)), Some(V::empty())); } // Insert more to cause more splitting. - assert_eq!(btree.insert(key(13), value(0)), None); - assert_eq!(btree.insert(key(14), value(0)), None); - assert_eq!(btree.insert(key(15), value(0)), None); - assert_eq!(btree.insert(key(16), value(0)), None); - assert_eq!(btree.insert(key(17), value(0)), None); + assert_eq!(btree.insert(key(13), V::empty()), None); + assert_eq!(btree.insert(key(14), V::empty()), None); + assert_eq!(btree.insert(key(15), V::empty()), None); + assert_eq!(btree.insert(key(16), V::empty()), None); + assert_eq!(btree.insert(key(17), V::empty()), None); // Should cause another split - assert_eq!(btree.insert(key(18), value(0)), None); + assert_eq!(btree.insert(key(18), V::empty()), None); for i in 1..=18 { - assert_eq!(btree.get(&key(i)), Some(value(0))); + assert_eq!(btree.get(&key(i)), Some(V::empty())); } let root = btree.load_node(btree.root_addr); @@ -1598,6 +1597,8 @@ mod test { child_2.entries(btree.memory()), vec![e(13), e(14), e(15), e(16), e(17), e(18)] ); + + assert_eq!(btree.allocator.num_allocated_chunks(), 4); }); } btree_test!( @@ -1667,9 +1668,8 @@ mod test { ); fn remove_case_2a_and_2c() { - let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let key = |i| K::make(i); let e = |i: u32| (key(i), encode(V::empty())); - run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(key(i), V::empty()), None); @@ -1736,7 +1736,7 @@ mod test { btree_test!(test_remove_case_2a_and_2c, remove_case_2a_and_2c); fn remove_case_2b() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let key = |i| K::make(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1809,7 +1809,7 @@ mod test { btree_test!(test_remove_case_2b, remove_case_2b); fn remove_case_3a_right() { - let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let key = |i| K::make(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1857,7 +1857,7 @@ mod test { btree_test!(test_remove_case_3a_right, remove_case_3a_right); fn remove_case_3a_left() { - let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let key = |i| K::make(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1904,7 +1904,7 @@ mod test { btree_test!(test_remove_case_3a_left, remove_case_3a_left); fn remove_case_3b_merge_into_right() { - let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let key = |i| K::make(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1987,9 +1987,8 @@ mod test { ); fn remove_case_3b_merge_into_left() { - let (key, _value) = (|i| K::make(i), |i| V::make(i)); + let key = |i| K::make(i); let e = |i: u32| (key(i), encode(V::empty())); - run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(key(i), V::empty()), None); From 2ef7cbfc9998ea9a5ffbd409d108bbfb7aac8fd7 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 16:48:00 +0200 Subject: [PATCH 26/66] . --- src/btreemap.rs | 97 +++++++++++++++---------------------------------- 1 file changed, 30 insertions(+), 67 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 0480a046..30267b01 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2060,77 +2060,40 @@ mod test { remove_case_3b_merge_into_left ); - // #[test] - // fn many_insertions() { - // let mem = make_memory(); - // let mut btree = BTreeMap::new(mem.clone()); - - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.insert(b(&[i, j]), b(&[i, j])), None); - // } - // } - - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.get(&b(&[i, j])), Some(b(&[i, j]))); - // } - // } - - // let mut btree = BTreeMap::load(mem); - - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.remove(&b(&[i, j])), Some(b(&[i, j]))); - // } - // } - - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.get(&b(&[i, j])), None); - // } - // } - - // // We've deallocated everything. - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // } - // btree_test!(test_, ); - - // #[test] - // fn many_insertions_2() { - // let mem = make_memory(); - // let mut btree = BTreeMap::new(mem.clone()); - - // for j in (0..=10).rev() { - // for i in (0..=255).rev() { - // assert_eq!(btree.insert(b(&[i, j]), b(&[i, j])), None); - // } - // } - - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.get(&b(&[i, j])), Some(b(&[i, j]))); - // } - // } + fn many_insertions(ids: &[u32]) { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + for &i in ids { + assert_eq!(btree.insert(key(i), value(i)), None); + } + for &i in ids { + assert_eq!(btree.get(&key(i)), Some(value(i))); + } - // let mut btree = BTreeMap::load(mem); + let mut btree = BTreeMap::::load(btree.into_memory()); + for &i in ids { + assert_eq!(btree.remove(&key(i)), Some(value(i))); + } + for &i in ids { + assert_eq!(btree.get(&key(i)), None); + } - // for j in (0..=10).rev() { - // for i in (0..=255).rev() { - // assert_eq!(btree.remove(&b(&[i, j])), Some(b(&[i, j]))); - // } - // } + // We've deallocated everything. + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + }); + } - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.get(&b(&[i, j])), None); - // } - // } + fn many_insertions_ascending() { + let n = 10_000; + many_insertions::(&(0..n).collect::>()); + } + btree_test!(test_many_insertions_ascending, many_insertions_ascending); - // // We've deallocated everything. - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // } - // btree_test!(test_, ); + fn many_insertions_descending() { + let n = 10_000; + many_insertions::(&(0..n).rev().collect::>()); + } + btree_test!(test_many_insertions_descending, many_insertions_descending); // #[test] // fn pop_first_many_entries() { From 9be63d7bc9b17b65a278c7a93f7581bd529702b7 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 16:58:23 +0200 Subject: [PATCH 27/66] . --- src/btreemap.rs | 140 ++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 82 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 30267b01..4f38e328 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1286,8 +1286,8 @@ mod test { impl TestKey for T where T: Storable + Ord + Clone + Make + std::fmt::Debug {} // Define a trait for values that need the full set of bounds. - trait TestValue: Storable + Make + std::fmt::Debug + PartialEq {} - impl TestValue for T where T: Storable + Make + std::fmt::Debug + PartialEq {} + trait TestValue: Storable + Clone + Make + std::fmt::Debug + PartialEq {} + impl TestValue for T where T: Storable + Clone + Make + std::fmt::Debug + PartialEq {} fn init_preserves_data() { let (key, value) = (|i| K::make(i), |i| V::make(i)); @@ -2095,91 +2095,67 @@ mod test { } btree_test!(test_many_insertions_descending, many_insertions_descending); - // #[test] - // fn pop_first_many_entries() { - // let mem = make_memory(); - // let mut std_btree = std::collections::BTreeMap::new(); - // let mut btree = BTreeMap::new(mem.clone()); - - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!( - // btree.insert(b(&[i, j]), b(&[i, j])), - // std_btree.insert(b(&[i, j]), b(&[i, j])) - // ); - // } - // } - - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.get(&b(&[i, j])), std_btree.get(&b(&[i, j])).cloned()); - // } - // } - - // let mut btree = BTreeMap::load(mem); - - // for _ in 0..=10 { - // for _ in 0..=255 { - // assert_eq!(btree.pop_first(), std_btree.pop_first()); - // } - // } - - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.get(&b(&[i, j])), None); - // assert_eq!(std_btree.get(&b(&[i, j])), None); - // } - // } - - // // We've deallocated everything. - // assert!(std_btree.is_empty()); - // assert!(btree.is_empty()); - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // } - // btree_test!(test_, ); - - // #[test] - // fn pop_last_many_entries() { - // let mem = make_memory(); - // let mut std_btree = std::collections::BTreeMap::new(); - // let mut btree = BTreeMap::new(mem.clone()); - - // for j in (0..=10).rev() { - // for i in (0..=255).rev() { - // assert_eq!( - // btree.insert(b(&[i, j]), b(&[i, j])), - // std_btree.insert(b(&[i, j]), b(&[i, j])) - // ); - // } - // } + fn pop_first_many_entries() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + let mut std_btree = std::collections::BTreeMap::::new(); + let n = 10_000; + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + assert_eq!(std_btree.insert(key(i), value(i)), None); + } + for i in 0..n { + assert_eq!(btree.get(&key(i)), Some(value(i))); + assert_eq!(std_btree.get(&key(i)), Some(&value(i))); + } - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.get(&b(&[i, j])), std_btree.get(&b(&[i, j])).cloned()); - // } - // } + let mut btree = BTreeMap::::load(btree.into_memory()); + for _ in 0..n { + assert_eq!(btree.pop_first(), std_btree.pop_first()); + } + for i in 0..n { + assert_eq!(btree.get(&key(i)), None); + assert_eq!(std_btree.get(&key(i)), None); + } - // let mut btree = BTreeMap::load(mem); + // We've deallocated everything. + assert!(btree.is_empty()); + assert!(std_btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + }); + } + btree_test!(test_pop_first_many_entries, pop_first_many_entries); - // for _ in (0..=10).rev() { - // for _ in (0..=255).rev() { - // assert_eq!(btree.pop_last(), std_btree.pop_last()); - // } - // } + fn pop_last_many_entries() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + let mut std_btree = std::collections::BTreeMap::::new(); + let n = 10_000; + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + assert_eq!(std_btree.insert(key(i), value(i)), None); + } + for i in 0..n { + assert_eq!(btree.get(&key(i)), Some(value(i))); + assert_eq!(std_btree.get(&key(i)), Some(&value(i))); + } - // for j in 0..=10 { - // for i in 0..=255 { - // assert_eq!(btree.get(&b(&[i, j])), None); - // assert_eq!(std_btree.get(&b(&[i, j])), None); - // } - // } + let mut btree = BTreeMap::::load(btree.into_memory()); + for _ in 0..n { + assert_eq!(btree.pop_last(), std_btree.pop_last()); + } + for i in 0..n { + assert_eq!(btree.get(&key(i)), None); + assert_eq!(std_btree.get(&key(i)), None); + } - // // We've deallocated everything. - // assert!(std_btree.is_empty()); - // assert!(btree.is_empty()); - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // } - // btree_test!(test_, ); + // We've deallocated everything. + assert!(btree.is_empty()); + assert!(std_btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + }); + } + btree_test!(test_pop_last_many_entries, pop_last_many_entries); // #[test] // fn reloading() { From 13d102f757dcde92157b7f389f772cb585f9cbd9 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 19:09:12 +0200 Subject: [PATCH 28/66] . --- src/btreemap.rs | 287 +++++++++++++++++++++++------------------------- 1 file changed, 138 insertions(+), 149 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 4f38e328..bf29928a 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1169,9 +1169,8 @@ mod test { /// Returns a fixed‑size buffer for the given u32. fn make_buffer(i: u32) -> [u8; N] { let mut buf = [0u8; N]; - let bytes = i.to_le_bytes(); - let len = N.min(bytes.len()); - buf[..len].copy_from_slice(&bytes[..len]); + let bytes = i.to_be_bytes(); + buf[N - bytes.len()..].copy_from_slice(&bytes); buf } @@ -1222,15 +1221,6 @@ mod test { Blob::<10>::try_from(x).unwrap() } - /// Asserts that keys from consecutive IDs are strictly increasing. - /// - /// This is important for the B-tree structure to maintain its properties. - fn verify_monotonic_keys() { - for i in 0..10 { - assert!(T::make(i) < T::make(i + 1)); - } - } - /// Creates a new shared memory instance. pub(crate) fn make_memory() -> Rc>> { Rc::new(RefCell::new(Vec::new())) @@ -1260,6 +1250,15 @@ mod test { f(tree_v2); } + /// Checks that objects from boundary u32 values are strictly increasing. + /// This ensures multi-byte conversions preserve order. + fn verify_monotonic() { + for shift_bits in [8, 16, 24] { + let i = (1 << shift_bits) - 1; + assert!(T::make(i) < T::make(i + 1), "Monotonicity failed at i: {i}",); + } + } + /// Macro to apply a test function to a predefined grid of key/value types. macro_rules! btree_test { ($name:ident, $runner_fn:ident) => { @@ -1268,13 +1267,13 @@ mod test { { type K = u32; type V = Blob<20>; - verify_monotonic_keys::(); + verify_monotonic::(); $runner_fn::(); } { type K = Blob<10>; type V = Blob<20>; - verify_monotonic_keys::(); + verify_monotonic::(); $runner_fn::(); } } @@ -1289,34 +1288,38 @@ mod test { trait TestValue: Storable + Clone + Make + std::fmt::Debug + PartialEq {} impl TestValue for T where T: Storable + Clone + Make + std::fmt::Debug + PartialEq {} - fn init_preserves_data() { + fn insert_get_init_preserves_data() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - assert_eq!(btree.insert(key(1), value(20)), None); - assert_eq!(btree.get(&key(1)), Some(value(20))); + let n = 1_000; + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + } + for i in 0..n { + assert_eq!(btree.get(&key(i)), Some(value(i))); + } // Reload the BTreeMap and verify the entry. let btree = BTreeMap::::init(btree.into_memory()); - assert_eq!(btree.get(&key(1)), Some(value(20))); - }); - } - btree_test!(test_init_preserves_data, init_preserves_data); - - fn insert_get() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); - run_btree_test(|mut btree| { - assert_eq!(btree.insert(key(1), value(20)), None); - assert_eq!(btree.get(&key(1)), Some(value(20))); + for i in 0..n { + assert_eq!(btree.get(&key(i)), Some(value(i))); + } }); } - btree_test!(test_insert_get, insert_get); + btree_test!( + test_insert_get_init_preserves_data, + insert_get_init_preserves_data + ); fn insert_overwrites_previous_value() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - assert_eq!(btree.insert(key(1), value(20)), None); - assert_eq!(btree.insert(key(1), value(30)), Some(value(20))); - assert_eq!(btree.get(&key(1)), Some(value(30))); + let n = 1_000; + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + assert_eq!(btree.insert(key(i), value(i + 1)), Some(value(i))); + assert_eq!(btree.get(&key(i)), Some(value(i + 1))); + } }); } btree_test!( @@ -1324,22 +1327,18 @@ mod test { insert_overwrites_previous_value ); - fn insert_get_multiple_entries() { + fn insert_same_key_multiple() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - let n = 10_000; - for i in 0..n { - assert_eq!(btree.insert(key(i), value(i)), None); - } - for i in 0..n { - assert_eq!(btree.get(&key(i)), Some(value(i))); + let n = 1_000; + assert_eq!(btree.insert(key(1), value(2)), None); + for i in 2..n { + assert_eq!(btree.insert(key(1), value(i + 1)), Some(value(i))); } + assert_eq!(btree.get(&key(1)), Some(value(n))); }); } - btree_test!( - test_insert_get_multiple_entries, - insert_get_multiple_entries - ); + btree_test!(test_insert_same_key_multiple, insert_same_key_multiple); fn insert_overwrite_median_key_in_full_child_node() { let (key, value) = (|i| K::make(i), |i| V::make(i)); @@ -1395,7 +1394,7 @@ mod test { // We now have a root that is full and looks like this: // - // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + // [1, 2, 3, 4, 5, (6), 7, 8, 9, 10, 11] let root = btree.load_node(btree.root_addr); assert!(root.is_full()); @@ -1413,8 +1412,22 @@ mod test { insert_overwrite_key_in_full_root_node ); - fn allocations() { - let (key, _value) = (|i| K::make(i), |i| V::make(i)); + fn allocations_without_split() { + let key = |i| K::make(i); + run_btree_test(|mut btree| { + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + assert_eq!(btree.insert(key(1), V::empty()), None); + assert_eq!(btree.allocator.num_allocated_chunks(), 1); + + assert_eq!(btree.remove(&key(1)), Some(V::empty())); + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + }); + } + btree_test!(test_allocations_without_split, allocations_without_split); + + fn allocations_with_split() { + let key = |i| K::make(i); run_btree_test(|mut btree| { // Insert entries until the root node is full. let mut i = 0; @@ -1436,66 +1449,7 @@ mod test { assert_eq!(btree.allocator.num_allocated_chunks(), 3); }); } - btree_test!(test_allocations, allocations); - - fn allocations_2() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); - run_btree_test(|mut btree| { - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - - assert_eq!(btree.insert(key(1), value(20)), None); - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - - assert_eq!(btree.remove(&key(1)), Some(value(20))); - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - }); - } - btree_test!(test_allocations_2, allocations_2); - - fn pop_last_single_entry() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); - run_btree_test(|mut btree| { - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - - assert_eq!(btree.insert(key(1), value(20)), None); - assert!(!btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - - assert_eq!(btree.pop_last(), Some((key(1), value(20)))); - assert!(btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - }); - } - btree_test!(test_pop_last_single_entry, pop_last_single_entry); - - fn pop_first_single_entry() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); - run_btree_test(|mut btree| { - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - - assert_eq!(btree.insert(key(1), value(20)), None); - assert!(!btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 1); - - assert_eq!(btree.pop_first(), Some((key(1), value(20)))); - assert!(btree.is_empty()); - assert_eq!(btree.allocator.num_allocated_chunks(), 0); - }); - } - btree_test!(test_pop_first_single_entry, pop_first_single_entry); - - fn insert_same_key_multiple() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); - run_btree_test(|mut btree| { - let n = 10; - assert_eq!(btree.insert(key(1), value(2)), None); - for i in 2..n { - assert_eq!(btree.insert(key(1), value(i + 1)), Some(value(i))); - } - assert_eq!(btree.get(&key(1)), Some(value(n))); - }); - } - btree_test!(test_insert_same_key_multiple, insert_same_key_multiple); + btree_test!(test_allocations_with_split, allocations_with_split); fn insert_split_node() { let (key, value) = (|i| K::make(i), |i| V::make(i)); @@ -1606,66 +1560,106 @@ mod test { insert_split_multiple_nodes ); - fn remove_simple() { + fn remove_multiple() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - assert_eq!(btree.insert(key(1), value(2)), None); - assert_eq!(btree.get(&key(1)), Some(value(2))); - assert_eq!(btree.remove(&key(1)), Some(value(2))); - assert_eq!(btree.get(&key(1)), None); + let n = 1_000; + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + assert_eq!(btree.get(&key(i)), Some(value(i))); + } + for i in 0..n { + assert_eq!(btree.remove(&key(i)), Some(value(i))); + assert_eq!(btree.get(&key(i)), None); + } }); } - btree_test!(test_remove_simple, remove_simple); + btree_test!(test_remove_multiple, remove_multiple); - fn pop_last_simple() { + fn first_key_value() { let (key, value) = (|i| K::make(i), |i| V::make(i)); - run_btree_test(|mut btree| { - assert_eq!(btree.insert(key(1), value(1)), None); - assert_eq!(btree.get(&key(1)), Some(value(1))); - assert_eq!(btree.pop_last().unwrap().1, value(1)); - assert_eq!(btree.get(&key(1)), None); + run_btree_test(|mut btree: BTreeMap| { + assert_eq!(btree.first_key_value(), None); + + let n = 1_000; + for i in (0..n).rev() { + assert_eq!(btree.insert(key(i), value(i)), None); + assert_eq!(btree.first_key_value(), Some((key(i), value(i)))); + } + + for i in 0..n { + assert_eq!(btree.remove(&key(i)), Some(value(i))); + if !btree.is_empty() { + assert_eq!(btree.first_key_value(), Some((key(i + 1), value(i + 1)))); + } + } + assert_eq!(btree.first_key_value(), None); }); } - btree_test!(test_pop_last_simple, pop_last_simple); + btree_test!(test_first_key_value, first_key_value); - fn pop_first_simple() { + fn last_key_value() { let (key, value) = (|i| K::make(i), |i| V::make(i)); - run_btree_test(|mut btree| { - assert_eq!(btree.insert(key(1), value(1)), None); - assert_eq!(btree.get(&key(1)), Some(value(1))); - assert_eq!(btree.pop_first().map(|e| e.1), Some(value(1))); - assert_eq!(btree.get(&key(1)), None); + run_btree_test(|mut btree: BTreeMap| { + assert_eq!(btree.last_key_value(), None); + + let n = 1_000; + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + assert_eq!(btree.last_key_value(), Some((key(i), value(i)))); + } + + for i in (0..n).rev() { + assert_eq!(btree.remove(&key(i)), Some(value(i))); + if !btree.is_empty() { + assert_eq!(btree.last_key_value(), Some((key(i - 1), value(i - 1)))); + } + } + assert_eq!(btree.last_key_value(), None); }); } - btree_test!(test_pop_first_simple, pop_first_simple); + btree_test!(test_last_key_value, last_key_value); - fn pop_on_empty_tree_simple() { + fn pop_on_empty_tree() { run_btree_test(|mut btree: BTreeMap| { - assert_eq!(btree.pop_last(), None); + assert!(btree.is_empty()); assert_eq!(btree.pop_first(), None); + assert_eq!(btree.pop_last(), None); }); } - btree_test!(test_pop_on_empty_tree_simple, pop_on_empty_tree_simple); + btree_test!(test_pop_on_empty_tree, pop_on_empty_tree); - fn last_key_value_empty_tree_simple() { - run_btree_test(|btree: BTreeMap| { - assert_eq!(btree.last_key_value(), None); + fn pop_first_single_entry() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + assert_eq!(btree.insert(key(1), value(1)), None); + assert!(!btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 1); + + assert_eq!(btree.pop_first(), Some((key(1), value(1)))); + assert!(btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 0); }); } - btree_test!( - test_last_key_value_empty_tree_simple, - last_key_value_empty_tree_simple - ); + btree_test!(test_pop_first_single_entry, pop_first_single_entry); - fn first_key_value_empty_tree_simple() { - run_btree_test(|btree: BTreeMap| { - assert_eq!(btree.first_key_value(), None); + fn pop_last_single_entry() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + assert_eq!(btree.insert(key(1), value(1)), None); + assert!(!btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 1); + + assert_eq!(btree.pop_last(), Some((key(1), value(1)))); + assert!(btree.is_empty()); + assert_eq!(btree.allocator.num_allocated_chunks(), 0); }); } - btree_test!( - test_first_key_value_empty_tree_simple, - first_key_value_empty_tree_simple - ); + btree_test!(test_pop_last_single_entry, pop_last_single_entry); fn remove_case_2a_and_2c() { let key = |i| K::make(i); @@ -2098,29 +2092,24 @@ mod test { fn pop_first_many_entries() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - let mut std_btree = std::collections::BTreeMap::::new(); let n = 10_000; for i in 0..n { assert_eq!(btree.insert(key(i), value(i)), None); - assert_eq!(std_btree.insert(key(i), value(i)), None); } for i in 0..n { assert_eq!(btree.get(&key(i)), Some(value(i))); - assert_eq!(std_btree.get(&key(i)), Some(&value(i))); } let mut btree = BTreeMap::::load(btree.into_memory()); - for _ in 0..n { - assert_eq!(btree.pop_first(), std_btree.pop_first()); + for i in 0..n { + assert_eq!(btree.pop_first(), Some((key(i), value(i)))); } for i in 0..n { assert_eq!(btree.get(&key(i)), None); - assert_eq!(std_btree.get(&key(i)), None); } // We've deallocated everything. assert!(btree.is_empty()); - assert!(std_btree.is_empty()); assert_eq!(btree.allocator.num_allocated_chunks(), 0); }); } From a753d7aa5924d8cf6ab90ba7b63ca3b014b50d7a Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 19:17:03 +0200 Subject: [PATCH 29/66] . --- src/btreemap.rs | 58 ++++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index bf29928a..c9d9547c 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1783,18 +1783,10 @@ mod test { assert_eq!(root.node_type(), NodeType::Leaf); assert_eq!( root.entries(btree.memory()), - vec![ - e(1), - e(2), - e(3), - e(4), - e(5), - e(8), - e(9), - e(10), - e(11), - e(12) - ] + [1, 2, 3, 4, 5, 8, 9, 10, 11, 12] + .into_iter() + .map(e) + .collect::>() ); assert_eq!(btree.allocator.num_allocated_chunks(), 1); @@ -1957,18 +1949,10 @@ mod test { assert_eq!(root.node_type(), NodeType::Leaf); assert_eq!( root.entries(btree.memory()), - vec![ - e(1), - e(2), - e(4), - e(5), - e(7), - e(8), - e(9), - e(10), - e(11), - e(12) - ] + [1, 2, 4, 5, 7, 8, 9, 10, 11, 12] + .into_iter() + .map(e) + .collect::>() ); // There is only one allocated node remaining. @@ -2037,7 +2021,7 @@ mod test { // The result should look like this: // - // [1, 2, 3, 4, 5, 7, 8, 9, 11, 12] + // [1, 2, 3, 4, 5, 7, 8, 9, 11, 12], 10 is gone let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Leaf); assert_eq!( @@ -2054,21 +2038,22 @@ mod test { remove_case_3b_merge_into_left ); - fn many_insertions(ids: &[u32]) { + fn insert_remove_many() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - for &i in ids { + let n = 10_000; + for i in 0..n { assert_eq!(btree.insert(key(i), value(i)), None); } - for &i in ids { + for i in 0..n { assert_eq!(btree.get(&key(i)), Some(value(i))); } let mut btree = BTreeMap::::load(btree.into_memory()); - for &i in ids { + for i in 0..n { assert_eq!(btree.remove(&key(i)), Some(value(i))); } - for &i in ids { + for i in 0..n { assert_eq!(btree.get(&key(i)), None); } @@ -2076,18 +2061,7 @@ mod test { assert_eq!(btree.allocator.num_allocated_chunks(), 0); }); } - - fn many_insertions_ascending() { - let n = 10_000; - many_insertions::(&(0..n).collect::>()); - } - btree_test!(test_many_insertions_ascending, many_insertions_ascending); - - fn many_insertions_descending() { - let n = 10_000; - many_insertions::(&(0..n).rev().collect::>()); - } - btree_test!(test_many_insertions_descending, many_insertions_descending); + btree_test!(test_insert_remove_many, insert_remove_many); fn pop_first_many_entries() { let (key, value) = (|i| K::make(i), |i| V::make(i)); From 744c5dead60f6b2740089998f4e132734105bbbf Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 19:25:19 +0200 Subject: [PATCH 30/66] . --- src/btreemap.rs | 70 +++++++++++-------------------------------------- 1 file changed, 16 insertions(+), 54 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index c9d9547c..eefbf200 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1294,8 +1294,6 @@ mod test { let n = 1_000; for i in 0..n { assert_eq!(btree.insert(key(i), value(i)), None); - } - for i in 0..n { assert_eq!(btree.get(&key(i)), Some(value(i))); } @@ -1327,7 +1325,7 @@ mod test { insert_overwrites_previous_value ); - fn insert_same_key_multiple() { + fn insert_same_key_many() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { let n = 1_000; @@ -1338,7 +1336,7 @@ mod test { assert_eq!(btree.get(&key(1)), Some(value(n))); }); } - btree_test!(test_insert_same_key_multiple, insert_same_key_multiple); + btree_test!(test_insert_same_key_many, insert_same_key_many); fn insert_overwrite_median_key_in_full_child_node() { let (key, value) = (|i| K::make(i), |i| V::make(i)); @@ -1560,22 +1558,6 @@ mod test { insert_split_multiple_nodes ); - fn remove_multiple() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); - run_btree_test(|mut btree| { - let n = 1_000; - for i in 0..n { - assert_eq!(btree.insert(key(i), value(i)), None); - assert_eq!(btree.get(&key(i)), Some(value(i))); - } - for i in 0..n { - assert_eq!(btree.remove(&key(i)), Some(value(i))); - assert_eq!(btree.get(&key(i)), None); - } - }); - } - btree_test!(test_remove_multiple, remove_multiple); - fn first_key_value() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree: BTreeMap| { @@ -1620,15 +1602,6 @@ mod test { } btree_test!(test_last_key_value, last_key_value); - fn pop_on_empty_tree() { - run_btree_test(|mut btree: BTreeMap| { - assert!(btree.is_empty()); - assert_eq!(btree.pop_first(), None); - assert_eq!(btree.pop_last(), None); - }); - } - btree_test!(test_pop_on_empty_tree, pop_on_empty_tree); - fn pop_first_single_entry() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { @@ -2044,16 +2017,12 @@ mod test { let n = 10_000; for i in 0..n { assert_eq!(btree.insert(key(i), value(i)), None); - } - for i in 0..n { assert_eq!(btree.get(&key(i)), Some(value(i))); } let mut btree = BTreeMap::::load(btree.into_memory()); for i in 0..n { assert_eq!(btree.remove(&key(i)), Some(value(i))); - } - for i in 0..n { assert_eq!(btree.get(&key(i)), None); } @@ -2063,22 +2032,21 @@ mod test { } btree_test!(test_insert_remove_many, insert_remove_many); - fn pop_first_many_entries() { + fn pop_first_many() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { let n = 10_000; + + assert!(btree.is_empty()); + assert_eq!(btree.pop_first(), None); + for i in 0..n { assert_eq!(btree.insert(key(i), value(i)), None); } - for i in 0..n { - assert_eq!(btree.get(&key(i)), Some(value(i))); - } let mut btree = BTreeMap::::load(btree.into_memory()); for i in 0..n { assert_eq!(btree.pop_first(), Some((key(i), value(i)))); - } - for i in 0..n { assert_eq!(btree.get(&key(i)), None); } @@ -2087,38 +2055,32 @@ mod test { assert_eq!(btree.allocator.num_allocated_chunks(), 0); }); } - btree_test!(test_pop_first_many_entries, pop_first_many_entries); + btree_test!(test_pop_first_many, pop_first_many); - fn pop_last_many_entries() { + fn pop_last_many() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - let mut std_btree = std::collections::BTreeMap::::new(); let n = 10_000; + + assert!(btree.is_empty()); + assert_eq!(btree.pop_last(), None); + for i in 0..n { assert_eq!(btree.insert(key(i), value(i)), None); - assert_eq!(std_btree.insert(key(i), value(i)), None); - } - for i in 0..n { - assert_eq!(btree.get(&key(i)), Some(value(i))); - assert_eq!(std_btree.get(&key(i)), Some(&value(i))); } let mut btree = BTreeMap::::load(btree.into_memory()); - for _ in 0..n { - assert_eq!(btree.pop_last(), std_btree.pop_last()); - } - for i in 0..n { + for i in (0..n).rev() { + assert_eq!(btree.pop_last(), Some((key(i), value(i)))); assert_eq!(btree.get(&key(i)), None); - assert_eq!(std_btree.get(&key(i)), None); } // We've deallocated everything. assert!(btree.is_empty()); - assert!(std_btree.is_empty()); assert_eq!(btree.allocator.num_allocated_chunks(), 0); }); } - btree_test!(test_pop_last_many_entries, pop_last_many_entries); + btree_test!(test_pop_last_many, pop_last_many); // #[test] // fn reloading() { From abb1b7f8f3cfd08300f1284de8c09efc1451ade4 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 19:40:32 +0200 Subject: [PATCH 31/66] . --- src/btreemap.rs | 131 +++++++++++++++++------------------------------- 1 file changed, 45 insertions(+), 86 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index eefbf200..59f379fa 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2043,6 +2043,7 @@ mod test { for i in 0..n { assert_eq!(btree.insert(key(i), value(i)), None); } + assert_eq!(btree.len(), n as u64); let mut btree = BTreeMap::::load(btree.into_memory()); for i in 0..n { @@ -2068,6 +2069,7 @@ mod test { for i in 0..n { assert_eq!(btree.insert(key(i), value(i)), None); } + assert_eq!(btree.len(), n as u64); let mut btree = BTreeMap::::load(btree.into_memory()); for i in (0..n).rev() { @@ -2082,99 +2084,56 @@ mod test { } btree_test!(test_pop_last_many, pop_last_many); - // #[test] - // fn reloading() { - // run_btree_test(|mut btree| { - // // The btree is initially empty. - // assert_eq!(btree.len(), 0); - // assert!(btree.is_empty()); - - // // Add an entry into the btree. - // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - // assert_eq!(btree.len(), 1); - // assert!(!btree.is_empty()); - - // // Reload the btree. The element should still be there, and `len()` - // // should still be `1`. - // let btree = BTreeMap::load(btree.into_memory()); - // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - // assert_eq!(btree.len(), 1); - // assert!(!btree.is_empty()); - - // // Remove an element. Length should be zero. - // let mut btree = BTreeMap::load(btree.into_memory()); - // assert_eq!(btree.remove(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); - // assert_eq!(btree.len(), 0); - // assert!(btree.is_empty()); - - // // Reload. Btree should still be empty. - // let btree = BTreeMap::, Blob<10>, _>::load(btree.into_memory()); - // assert_eq!(btree.get(&b(&[1, 2, 3])), None); - // assert_eq!(btree.len(), 0); - // assert!(btree.is_empty()); - // }); - // } - // btree_test!(test_, ); - - // #[test] - // fn len() { - // run_btree_test(|mut btree| { - // for i in 0..1000u32 { - // assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); - // } - - // assert_eq!(btree.len(), 1000); - // assert!(!btree.is_empty()); - - // for i in 0..1000u32 { - // assert_eq!(btree.remove(&b(&i.to_le_bytes())), Some(b(&[]))); - // } - - // assert_eq!(btree.len(), 0); - // assert!(btree.is_empty()); - // }); - // } - // btree_test!(test_, ); - - // #[test] - // fn pop_first_len() { - // run_btree_test(|mut btree| { - // for i in 0..1000u32 { - // assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); - // } + fn reloading() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + let n = 1_000; + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + assert_eq!(btree.get(&key(i)), Some(value(i))); + } + assert_eq!(btree.len(), n as u64); - // assert_eq!(btree.len(), 1000); - // assert!(!btree.is_empty()); + // Reload the BTreeMap and verify the entry. + let mut btree = BTreeMap::::load(btree.into_memory()); + assert_eq!(btree.len(), n as u64); + for i in 0..n { + assert_eq!(btree.get(&key(i)), Some(value(i))); + } - // for i in 0..1000u32 { - // assert_eq!(btree.pop_first().unwrap().1, b(&i.to_le_bytes())); - // } + // Remove all entries and verify the entry. + for i in 0..n { + assert_eq!(btree.remove(&key(i)), Some(value(i))); + } + assert_eq!(btree.len(), 0); - // assert_eq!(btree.len(), 0); - // assert!(btree.is_empty()); - // }); - // } - // btree_test!(test_, ); + // Reload the BTreeMap and verify the entry. + let btree = BTreeMap::::load(btree.into_memory()); + assert_eq!(btree.len(), 0); + }); + } + btree_test!(test_reloading, reloading); - // #[test] - // fn pop_last_len() { - // run_btree_test(|mut btree| { - // for i in 0..1000u32 { - // assert_eq!(btree.insert(i, b(&i.to_le_bytes())), None); - // } + fn len() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + let n = 1_000; + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + } - // assert_eq!(btree.len(), 1000); - // assert!(!btree.is_empty()); + assert_eq!(btree.len(), n as u64); + assert!(!btree.is_empty()); - // for i in (0..1000u32).rev() { - // assert_eq!(btree.pop_last().unwrap().1, b(&i.to_le_bytes())); - // } + for i in 0..n { + assert_eq!(btree.remove(&key(i)), Some(value(i))); + } - // assert_eq!(btree.len(), 0); - // assert!(btree.is_empty()); - // }); - // } - // btree_test!(test_, ); + assert_eq!(btree.len(), 0); + assert!(btree.is_empty()); + }); + } + btree_test!(test_len, len); // #[test] // fn contains_key() { From a5aff03d643729df3ea5ed71c429958c9bc2a808 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 19:46:34 +0200 Subject: [PATCH 32/66] . --- src/btreemap.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 59f379fa..29fcfb2b 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2135,22 +2135,21 @@ mod test { } btree_test!(test_len, len); - // #[test] - // fn contains_key() { - // run_btree_test(|mut btree| { - // // Insert even numbers from 0 to 1000. - // for i in (0..1000u32).step_by(2) { - // assert_eq!(btree.insert(b(&i.to_le_bytes()), b(&[])), None); - // } + fn contains_key() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + let n = 1_000; + for i in (0..n).step_by(2) { + assert_eq!(btree.insert(key(i), value(i)), None); + } - // // Contains key should return true on all the even numbers and false on all the odd - // // numbers. - // for i in 0..1000u32 { - // assert_eq!(btree.contains_key(&b(&i.to_le_bytes())), i % 2 == 0); - // } - // }); - // } - // btree_test!(test_, ); + // Only even keys should be present. + for i in 0..n { + assert_eq!(btree.contains_key(&key(i)), i % 2 == 0); + } + }); + } + btree_test!(test_contains_key, contains_key); // #[test] // fn range_empty() { From c5229391b4861bb45df3ffe9a7b0f91b9507c3a1 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 20:21:46 +0200 Subject: [PATCH 33/66] range --- src/btreemap.rs | 467 +++++++++++++++++++++++------------------------- 1 file changed, 227 insertions(+), 240 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 29fcfb2b..4339ec0d 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1214,6 +1214,7 @@ mod test { // fn e(x: u8) -> (Blob<10>, Vec) { // (b(&[x]), vec![]) // } + // btree_test!(test_, ); // TODO: remove obsolete code. /// A helper method to succinctly create a blob. @@ -2151,244 +2152,250 @@ mod test { } btree_test!(test_contains_key, contains_key); - // #[test] - // fn range_empty() { - // run_btree_test(|btree| { - // // Test prefixes that don't exist in the map. - // assert_eq!( - // btree - // .range(b(&[0])..) - // .collect::, Blob<10>)>>(), - // vec![] - // ); - // assert_eq!(btree.range(b(&[1, 2, 3, 4])..).collect::>(), vec![]); - // }); - // } + fn range_empty() { + let key = |i| K::make(i); + run_btree_test(|btree| { + // Test prefixes that don't exist in the map. + assert_eq!(btree.range(key(0)..).collect::>(), vec![]); + assert_eq!(btree.range(key(10)..).collect::>(), vec![]); + assert_eq!(btree.range(key(100)..).collect::>(), vec![]); + }); + } + btree_test!(test_range_empty, range_empty); - // // Tests the case where the prefix is larger than all the entries in a leaf node. - // #[test] - // fn range_leaf_prefix_greater_than_all_entries() { - // run_btree_test(|mut btree| { - // btree.insert(b(&[0]), b(&[])); + // Tests the case where the prefix is larger than all the entries in a leaf node. + fn range_leaf_prefix_greater_than_all_entries() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + btree.insert(key(0), value(0)); - // // Test a prefix that's larger than the value in the leaf node. Should be empty. - // assert_eq!(btree.range(b(&[1])..).collect::>(), vec![]); - // }); - // } + // Test a prefix that's larger than the value in the leaf node. Should be empty. + assert_eq!(btree.range(key(1)..).collect::>(), vec![]); + }); + } + btree_test!( + test_range_leaf_prefix_greater_than_all_entries, + range_leaf_prefix_greater_than_all_entries + ); - // // Tests the case where the prefix is larger than all the entries in an internal node. - // #[test] - // fn range_internal_prefix_greater_than_all_entries() { - // run_btree_test(|mut btree| { - // for i in 1..=12 { - // assert_eq!(btree.insert(b(&[i]), b(&[])), None); - // } + // Tests the case where the prefix is larger than all the entries in an internal node. + fn range_internal_prefix_greater_than_all_entries() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + for i in 1..=12 { + assert_eq!(btree.insert(key(i), value(i)), None); + } - // // The result should look like this: - // // [6] - // // / \ - // // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] + // The result should look like this: + // [6] + // / \ + // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] - // // Test a prefix that's larger than the key in the internal node. - // assert_eq!( - // btree.range(b(&[7])..b(&[8])).collect::>(), - // vec![(b(&[7]), b(&[]))] - // ); - // }); - // } - // btree_test!(test_, ); + // Test a prefix that's larger than the key in the internal node. + assert_eq!( + btree.range(key(7)..key(8)).collect::>(), + vec![(key(7), value(7))] + ); + }); + } + btree_test!( + test_range_internal_prefix_greater_than_all_entries, + range_internal_prefix_greater_than_all_entries + ); - // #[test] - // fn range_various_prefixes() { - // run_btree_test(|mut btree| { - // btree.insert(b(&[0, 1]), b(&[])); - // btree.insert(b(&[0, 2]), b(&[])); - // btree.insert(b(&[0, 3]), b(&[])); - // btree.insert(b(&[0, 4]), b(&[])); - // btree.insert(b(&[1, 1]), b(&[])); - // btree.insert(b(&[1, 2]), b(&[])); - // btree.insert(b(&[1, 3]), b(&[])); - // btree.insert(b(&[1, 4]), b(&[])); - // btree.insert(b(&[2, 1]), b(&[])); - // btree.insert(b(&[2, 2]), b(&[])); - // btree.insert(b(&[2, 3]), b(&[])); - // btree.insert(b(&[2, 4]), b(&[])); + fn range_various_prefixes() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + btree.insert(key(1), value(100)); + btree.insert(key(2), value(200)); + btree.insert(key(3), value(300)); + btree.insert(key(4), value(400)); + btree.insert(key(11), value(500)); + btree.insert(key(12), value(600)); + btree.insert(key(13), value(700)); + btree.insert(key(14), value(800)); + btree.insert(key(21), value(900)); + btree.insert(key(22), value(1_000)); + btree.insert(key(23), value(1_100)); + btree.insert(key(24), value(1_200)); - // // The result should look like this: - // // [(1, 2)] - // // / \ - // // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 1)] [(1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4)] + // The result should look like this: + // [12] + // / \ + // [1, 2, 3, 4, 11] [13, 14, 21, 22, 23, 24] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![(b(&[1, 2]), vec![])]); - // assert_eq!(root.children_len(), 2); + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!( + root.entries(btree.memory()), + vec![(key(12), encode(value(600)))] + ); + assert_eq!(root.children_len(), 2); - // // Tests a prefix that's smaller than the key in the internal node. - // assert_eq!( - // btree.range(b(&[0])..b(&[1])).collect::>(), - // vec![ - // (b(&[0, 1]), b(&[])), - // (b(&[0, 2]), b(&[])), - // (b(&[0, 3]), b(&[])), - // (b(&[0, 4]), b(&[])), - // ] - // ); + // Tests a prefix that's smaller than the key in the internal node. + assert_eq!( + btree.range(key(0)..key(11)).collect::>(), + vec![ + (key(1), value(100)), + (key(2), value(200)), + (key(3), value(300)), + (key(4), value(400)), + ] + ); - // // Tests a prefix that crosses several nodes. - // assert_eq!( - // btree.range(b(&[1])..b(&[2])).collect::>(), - // vec![ - // (b(&[1, 1]), b(&[])), - // (b(&[1, 2]), b(&[])), - // (b(&[1, 3]), b(&[])), - // (b(&[1, 4]), b(&[])), - // ] - // ); + // Tests a prefix that crosses several nodes. + assert_eq!( + btree.range(key(10)..key(20)).collect::>(), + vec![ + (key(11), value(500)), + (key(12), value(600)), + (key(13), value(700)), + (key(14), value(800)), + ] + ); - // // Tests a prefix that's larger than the key in the internal node. - // assert_eq!( - // btree.range(b(&[2])..b(&[3])).collect::>(), - // vec![ - // (b(&[2, 1]), b(&[])), - // (b(&[2, 2]), b(&[])), - // (b(&[2, 3]), b(&[])), - // (b(&[2, 4]), b(&[])), - // ] - // ); - // }); - // } - // btree_test!(test_, ); + // Tests a prefix that's larger than the key in the internal node. + assert_eq!( + btree.range(key(20)..key(30)).collect::>(), + vec![ + (key(21), value(900)), + (key(22), value(1_000)), + (key(23), value(1_100)), + (key(24), value(1_200)), + ] + ); + }); + } + btree_test!(test_range_various_prefixes, range_various_prefixes); - // #[test] - // fn range_various_prefixes_2() { - // run_btree_test(|mut btree| { - // btree.insert(b(&[0, 1]), b(&[])); - // btree.insert(b(&[0, 2]), b(&[])); - // btree.insert(b(&[0, 3]), b(&[])); - // btree.insert(b(&[0, 4]), b(&[])); - // btree.insert(b(&[1, 2]), b(&[])); - // btree.insert(b(&[1, 4]), b(&[])); - // btree.insert(b(&[1, 6]), b(&[])); - // btree.insert(b(&[1, 8]), b(&[])); - // btree.insert(b(&[1, 10]), b(&[])); - // btree.insert(b(&[2, 1]), b(&[])); - // btree.insert(b(&[2, 2]), b(&[])); - // btree.insert(b(&[2, 3]), b(&[])); - // btree.insert(b(&[2, 4]), b(&[])); - // btree.insert(b(&[2, 5]), b(&[])); - // btree.insert(b(&[2, 6]), b(&[])); - // btree.insert(b(&[2, 7]), b(&[])); - // btree.insert(b(&[2, 8]), b(&[])); - // btree.insert(b(&[2, 9]), b(&[])); + fn range_various_prefixes_2() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + btree.insert(key(1), value(100)); + btree.insert(key(2), value(200)); + btree.insert(key(3), value(300)); + btree.insert(key(4), value(400)); + btree.insert(key(12), value(500)); + btree.insert(key(14), value(600)); + btree.insert(key(16), value(700)); + btree.insert(key(18), value(800)); + btree.insert(key(19), value(900)); + btree.insert(key(21), value(1000)); + btree.insert(key(22), value(1100)); + btree.insert(key(23), value(1200)); + btree.insert(key(24), value(1300)); + btree.insert(key(25), value(1400)); + btree.insert(key(26), value(1500)); + btree.insert(key(27), value(1600)); + btree.insert(key(28), value(1700)); + btree.insert(key(29), value(1800)); - // // The result should look like this: - // // [(1, 4), (2, 3)] - // // / | \ - // // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2)] | [(2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9)] - // // | - // // [(1, 6), (1, 8), (1, 10), (2, 1), (2, 2)] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!( - // root.entries(btree.memory()), - // vec![(b(&[1, 4]), vec![]), (b(&[2, 3]), vec![])] - // ); - // assert_eq!(root.children_len(), 3); - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![ - // (b(&[0, 1]), vec![]), - // (b(&[0, 2]), vec![]), - // (b(&[0, 3]), vec![]), - // (b(&[0, 4]), vec![]), - // (b(&[1, 2]), vec![]), - // ] - // ); + // The result should look like this: + // [14, 23] + // / | \ + // [1, 2, 3, 4, 12] | [24, 25, 26, 27, 28, 29] + // | + // [16, 18, 19, 21, 22] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!( + root.entries(btree.memory()), + vec![ + (key(14), encode(value(600))), + (key(23), encode(value(1200))) + ] + ); + assert_eq!(root.children_len(), 3); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![ + (key(1), encode(value(100))), + (key(2), encode(value(200))), + (key(3), encode(value(300))), + (key(4), encode(value(400))), + (key(12), encode(value(500))), + ] + ); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![ - // (b(&[1, 6]), vec![]), - // (b(&[1, 8]), vec![]), - // (b(&[1, 10]), vec![]), - // (b(&[2, 1]), vec![]), - // (b(&[2, 2]), vec![]), - // ] - // ); + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![ + (key(16), encode(value(700))), + (key(18), encode(value(800))), + (key(19), encode(value(900))), + (key(21), encode(value(1000))), + (key(22), encode(value(1100))), + ] + ); - // let child_2 = btree.load_node(root.child(2)); - // assert_eq!( - // child_2.entries(btree.memory()), - // vec![ - // (b(&[2, 4]), vec![]), - // (b(&[2, 5]), vec![]), - // (b(&[2, 6]), vec![]), - // (b(&[2, 7]), vec![]), - // (b(&[2, 8]), vec![]), - // (b(&[2, 9]), vec![]), - // ] - // ); + let child_2 = btree.load_node(root.child(2)); + assert_eq!( + child_2.entries(btree.memory()), + vec![ + (key(24), encode(value(1300))), + (key(25), encode(value(1400))), + (key(26), encode(value(1500))), + (key(27), encode(value(1600))), + (key(28), encode(value(1700))), + (key(29), encode(value(1800))), + ] + ); - // // Tests a prefix that doesn't exist, but is in the middle of the root node. - // assert_eq!( - // btree.range(b(&[1, 5])..b(&[1, 6])).collect::>(), - // vec![] - // ); + // Tests a prefix that doesn't exist, but is in the middle of the root node. + assert_eq!(btree.range(key(15)..key(16)).collect::>(), vec![]); - // // Tests a prefix beginning in the middle of the tree and crossing several nodes. - // assert_eq!( - // btree.range(b(&[1, 5])..=b(&[2, 6])).collect::>(), - // vec![ - // (b(&[1, 6]), b(&[])), - // (b(&[1, 8]), b(&[])), - // (b(&[1, 10]), b(&[])), - // (b(&[2, 1]), b(&[])), - // (b(&[2, 2]), b(&[])), - // (b(&[2, 3]), b(&[])), - // (b(&[2, 4]), b(&[])), - // (b(&[2, 5]), b(&[])), - // (b(&[2, 6]), b(&[])), - // ] - // ); + // Tests a prefix beginning in the middle of the tree and crossing several nodes. + assert_eq!( + btree.range(key(15)..=key(26)).collect::>(), + vec![ + (key(16), value(700)), + (key(18), value(800)), + (key(19), value(900)), + (key(21), value(1000)), + (key(22), value(1100)), + (key(23), value(1200)), + (key(24), value(1300)), + (key(25), value(1400)), + (key(26), value(1500)), + ] + ); - // // Tests a prefix that crosses several nodes. - // assert_eq!( - // btree.range(b(&[1])..b(&[2])).collect::>(), - // vec![ - // (b(&[1, 2]), b(&[])), - // (b(&[1, 4]), b(&[])), - // (b(&[1, 6]), b(&[])), - // (b(&[1, 8]), b(&[])), - // (b(&[1, 10]), b(&[])), - // ] - // ); + // Tests a prefix that crosses several nodes. + assert_eq!( + btree.range(key(10)..key(20)).collect::>(), + vec![ + (key(12), value(500)), + (key(14), value(600)), + (key(16), value(700)), + (key(18), value(800)), + (key(19), value(900)), + ] + ); - // // Tests a prefix that starts from a leaf node, then iterates through the root and right - // // sibling. - // assert_eq!( - // btree.range(b(&[2])..).collect::>(), - // vec![ - // (b(&[2, 1]), b(&[])), - // (b(&[2, 2]), b(&[])), - // (b(&[2, 3]), b(&[])), - // (b(&[2, 4]), b(&[])), - // (b(&[2, 5]), b(&[])), - // (b(&[2, 6]), b(&[])), - // (b(&[2, 7]), b(&[])), - // (b(&[2, 8]), b(&[])), - // (b(&[2, 9]), b(&[])), - // ] - // ); - // }); - // } - // btree_test!(test_, ); + // Tests a prefix that starts from a leaf node, then iterates through the root and right + // sibling. + assert_eq!( + btree.range(key(20)..key(30)).collect::>(), + vec![ + (key(21), value(1000)), + (key(22), value(1100)), + (key(23), value(1200)), + (key(24), value(1300)), + (key(25), value(1400)), + (key(26), value(1500)), + (key(27), value(1600)), + (key(28), value(1700)), + (key(29), value(1800)), + ] + ); + }); + } + btree_test!(test_range_various_prefixes_2, range_various_prefixes_2); - // #[test] // fn range_large() { // run_btree_test(|mut btree| { // // Insert 1000 elements with prefix 0 and another 1000 elements with prefix 1. @@ -2430,7 +2437,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn range_various_prefixes_with_offset() { // run_btree_test(|mut btree| { // btree.insert(b(&[0, 1]), b(&[])); @@ -2478,7 +2484,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn range_various_prefixes_with_offset_2() { // run_btree_test(|mut btree| { // btree.insert(b(&[0, 1]), b(&[])); @@ -2583,7 +2588,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // #[should_panic(expected = "max_key_size must be <= 4")] // fn v1_rejects_increases_in_max_key_size() { // let mem = make_memory(); @@ -2592,7 +2596,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn v2_handles_increases_in_max_key_size_and_max_value_size() { // let mem = make_memory(); // let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::init(mem); @@ -2621,7 +2624,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn accepts_small_or_equal_key_sizes() { // let mem = make_memory(); // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); @@ -2632,7 +2634,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // #[should_panic(expected = "max_value_size must be <= 3")] // fn v1_rejects_larger_value_sizes() { // let mem = make_memory(); @@ -2641,7 +2642,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn accepts_small_or_equal_value_sizes() { // let mem = make_memory(); // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); @@ -2652,7 +2652,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn bruteforce_range_search() { // run_btree_test(|mut stable_map| { // use std::collections::BTreeMap; @@ -2714,7 +2713,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn test_iter_upper_bound() { // run_btree_test(|mut btree| { // for k in 0..100u64 { @@ -2735,6 +2733,7 @@ mod test { // } // }); // } + // btree_test!(test_, ); // // A buggy implementation of storable where the max_size is smaller than the serialized size. // #[derive(Clone, Ord, PartialOrd, Eq, PartialEq)] @@ -2755,7 +2754,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] // fn v1_panics_if_key_is_bigger_than_max_size() { // let mut btree = BTreeMap::init_v1(make_memory()); @@ -2763,7 +2761,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] // fn v2_panics_if_key_is_bigger_than_max_size() { // let mut btree = BTreeMap::init(make_memory()); @@ -2771,7 +2768,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] // fn v1_panics_if_value_is_bigger_than_max_size() { // let mut btree = BTreeMap::init(make_memory()); @@ -2779,16 +2775,15 @@ mod test { // } // btree_test!(test_, ); - // #[test] // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] // fn v2_panics_if_value_is_bigger_than_max_size() { // let mut btree = BTreeMap::init(make_memory()); // btree.insert((), BuggyStruct); // } + // btree_test!(test_, ); // // To generate the memory dump file for the current version: // // cargo test create_btreemap_dump_file -- --include-ignored - // #[test] // #[ignore] // fn create_btreemap_dump_file() { // let mem = make_memory(); @@ -2803,7 +2798,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn produces_layout_identical_to_layout_version_1_with_packed_headers() { // let mem = make_memory(); // let mut btree = BTreeMap::init_v1(mem.clone()); @@ -2815,7 +2809,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn read_write_header_is_identical_to_read_write_struct() { // #[repr(C, packed)] // struct BTreePackedHeader { @@ -2874,7 +2867,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn migrate_from_bounded_to_unbounded_and_back() { // // A type that is bounded. // #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] @@ -2930,7 +2922,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn test_clear_new_bounded_type() { // let mem = make_memory(); // let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::new(mem.clone()); @@ -2956,7 +2947,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn test_clear_new_unbounded_type() { // let mem = make_memory(); // let mut btree: BTreeMap = BTreeMap::new(mem.clone()); @@ -2978,7 +2968,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn deallocating_node_with_overflows() { // let mem = make_memory(); // let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); @@ -2999,7 +2988,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn repeatedly_deallocating_nodes_with_overflows() { // let mem = make_memory(); // let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); @@ -3022,7 +3010,6 @@ mod test { // } // btree_test!(test_, ); - // #[test] // fn deallocating_root_does_not_leak_memory() { // let mem = make_memory(); // let mut btree: BTreeMap, _, _> = BTreeMap::new(mem.clone()); From 078707a6c64f9bb181c8efdadcce558c7516b3ea Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 20:31:11 +0200 Subject: [PATCH 34/66] . --- src/btreemap.rs | 64 +++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 4339ec0d..9db8e5db 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2396,46 +2396,32 @@ mod test { } btree_test!(test_range_various_prefixes_2, range_various_prefixes_2); - // fn range_large() { - // run_btree_test(|mut btree| { - // // Insert 1000 elements with prefix 0 and another 1000 elements with prefix 1. - // for prefix in 0..=1 { - // for i in 0..1000u32 { - // assert_eq!( - // btree.insert( - // // The key is the prefix followed by the integer's encoding. - // // The encoding is big-endian so that the byte representation of the - // // integers are sorted. - // b([vec![prefix], i.to_be_bytes().to_vec()] - // .into_iter() - // .flatten() - // .collect::>() - // .as_slice()), - // b(&[]) - // ), - // None - // ); - // } - // } + fn range_large() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + let n = 2_000; + let m = n / 2; - // // Getting the range with a prefix should return all 1000 elements with that prefix. - // for prefix in 0..=1 { - // let mut i: u32 = 0; - // for (key, _) in btree.range(b(&[prefix])..b(&[prefix + 1])) { - // assert_eq!( - // key, - // b(&[vec![prefix], i.to_be_bytes().to_vec()] - // .into_iter() - // .flatten() - // .collect::>()) - // ); - // i += 1; - // } - // assert_eq!(i, 1000); - // } - // }); - // } - // btree_test!(test_, ); + for i in 0..n { + assert_eq!(btree.insert(key(i), value(i)), None); + } + + // Inspect the first half. + let keys: Vec<_> = btree.range(key(0)..key(m)).collect(); + assert_eq!(keys.len(), m as usize); + for (i, (k, _)) in keys.into_iter().enumerate() { + assert_eq!(k, key(i as u32)); + } + + // Inspect the second half. + let keys: Vec<_> = btree.range(key(m)..).collect(); + assert_eq!(keys.len(), (n - m) as usize); + for (i, (k, _)) in keys.into_iter().enumerate() { + assert_eq!(k, key(m + i as u32)); + } + }); + } + btree_test!(test_range_large, range_large); // fn range_various_prefixes_with_offset() { // run_btree_test(|mut btree| { From 8a77ef3f211eeba2b302ada93c81affa7178ccbc Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 20:34:29 +0200 Subject: [PATCH 35/66] . --- src/btreemap.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 9db8e5db..57e3c44f 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2399,25 +2399,29 @@ mod test { fn range_large() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - let n = 2_000; - let m = n / 2; + const TOTAL: u32 = 2_000; + const MID: u32 = TOTAL / 2; - for i in 0..n { + for i in 0..TOTAL { assert_eq!(btree.insert(key(i), value(i)), None); } - // Inspect the first half. - let keys: Vec<_> = btree.range(key(0)..key(m)).collect(); - assert_eq!(keys.len(), m as usize); - for (i, (k, _)) in keys.into_iter().enumerate() { - assert_eq!(k, key(i as u32)); + // Check range [0, MID): should yield exactly the first MID entries. + let keys: Vec<_> = btree.range(key(0)..key(MID)).collect(); + assert_eq!(keys.len(), MID as usize); + for (i, (k, v)) in keys.into_iter().enumerate() { + let j = i as u32; + assert_eq!(k, key(j)); + assert_eq!(v, value(j)); } - // Inspect the second half. - let keys: Vec<_> = btree.range(key(m)..).collect(); - assert_eq!(keys.len(), (n - m) as usize); - for (i, (k, _)) in keys.into_iter().enumerate() { - assert_eq!(k, key(m + i as u32)); + // Check range [MID, TOTAL): should yield the remaining entries. + let keys: Vec<_> = btree.range(key(MID)..).collect(); + assert_eq!(keys.len(), (TOTAL - MID) as usize); + for (i, (k, v)) in keys.into_iter().enumerate() { + let j = MID + i as u32; + assert_eq!(k, key(j)); + assert_eq!(v, value(j)); } }); } From eaadc458d525712acbb57ff7d00cbb2fbadaeb0d Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 20:41:32 +0200 Subject: [PATCH 36/66] . --- src/btreemap.rs | 131 +++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 62 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 57e3c44f..9a7ee60d 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2427,54 +2427,61 @@ mod test { } btree_test!(test_range_large, range_large); - // fn range_various_prefixes_with_offset() { - // run_btree_test(|mut btree| { - // btree.insert(b(&[0, 1]), b(&[])); - // btree.insert(b(&[0, 2]), b(&[])); - // btree.insert(b(&[0, 3]), b(&[])); - // btree.insert(b(&[0, 4]), b(&[])); - // btree.insert(b(&[1, 1]), b(&[])); - // btree.insert(b(&[1, 2]), b(&[])); - // btree.insert(b(&[1, 3]), b(&[])); - // btree.insert(b(&[1, 4]), b(&[])); - // btree.insert(b(&[2, 1]), b(&[])); - // btree.insert(b(&[2, 2]), b(&[])); - // btree.insert(b(&[2, 3]), b(&[])); - // btree.insert(b(&[2, 4]), b(&[])); + fn range_various_prefixes_with_offset() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + btree.insert(key(1), value(100)); + btree.insert(key(2), value(200)); + btree.insert(key(3), value(300)); + btree.insert(key(4), value(400)); + btree.insert(key(11), value(500)); + btree.insert(key(12), value(600)); + btree.insert(key(13), value(700)); + btree.insert(key(14), value(800)); + btree.insert(key(21), value(900)); + btree.insert(key(22), value(1000)); + btree.insert(key(23), value(1100)); + btree.insert(key(24), value(1200)); - // // The result should look like this: - // // [(1, 2)] - // // / \ - // // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 1)] [(1, 3), (1, 4), (2, 1), (2, 2), (2, 3), (2, 4)] + // The result should look like this: + // [12] + // / \ + // [1, 2, 3, 4, 11] [13, 14, 21, 22, 23, 24] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.entries(btree.memory()), vec![(b(&[1, 2]), vec![])]); - // assert_eq!(root.children_len(), 2); + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!( + root.entries(btree.memory()), + vec![(key(12), encode(value(600)))] + ); + assert_eq!(root.children_len(), 2); - // assert_eq!( - // btree.range(b(&[0])..b(&[1])).collect::>(), - // vec![ - // (b(&[0, 1]), b(&[])), - // (b(&[0, 2]), b(&[])), - // (b(&[0, 3]), b(&[])), - // (b(&[0, 4]), b(&[])), - // ] - // ); + assert_eq!( + btree.range(key(0)..key(10)).collect::>(), + vec![ + (key(1), value(100)), + (key(2), value(200)), + (key(3), value(300)), + (key(4), value(400)), + ] + ); - // // Tests an offset that has a keys somewhere in the range of keys of an internal node. - // assert_eq!( - // btree.range(b(&[1, 3])..b(&[2])).collect::>(), - // vec![(b(&[1, 3]), b(&[])), (b(&[1, 4]), b(&[])),] - // ); + // Tests an offset that has a keys somewhere in the range of keys of an internal node. + assert_eq!( + btree.range(key(13)..key(20)).collect::>(), + vec![(key(13), value(700)), (key(14), value(800))] + ); - // // Tests an offset that's larger than the key in the internal node. - // assert_eq!(btree.range(b(&[2, 5])..).collect::>(), vec![]); - // }); - // } - // btree_test!(test_, ); + // Tests an offset that's larger than the key in the internal node. + assert_eq!(btree.range(key(25)..).collect::>(), vec![]); + }); + } + btree_test!( + test_range_various_prefixes_with_offset, + range_various_prefixes_with_offset + ); - // fn range_various_prefixes_with_offset_2() { + // fn range_various_prefixes_with_offset_2() { // run_btree_test(|mut btree| { // btree.insert(b(&[0, 1]), b(&[])); // btree.insert(b(&[0, 2]), b(&[])); @@ -2579,14 +2586,14 @@ mod test { // btree_test!(test_, ); // #[should_panic(expected = "max_key_size must be <= 4")] - // fn v1_rejects_increases_in_max_key_size() { + // fn v1_rejects_increases_in_max_key_size() { // let mem = make_memory(); // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(btree.into_memory()); // } // btree_test!(test_, ); - // fn v2_handles_increases_in_max_key_size_and_max_value_size() { + // fn v2_handles_increases_in_max_key_size_and_max_value_size() { // let mem = make_memory(); // let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::init(mem); // btree.insert( @@ -2614,7 +2621,7 @@ mod test { // } // btree_test!(test_, ); - // fn accepts_small_or_equal_key_sizes() { + // fn accepts_small_or_equal_key_sizes() { // let mem = make_memory(); // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); // // Smaller key size @@ -2625,14 +2632,14 @@ mod test { // btree_test!(test_, ); // #[should_panic(expected = "max_value_size must be <= 3")] - // fn v1_rejects_larger_value_sizes() { + // fn v1_rejects_larger_value_sizes() { // let mem = make_memory(); // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); // let _btree: BTreeMap, Blob<4>, _> = BTreeMap::init_v1(btree.into_memory()); // } // btree_test!(test_, ); - // fn accepts_small_or_equal_value_sizes() { + // fn accepts_small_or_equal_value_sizes() { // let mem = make_memory(); // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); // // Smaller key size @@ -2642,7 +2649,7 @@ mod test { // } // btree_test!(test_, ); - // fn bruteforce_range_search() { + // fn bruteforce_range_search() { // run_btree_test(|mut stable_map| { // use std::collections::BTreeMap; // const NKEYS: u64 = 60; @@ -2703,7 +2710,7 @@ mod test { // } // btree_test!(test_, ); - // fn test_iter_upper_bound() { + // fn test_iter_upper_bound() { // run_btree_test(|mut btree| { // for k in 0..100u64 { // btree.insert(k, ()); @@ -2745,28 +2752,28 @@ mod test { // btree_test!(test_, ); // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - // fn v1_panics_if_key_is_bigger_than_max_size() { + // fn v1_panics_if_key_is_bigger_than_max_size() { // let mut btree = BTreeMap::init_v1(make_memory()); // btree.insert(BuggyStruct, ()); // } // btree_test!(test_, ); // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - // fn v2_panics_if_key_is_bigger_than_max_size() { + // fn v2_panics_if_key_is_bigger_than_max_size() { // let mut btree = BTreeMap::init(make_memory()); // btree.insert(BuggyStruct, ()); // } // btree_test!(test_, ); // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - // fn v1_panics_if_value_is_bigger_than_max_size() { + // fn v1_panics_if_value_is_bigger_than_max_size() { // let mut btree = BTreeMap::init(make_memory()); // btree.insert((), BuggyStruct); // } // btree_test!(test_, ); // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - // fn v2_panics_if_value_is_bigger_than_max_size() { + // fn v2_panics_if_value_is_bigger_than_max_size() { // let mut btree = BTreeMap::init(make_memory()); // btree.insert((), BuggyStruct); // } @@ -2775,7 +2782,7 @@ mod test { // // To generate the memory dump file for the current version: // // cargo test create_btreemap_dump_file -- --include-ignored // #[ignore] - // fn create_btreemap_dump_file() { + // fn create_btreemap_dump_file() { // let mem = make_memory(); // let mut btree = BTreeMap::init_v1(mem.clone()); // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); @@ -2788,7 +2795,7 @@ mod test { // } // btree_test!(test_, ); - // fn produces_layout_identical_to_layout_version_1_with_packed_headers() { + // fn produces_layout_identical_to_layout_version_1_with_packed_headers() { // let mem = make_memory(); // let mut btree = BTreeMap::init_v1(mem.clone()); // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); @@ -2799,7 +2806,7 @@ mod test { // } // btree_test!(test_, ); - // fn read_write_header_is_identical_to_read_write_struct() { + // fn read_write_header_is_identical_to_read_write_struct() { // #[repr(C, packed)] // struct BTreePackedHeader { // magic: [u8; 3], @@ -2857,7 +2864,7 @@ mod test { // } // btree_test!(test_, ); - // fn migrate_from_bounded_to_unbounded_and_back() { + // fn migrate_from_bounded_to_unbounded_and_back() { // // A type that is bounded. // #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] // struct T; @@ -2912,7 +2919,7 @@ mod test { // } // btree_test!(test_, ); - // fn test_clear_new_bounded_type() { + // fn test_clear_new_bounded_type() { // let mem = make_memory(); // let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::new(mem.clone()); @@ -2937,7 +2944,7 @@ mod test { // } // btree_test!(test_, ); - // fn test_clear_new_unbounded_type() { + // fn test_clear_new_unbounded_type() { // let mem = make_memory(); // let mut btree: BTreeMap = BTreeMap::new(mem.clone()); // btree.insert("asd".into(), "bce".into()); @@ -2958,7 +2965,7 @@ mod test { // } // btree_test!(test_, ); - // fn deallocating_node_with_overflows() { + // fn deallocating_node_with_overflows() { // let mem = make_memory(); // let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); @@ -2978,7 +2985,7 @@ mod test { // } // btree_test!(test_, ); - // fn repeatedly_deallocating_nodes_with_overflows() { + // fn repeatedly_deallocating_nodes_with_overflows() { // let mem = make_memory(); // let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); @@ -3000,7 +3007,7 @@ mod test { // } // btree_test!(test_, ); - // fn deallocating_root_does_not_leak_memory() { + // fn deallocating_root_does_not_leak_memory() { // let mem = make_memory(); // let mut btree: BTreeMap, _, _> = BTreeMap::new(mem.clone()); From 8a1d9e9e19c4e4aec4aff133124081ffa93a4819 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 20:47:03 +0200 Subject: [PATCH 37/66] . --- src/btreemap.rs | 208 ++++++++++++++++++++++++------------------------ 1 file changed, 106 insertions(+), 102 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 9a7ee60d..3992fb9d 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2291,10 +2291,10 @@ mod test { btree.insert(key(29), value(1800)); // The result should look like this: - // [14, 23] - // / | \ - // [1, 2, 3, 4, 12] | [24, 25, 26, 27, 28, 29] - // | + // [14, 23] + // / | \ + // [1, 2, 3, 4, 12] | [24, 25, 26, 27, 28, 29] + // | // [16, 18, 19, 21, 22] let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Internal); @@ -2481,109 +2481,113 @@ mod test { range_various_prefixes_with_offset ); - // fn range_various_prefixes_with_offset_2() { - // run_btree_test(|mut btree| { - // btree.insert(b(&[0, 1]), b(&[])); - // btree.insert(b(&[0, 2]), b(&[])); - // btree.insert(b(&[0, 3]), b(&[])); - // btree.insert(b(&[0, 4]), b(&[])); - // btree.insert(b(&[1, 2]), b(&[])); - // btree.insert(b(&[1, 4]), b(&[])); - // btree.insert(b(&[1, 6]), b(&[])); - // btree.insert(b(&[1, 8]), b(&[])); - // btree.insert(b(&[1, 10]), b(&[])); - // btree.insert(b(&[2, 1]), b(&[])); - // btree.insert(b(&[2, 2]), b(&[])); - // btree.insert(b(&[2, 3]), b(&[])); - // btree.insert(b(&[2, 4]), b(&[])); - // btree.insert(b(&[2, 5]), b(&[])); - // btree.insert(b(&[2, 6]), b(&[])); - // btree.insert(b(&[2, 7]), b(&[])); - // btree.insert(b(&[2, 8]), b(&[])); - // btree.insert(b(&[2, 9]), b(&[])); - - // // The result should look like this: - // // [(1, 4), (2, 3)] - // // / | \ - // // [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2)] | [(2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9)] - // // | - // // [(1, 6), (1, 8), (1, 10), (2, 1), (2, 2)] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!( - // root.entries(btree.memory()), - // vec![(b(&[1, 4]), vec![]), (b(&[2, 3]), vec![])] - // ); - // assert_eq!(root.children_len(), 3); + fn range_various_prefixes_with_offset_2() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + btree.insert(key(01), value(0)); + btree.insert(key(02), value(0)); + btree.insert(key(03), value(0)); + btree.insert(key(04), value(0)); + btree.insert(key(12), value(0)); + btree.insert(key(14), value(0)); + btree.insert(key(16), value(0)); + btree.insert(key(18), value(0)); + btree.insert(key(19), value(0)); + btree.insert(key(21), value(0)); + btree.insert(key(22), value(0)); + btree.insert(key(23), value(0)); + btree.insert(key(24), value(0)); + btree.insert(key(25), value(0)); + btree.insert(key(26), value(0)); + btree.insert(key(27), value(0)); + btree.insert(key(28), value(0)); + btree.insert(key(29), value(0)); - // let child_0 = btree.load_node(root.child(0)); - // assert_eq!(child_0.node_type(), NodeType::Leaf); - // assert_eq!( - // child_0.entries(btree.memory()), - // vec![ - // (b(&[0, 1]), vec![]), - // (b(&[0, 2]), vec![]), - // (b(&[0, 3]), vec![]), - // (b(&[0, 4]), vec![]), - // (b(&[1, 2]), vec![]), - // ] - // ); + // The result should look like this: + // [14, 23] + // / | \ + // [1, 2, 3, 4, 12] | [24, 25, 26, 27, 28, 29] + // | + // [16, 18, 19, 21, 22] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!( + root.entries(btree.memory()), + vec![(key(14), encode(value(0))), (key(23), encode(value(0)))] + ); + assert_eq!(root.children_len(), 3); - // let child_1 = btree.load_node(root.child(1)); - // assert_eq!(child_1.node_type(), NodeType::Leaf); - // assert_eq!( - // child_1.entries(btree.memory()), - // vec![ - // (b(&[1, 6]), vec![]), - // (b(&[1, 8]), vec![]), - // (b(&[1, 10]), vec![]), - // (b(&[2, 1]), vec![]), - // (b(&[2, 2]), vec![]), - // ] - // ); + let child_0 = btree.load_node(root.child(0)); + assert_eq!(child_0.node_type(), NodeType::Leaf); + assert_eq!( + child_0.entries(btree.memory()), + vec![ + (key(1), encode(value(0))), + (key(2), encode(value(0))), + (key(3), encode(value(0))), + (key(4), encode(value(0))), + (key(12), encode(value(0))), + ] + ); - // let child_2 = btree.load_node(root.child(2)); - // assert_eq!( - // child_2.entries(btree.memory()), - // vec![ - // (b(&[2, 4]), vec![]), - // (b(&[2, 5]), vec![]), - // (b(&[2, 6]), vec![]), - // (b(&[2, 7]), vec![]), - // (b(&[2, 8]), vec![]), - // (b(&[2, 9]), vec![]), - // ] - // ); + let child_1 = btree.load_node(root.child(1)); + assert_eq!(child_1.node_type(), NodeType::Leaf); + assert_eq!( + child_1.entries(btree.memory()), + vec![ + (key(16), encode(value(0))), + (key(18), encode(value(0))), + (key(19), encode(value(0))), + (key(21), encode(value(0))), + (key(22), encode(value(0))), + ] + ); - // // Tests a offset that crosses several nodes. - // assert_eq!( - // btree.range(b(&[1, 4])..b(&[2])).collect::>(), - // vec![ - // (b(&[1, 4]), b(&[])), - // (b(&[1, 6]), b(&[])), - // (b(&[1, 8]), b(&[])), - // (b(&[1, 10]), b(&[])), - // ] - // ); + let child_2 = btree.load_node(root.child(2)); + assert_eq!( + child_2.entries(btree.memory()), + vec![ + (key(24), encode(value(0))), + (key(25), encode(value(0))), + (key(26), encode(value(0))), + (key(27), encode(value(0))), + (key(28), encode(value(0))), + (key(29), encode(value(0))), + ] + ); - // // Tests a offset that starts from a leaf node, then iterates through the root and right - // // sibling. - // assert_eq!( - // btree.range(b(&[2, 2])..b(&[3])).collect::>(), - // vec![ - // (b(&[2, 2]), b(&[])), - // (b(&[2, 3]), b(&[])), - // (b(&[2, 4]), b(&[])), - // (b(&[2, 5]), b(&[])), - // (b(&[2, 6]), b(&[])), - // (b(&[2, 7]), b(&[])), - // (b(&[2, 8]), b(&[])), - // (b(&[2, 9]), b(&[])), - // ] - // ); - // }); - // } - // btree_test!(test_, ); + // Tests a offset that crosses several nodes. + assert_eq!( + btree.range(key(14)..key(20)).collect::>(), + vec![ + (key(14), value(0)), + (key(16), value(0)), + (key(18), value(0)), + (key(19), value(0)), + ] + ); + + // Tests a offset that starts from a leaf node, then iterates through the root and right + // sibling. + assert_eq!( + btree.range(key(22)..key(30)).collect::>(), + vec![ + (key(22), value(0)), + (key(23), value(0)), + (key(24), value(0)), + (key(25), value(0)), + (key(26), value(0)), + (key(27), value(0)), + (key(28), value(0)), + (key(29), value(0)), + ] + ); + }); + } + btree_test!( + test_range_various_prefixes_with_offset_2, + range_various_prefixes_with_offset_2 + ); // #[should_panic(expected = "max_key_size must be <= 4")] // fn v1_rejects_increases_in_max_key_size() { From 4f30efbba179f0cb9acb872be48ebe9799404d18 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 20:50:29 +0200 Subject: [PATCH 38/66] . --- src/btreemap.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 3992fb9d..f036904c 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2220,9 +2220,9 @@ mod test { btree.insert(key(24), value(1_200)); // The result should look like this: - // [12] - // / \ - // [1, 2, 3, 4, 11] [13, 14, 21, 22, 23, 24] + // [12] + // / \ + // [1, 2, 3, 4, 11] [13, 14, 21, 22, 23, 24] let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Internal); @@ -2291,11 +2291,11 @@ mod test { btree.insert(key(29), value(1800)); // The result should look like this: - // [14, 23] - // / | \ - // [1, 2, 3, 4, 12] | [24, 25, 26, 27, 28, 29] - // | - // [16, 18, 19, 21, 22] + // [14, 23] + // / | \ + // [1, 2, 3, 4, 12] | [24, 25, 26, 27, 28, 29] + // | + // [16, 18, 19, 21, 22] let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Internal); assert_eq!( @@ -2444,9 +2444,9 @@ mod test { btree.insert(key(24), value(1200)); // The result should look like this: - // [12] - // / \ - // [1, 2, 3, 4, 11] [13, 14, 21, 22, 23, 24] + // [12] + // / \ + // [1, 2, 3, 4, 11] [13, 14, 21, 22, 23, 24] let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Internal); @@ -2504,11 +2504,11 @@ mod test { btree.insert(key(29), value(0)); // The result should look like this: - // [14, 23] - // / | \ - // [1, 2, 3, 4, 12] | [24, 25, 26, 27, 28, 29] - // | - // [16, 18, 19, 21, 22] + // [14, 23] + // / | \ + // [1, 2, 3, 4, 12] | [24, 25, 26, 27, 28, 29] + // | + // [16, 18, 19, 21, 22] let root = btree.load_node(btree.root_addr); assert_eq!(root.node_type(), NodeType::Internal); assert_eq!( From 49249d964a9321e0bee3bbea1a869c1e09fdc64a Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:13:32 +0200 Subject: [PATCH 39/66] . --- src/btreemap.rs | 217 ++++++++++++++++++++++++------------------------ 1 file changed, 107 insertions(+), 110 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index f036904c..e5d08669 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2589,130 +2589,127 @@ mod test { range_various_prefixes_with_offset_2 ); - // #[should_panic(expected = "max_key_size must be <= 4")] - // fn v1_rejects_increases_in_max_key_size() { - // let mem = make_memory(); - // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); - // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(btree.into_memory()); - // } - // btree_test!(test_, ); + #[test] + #[should_panic(expected = "max_key_size must be <= 4")] + fn v1_rejects_increases_in_max_key_size() { + let mem = make_memory(); + let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); + let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(btree.into_memory()); + } - // fn v2_handles_increases_in_max_key_size_and_max_value_size() { - // let mem = make_memory(); - // let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::init(mem); - // btree.insert( - // [1u8; 4].as_slice().try_into().unwrap(), - // [1u8; 4].as_slice().try_into().unwrap(), - // ); + #[test] + fn v2_handles_increases_in_max_key_size_and_max_value_size() { + let mem = make_memory(); + let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::init(mem); + btree.insert( + [1u8; 4].as_slice().try_into().unwrap(), + [1u8; 4].as_slice().try_into().unwrap(), + ); - // // Reinitialize the BTree with larger keys and value sizes. - // let mut btree: BTreeMap, Blob<5>, _> = BTreeMap::init(btree.into_memory()); - // btree.insert( - // [2u8; 5].as_slice().try_into().unwrap(), - // [2u8; 5].as_slice().try_into().unwrap(), - // ); + // Reinitialize the BTree with larger keys and value sizes. + let mut btree: BTreeMap, Blob<5>, _> = BTreeMap::init(btree.into_memory()); + btree.insert( + [2u8; 5].as_slice().try_into().unwrap(), + [2u8; 5].as_slice().try_into().unwrap(), + ); - // // Still able to retrieve all the entries inserted. - // assert_eq!( - // btree.get(&([1u8; 4].as_slice().try_into().unwrap())), - // Some([1u8; 4].as_slice().try_into().unwrap()) - // ); + // Still able to retrieve all the entries inserted. + assert_eq!( + btree.get(&([1u8; 4].as_slice().try_into().unwrap())), + Some([1u8; 4].as_slice().try_into().unwrap()) + ); - // assert_eq!( - // btree.get(&([2u8; 5].as_slice().try_into().unwrap())), - // Some([2u8; 5].as_slice().try_into().unwrap()) - // ); - // } - // btree_test!(test_, ); + assert_eq!( + btree.get(&([2u8; 5].as_slice().try_into().unwrap())), + Some([2u8; 5].as_slice().try_into().unwrap()) + ); + } - // fn accepts_small_or_equal_key_sizes() { - // let mem = make_memory(); - // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); - // // Smaller key size - // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); - // // Equal key size - // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); - // } - // btree_test!(test_, ); + #[test] + fn accepts_small_or_equal_key_sizes() { + let mem = make_memory(); + let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); + // Smaller key size + let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); + // Equal key size + let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); + } - // #[should_panic(expected = "max_value_size must be <= 3")] - // fn v1_rejects_larger_value_sizes() { - // let mem = make_memory(); - // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); - // let _btree: BTreeMap, Blob<4>, _> = BTreeMap::init_v1(btree.into_memory()); - // } - // btree_test!(test_, ); + #[test] + #[should_panic(expected = "max_value_size must be <= 3")] + fn v1_rejects_larger_value_sizes() { + let mem = make_memory(); + let btree: BTreeMap, Blob<3>, _> = BTreeMap::init_v1(mem); + let _btree: BTreeMap, Blob<4>, _> = BTreeMap::init_v1(btree.into_memory()); + } - // fn accepts_small_or_equal_value_sizes() { - // let mem = make_memory(); - // let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); - // // Smaller key size - // let btree: BTreeMap, Blob<2>, _> = BTreeMap::init(btree.into_memory()); - // // Equal key size - // let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); - // } - // btree_test!(test_, ); + #[test] + fn accepts_small_or_equal_value_sizes() { + let mem = make_memory(); + let btree: BTreeMap, Blob<3>, _> = BTreeMap::init(mem); + // Smaller key size + let btree: BTreeMap, Blob<2>, _> = BTreeMap::init(btree.into_memory()); + // Equal key size + let _btree: BTreeMap, Blob<3>, _> = BTreeMap::init(btree.into_memory()); + } - // fn bruteforce_range_search() { - // run_btree_test(|mut stable_map| { - // use std::collections::BTreeMap; - // const NKEYS: u64 = 60; - // let mut std_map = BTreeMap::new(); + fn bruteforce_range_search() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); - // for k in 0..NKEYS { - // std_map.insert(k, k); - // stable_map.insert(k, k); - // } + fn collect_kv<'a, K: Clone + 'a, V: Clone + 'a>( + iter: impl Iterator, + ) -> Vec<(K, V)> { + iter.map(|(k, v)| (k.clone(), v.clone())).collect() + } - // assert_eq!( - // std_map.range(..).map(|(k, v)| (*k, *v)).collect::>(), - // stable_map.range(..).collect::>() - // ); + fn collect(it: impl Iterator) -> Vec<(K, V)> { + it.collect() + } - // for l in 0..=NKEYS { - // assert_eq!( - // std_map - // .range(l..) - // .map(|(k, v)| (*k, *v)) - // .collect::>(), - // stable_map.range(l..).collect::>() - // ); + run_btree_test(|mut stable_map| { + use std::collections::BTreeMap; + const NKEYS: u32 = 60; + let mut std_map = BTreeMap::new(); - // assert_eq!( - // std_map - // .range(..l) - // .map(|(k, v)| (*k, *v)) - // .collect::>(), - // stable_map.range(..l).collect::>() - // ); + for i in 0..NKEYS { + std_map.insert(key(i), value(i)); + stable_map.insert(key(i), value(i)); + } - // assert_eq!( - // std_map - // .range(..=l) - // .map(|(k, v)| (*k, *v)) - // .collect::>(), - // stable_map.range(..=l).collect::>() - // ); + assert_eq!(collect_kv(std_map.range(..)), collect(stable_map.range(..))); - // for r in l + 1..=NKEYS { - // for lbound in [Bound::Included(l), Bound::Excluded(l)] { - // for rbound in [Bound::Included(r), Bound::Excluded(r)] { - // let range = (lbound, rbound); - // assert_eq!( - // std_map - // .range(range) - // .map(|(k, v)| (*k, *v)) - // .collect::>(), - // stable_map.range(range).collect::>(), - // "range: {range:?}" - // ); - // } - // } - // } - // } - // }); - // } - // btree_test!(test_, ); + for l in 0..=NKEYS { + assert_eq!( + collect_kv(std_map.range(key(l)..)), + collect(stable_map.range(key(l)..)) + ); + + assert_eq!( + collect_kv(std_map.range(..key(l))), + collect(stable_map.range(..key(l))) + ); + + assert_eq!( + collect_kv(std_map.range(..=key(l))), + collect(stable_map.range(..=key(l))) + ); + + for r in l + 1..=NKEYS { + for lbound in [Bound::Included(key(l)), Bound::Excluded(key(l))] { + for rbound in [Bound::Included(key(r)), Bound::Excluded(key(r))] { + let range = (lbound.clone(), rbound); + assert_eq!( + collect_kv(std_map.range(range.clone())), + collect(stable_map.range(range.clone())), + "range: {range:?}" + ); + } + } + } + } + }); + } + btree_test!(test_bruteforce_range_search, bruteforce_range_search); // fn test_iter_upper_bound() { // run_btree_test(|mut btree| { From e5522ba23b8045b1bbd02851f854a72940b8d88f Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:17:27 +0200 Subject: [PATCH 40/66] . --- src/btreemap.rs | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index e5d08669..2137361a 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2711,27 +2711,28 @@ mod test { } btree_test!(test_bruteforce_range_search, bruteforce_range_search); - // fn test_iter_upper_bound() { - // run_btree_test(|mut btree| { - // for k in 0..100u64 { - // btree.insert(k, ()); - // for i in 0..=k { - // assert_eq!( - // Some((i, ())), - // btree.iter_upper_bound(&(i + 1)).next(), - // "failed to get an upper bound for key {}", - // i + 1 - // ); - // } - // assert_eq!( - // None, - // btree.iter_upper_bound(&0).next(), - // "key 0 must not have an upper bound" - // ); - // } - // }); - // } - // btree_test!(test_, ); + fn test_iter_upper_bound() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); + run_btree_test(|mut btree| { + for j in 0..100 { + btree.insert(key(j), value(j)); + for i in 0..=j { + assert_eq!( + btree.iter_upper_bound(&key(i + 1)).next(), + Some((key(i), value(i))), + "failed to get an upper bound for key({})", + i + 1 + ); + } + assert_eq!( + btree.iter_upper_bound(&key(0)).next(), + None, + "key(0) must not have an upper bound" + ); + } + }); + } + btree_test!(test_test_iter_upper_bound, test_iter_upper_bound); // // A buggy implementation of storable where the max_size is smaller than the serialized size. // #[derive(Clone, Ord, PartialOrd, Eq, PartialEq)] From 4dc14cd70fe825e8f2467118ee6286170b31b1be Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:19:00 +0200 Subject: [PATCH 41/66] . --- src/btreemap.rs | 79 ++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 2137361a..46a5b1f0 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2734,52 +2734,51 @@ mod test { } btree_test!(test_test_iter_upper_bound, test_iter_upper_bound); - // // A buggy implementation of storable where the max_size is smaller than the serialized size. - // #[derive(Clone, Ord, PartialOrd, Eq, PartialEq)] - // struct BuggyStruct; - // impl crate::Storable for BuggyStruct { - // fn to_bytes(&self) -> Cow<[u8]> { - // Cow::Borrowed(&[1, 2, 3, 4]) - // } + // A buggy implementation of storable where the max_size is smaller than the serialized size. + #[derive(Clone, Ord, PartialOrd, Eq, PartialEq)] + struct BuggyStruct; + impl crate::Storable for BuggyStruct { + fn to_bytes(&self) -> Cow<[u8]> { + Cow::Borrowed(&[1, 2, 3, 4]) + } - // fn from_bytes(_: Cow<[u8]>) -> Self { - // unimplemented!(); - // } + fn from_bytes(_: Cow<[u8]>) -> Self { + unimplemented!(); + } - // const BOUND: StorableBound = StorableBound::Bounded { - // max_size: 1, - // is_fixed_size: false, - // }; - // } - // btree_test!(test_, ); + const BOUND: StorableBound = StorableBound::Bounded { + max_size: 1, + is_fixed_size: false, + }; + } - // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - // fn v1_panics_if_key_is_bigger_than_max_size() { - // let mut btree = BTreeMap::init_v1(make_memory()); - // btree.insert(BuggyStruct, ()); - // } - // btree_test!(test_, ); + #[test] + #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] + fn v1_panics_if_key_is_bigger_than_max_size() { + let mut btree = BTreeMap::init_v1(make_memory()); + btree.insert(BuggyStruct, ()); + } - // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - // fn v2_panics_if_key_is_bigger_than_max_size() { - // let mut btree = BTreeMap::init(make_memory()); - // btree.insert(BuggyStruct, ()); - // } - // btree_test!(test_, ); + #[test] + #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] + fn v2_panics_if_key_is_bigger_than_max_size() { + let mut btree = BTreeMap::init(make_memory()); + btree.insert(BuggyStruct, ()); + } - // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - // fn v1_panics_if_value_is_bigger_than_max_size() { - // let mut btree = BTreeMap::init(make_memory()); - // btree.insert((), BuggyStruct); - // } - // btree_test!(test_, ); + #[test] + #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] + fn v1_panics_if_value_is_bigger_than_max_size() { + let mut btree = BTreeMap::init(make_memory()); + btree.insert((), BuggyStruct); + } - // #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] - // fn v2_panics_if_value_is_bigger_than_max_size() { - // let mut btree = BTreeMap::init(make_memory()); - // btree.insert((), BuggyStruct); - // } - // btree_test!(test_, ); + #[test] + #[should_panic(expected = "expected an element with length <= 1 bytes, but found 4")] + fn v2_panics_if_value_is_bigger_than_max_size() { + let mut btree = BTreeMap::init(make_memory()); + btree.insert((), BuggyStruct); + } // // To generate the memory dump file for the current version: // // cargo test create_btreemap_dump_file -- --include-ignored From 70a80cf4b6c5bb639fd1d75810337e1d6b2662b9 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:27:38 +0200 Subject: [PATCH 42/66] . --- src/btreemap.rs | 76 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 46a5b1f0..767decc3 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1260,23 +1260,42 @@ mod test { } } + macro_rules! btree_test_body { + ($runner_fn:ident) => {{ + // first key/value combo + { + type K = u32; + type V = Blob<20>; + verify_monotonic::(); + $runner_fn::(); + } + // second key/value combo + { + type K = Blob<10>; + type V = Blob<20>; + verify_monotonic::(); + $runner_fn::(); + } + }}; + } + /// Macro to apply a test function to a predefined grid of key/value types. macro_rules! btree_test { ($name:ident, $runner_fn:ident) => { #[test] fn $name() { - { - type K = u32; - type V = Blob<20>; - verify_monotonic::(); - $runner_fn::(); - } - { - type K = Blob<10>; - type V = Blob<20>; - verify_monotonic::(); - $runner_fn::(); - } + btree_test_body!($runner_fn); + } + }; + } + + /// Macro to apply a test function to a predefined grid of key/value types. + macro_rules! btree_test_ignored { + ($name:ident, $runner_fn:ident) => { + #[test] + #[ignore] + fn $name() { + btree_test_body!($runner_fn); } }; } @@ -2780,21 +2799,26 @@ mod test { btree.insert((), BuggyStruct); } - // // To generate the memory dump file for the current version: - // // cargo test create_btreemap_dump_file -- --include-ignored - // #[ignore] - // fn create_btreemap_dump_file() { - // let mem = make_memory(); - // let mut btree = BTreeMap::init_v1(mem.clone()); - // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + // To generate the memory dump file for the current version: + // cargo test create_btreemap_dump_file -- --include-ignored + fn create_btreemap_dump_file() { + let (key, value) = (|i| K::make(i), |i| V::make(i)); - // use std::io::prelude::*; - // let mut file = - // std::fs::File::create(format!("dumps/btreemap_v{LAYOUT_VERSION}.dump")).unwrap(); - // file.write_all(&mem.borrow()).unwrap(); - // } - // btree_test!(test_, ); + let mem = make_memory(); + let mut btree = BTreeMap::init_v1(mem.clone()); + assert_eq!(btree.insert(key(1), value(1)), None); + assert_eq!(btree.get(&key(1)), Some(value(1))); + + let key_type = std::any::type_name::(); + let value_type = std::any::type_name::(); + use std::io::prelude::*; + let mut file = std::fs::File::create(format!( + "dumps/btreemap_v{LAYOUT_VERSION}_{key_type}_{value_type}.dump" + )) + .unwrap(); + file.write_all(&mem.borrow()).unwrap(); + } + btree_test_ignored!(test_create_btreemap_dump_file, create_btreemap_dump_file); // fn produces_layout_identical_to_layout_version_1_with_packed_headers() { // let mem = make_memory(); From 3b63be04bf322560cbb12ce0f54717d567896d6c Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:32:06 +0200 Subject: [PATCH 43/66] . --- src/btreemap.rs | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 767decc3..32a04be8 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2801,35 +2801,36 @@ mod test { // To generate the memory dump file for the current version: // cargo test create_btreemap_dump_file -- --include-ignored - fn create_btreemap_dump_file() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); - + #[test] + #[ignore] + fn create_btreemap_dump_file() { let mem = make_memory(); let mut btree = BTreeMap::init_v1(mem.clone()); - assert_eq!(btree.insert(key(1), value(1)), None); - assert_eq!(btree.get(&key(1)), Some(value(1))); - let key_type = std::any::type_name::(); - let value_type = std::any::type_name::(); + let key = b(&[1, 2, 3]); + let value = b(&[4, 5, 6]); + assert_eq!(btree.insert(key, value), None); + assert_eq!(btree.get(&key), Some(value)); + use std::io::prelude::*; - let mut file = std::fs::File::create(format!( - "dumps/btreemap_v{LAYOUT_VERSION}_{key_type}_{value_type}.dump" - )) - .unwrap(); + let mut file = + std::fs::File::create(format!("dumps/btreemap_v{LAYOUT_VERSION}.dump")).unwrap(); file.write_all(&mem.borrow()).unwrap(); } - btree_test_ignored!(test_create_btreemap_dump_file, create_btreemap_dump_file); - // fn produces_layout_identical_to_layout_version_1_with_packed_headers() { - // let mem = make_memory(); - // let mut btree = BTreeMap::init_v1(mem.clone()); - // assert_eq!(btree.insert(b(&[1, 2, 3]), b(&[4, 5, 6])), None); - // assert_eq!(btree.get(&b(&[1, 2, 3])), Some(b(&[4, 5, 6]))); + #[test] + fn produces_layout_identical_to_layout_version_1_with_packed_headers() { + let mem = make_memory(); + let mut btree = BTreeMap::init_v1(mem.clone()); - // let btreemap_v1 = include_bytes!("../dumps/btreemap_v1_packed_headers.dump"); - // assert_eq!(*mem.borrow(), btreemap_v1); - // } - // btree_test!(test_, ); + let key = b(&[1, 2, 3]); + let value = b(&[4, 5, 6]); + assert_eq!(btree.insert(key, value), None); + assert_eq!(btree.get(&key), Some(value)); + + let btreemap_v1 = include_bytes!("../dumps/btreemap_v1_packed_headers.dump"); + assert_eq!(*mem.borrow(), btreemap_v1); + } // fn read_write_header_is_identical_to_read_write_struct() { // #[repr(C, packed)] From a4b266f5b9ff0dd7e4dc701e7d08f97cfc2222d0 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:36:32 +0200 Subject: [PATCH 44/66] . --- src/btreemap.rs | 477 ++++++++++++++++++++++++------------------------ 1 file changed, 239 insertions(+), 238 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 32a04be8..04c54698 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2832,269 +2832,270 @@ mod test { assert_eq!(*mem.borrow(), btreemap_v1); } - // fn read_write_header_is_identical_to_read_write_struct() { - // #[repr(C, packed)] - // struct BTreePackedHeader { - // magic: [u8; 3], - // version: u8, - // max_key_size: u32, - // max_value_size: u32, - // root_addr: Address, - // length: u64, - // _buffer: [u8; 24], - // } - // let packed_header = BTreePackedHeader { - // magic: *MAGIC, - // version: LAYOUT_VERSION, - // root_addr: Address::from(0xDEADBEEF), - // max_key_size: 0x12345678, - // max_value_size: 0x87654321, - // length: 0xA1B2D3C4, - // _buffer: [0; 24], - // }; - - // let packed_mem = make_memory(); - // crate::write_struct(&packed_header, Address::from(0), &packed_mem); - - // let v1_header = BTreeHeader { - // version: Version::V1(DerivedPageSize { - // max_key_size: 0x12345678, - // max_value_size: 0x87654321, - // }), - // root_addr: Address::from(0xDEADBEEF), - // length: 0xA1B2D3C4, - // }; - - // let v1_mem = make_memory(); - // BTreeMap::, Vec<_>, RefCell>>::write_header(&v1_header, &v1_mem); - - // assert_eq!(packed_mem, v1_mem); - - // let packed_header: BTreePackedHeader = crate::read_struct(Address::from(0), &v1_mem); - // let v1_header = BTreeMap::, Vec<_>, RefCell>>::read_header(&v1_mem); - // assert!(packed_header.magic == *MAGIC); - // assert!(packed_header.version == LAYOUT_VERSION); - // match v1_header.version { - // Version::V1(DerivedPageSize { - // max_key_size, - // max_value_size, - // }) => { - // assert!(packed_header.max_key_size == max_key_size); - // assert!(packed_header.max_value_size == max_value_size); - // } - // _ => unreachable!("version must be v1"), - // }; - - // assert!(packed_header.root_addr == v1_header.root_addr); - // assert!(packed_header.length == v1_header.length); - // } - // btree_test!(test_, ); + #[test] + fn read_write_header_is_identical_to_read_write_struct() { + #[repr(C, packed)] + struct BTreePackedHeader { + magic: [u8; 3], + version: u8, + max_key_size: u32, + max_value_size: u32, + root_addr: Address, + length: u64, + _buffer: [u8; 24], + } + let packed_header = BTreePackedHeader { + magic: *MAGIC, + version: LAYOUT_VERSION, + root_addr: Address::from(0xDEADBEEF), + max_key_size: 0x12345678, + max_value_size: 0x87654321, + length: 0xA1B2D3C4, + _buffer: [0; 24], + }; - // fn migrate_from_bounded_to_unbounded_and_back() { - // // A type that is bounded. - // #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] - // struct T; - // impl Storable for T { - // fn to_bytes(&self) -> Cow<[u8]> { - // Cow::Owned(vec![1, 2, 3]) - // } - - // fn from_bytes(bytes: Cow<[u8]>) -> Self { - // assert_eq!(bytes.to_vec(), vec![1, 2, 3]); - // T - // } - - // const BOUND: StorableBound = StorableBound::Bounded { - // max_size: 3, - // is_fixed_size: true, - // }; - // } - - // // Same as the above type, but unbounded. - // #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] - // struct T2; - // impl Storable for T2 { - // fn to_bytes(&self) -> Cow<[u8]> { - // Cow::Owned(vec![1, 2, 3]) - // } - - // fn from_bytes(bytes: Cow<[u8]>) -> Self { - // assert_eq!(bytes.to_vec(), vec![1, 2, 3]); - // T2 - // } - - // const BOUND: StorableBound = StorableBound::Unbounded; - // } - - // // Create a v1 btreemap with the bounded type. - // let mem = make_memory(); - // let mut btree: BTreeMap = BTreeMap::new_v1(mem); - // btree.insert(T, T); - - // // Migrate to v2 and the unbounded type. - // let btree: BTreeMap = BTreeMap::init(btree.into_memory()); - // btree.save_header(); - - // // Reload the BTree again and try to read the value. - // let btree: BTreeMap = BTreeMap::init(btree.into_memory()); - // assert_eq!(btree.get(&T2), Some(T2)); - - // // Reload the BTree again with bounded type. - // let btree: BTreeMap = BTreeMap::init(btree.into_memory()); - // assert_eq!(btree.get(&T), Some(T)); - // } - // btree_test!(test_, ); + let packed_mem = make_memory(); + crate::write_struct(&packed_header, Address::from(0), &packed_mem); - // fn test_clear_new_bounded_type() { - // let mem = make_memory(); - // let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::new(mem.clone()); + let v1_header = BTreeHeader { + version: Version::V1(DerivedPageSize { + max_key_size: 0x12345678, + max_value_size: 0x87654321, + }), + root_addr: Address::from(0xDEADBEEF), + length: 0xA1B2D3C4, + }; - // btree.insert( - // [1u8; 4].as_slice().try_into().unwrap(), - // [1u8; 4].as_slice().try_into().unwrap(), - // ); + let v1_mem = make_memory(); + BTreeMap::, Vec<_>, RefCell>>::write_header(&v1_header, &v1_mem); - // assert_ne!(btree.len(), 0); - // assert_ne!(btree.allocator.num_allocated_chunks(), 0); - // assert_ne!(btree.root_addr, NULL); + assert_eq!(packed_mem, v1_mem); - // btree.clear_new(); + let packed_header: BTreePackedHeader = crate::read_struct(Address::from(0), &v1_mem); + let v1_header = BTreeMap::, Vec<_>, RefCell>>::read_header(&v1_mem); + assert!(packed_header.magic == *MAGIC); + assert!(packed_header.version == LAYOUT_VERSION); + match v1_header.version { + Version::V1(DerivedPageSize { + max_key_size, + max_value_size, + }) => { + assert!(packed_header.max_key_size == max_key_size); + assert!(packed_header.max_value_size == max_value_size); + } + _ => unreachable!("version must be v1"), + }; - // let header_actual = BTreeMap::, Blob<4>, _>::read_header(&mem); + assert!(packed_header.root_addr == v1_header.root_addr); + assert!(packed_header.length == v1_header.length); + } - // BTreeMap::, Blob<4>, _>::new(mem.clone()); + #[test] + fn migrate_from_bounded_to_unbounded_and_back() { + // A type that is bounded. + #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] + struct T; + impl Storable for T { + fn to_bytes(&self) -> Cow<[u8]> { + Cow::Owned(vec![1, 2, 3]) + } - // let header_expected = BTreeMap::, Blob<4>, _>::read_header(&mem); + fn from_bytes(bytes: Cow<[u8]>) -> Self { + assert_eq!(bytes.to_vec(), vec![1, 2, 3]); + T + } - // assert_eq!(header_actual, header_expected); - // } - // btree_test!(test_, ); + const BOUND: StorableBound = StorableBound::Bounded { + max_size: 3, + is_fixed_size: true, + }; + } - // fn test_clear_new_unbounded_type() { - // let mem = make_memory(); - // let mut btree: BTreeMap = BTreeMap::new(mem.clone()); - // btree.insert("asd".into(), "bce".into()); + // Same as the above type, but unbounded. + #[derive(PartialOrd, Ord, Clone, Eq, PartialEq, Debug)] + struct T2; + impl Storable for T2 { + fn to_bytes(&self) -> Cow<[u8]> { + Cow::Owned(vec![1, 2, 3]) + } - // assert_ne!(btree.len(), 0); - // assert_ne!(btree.allocator.num_allocated_chunks(), 0); - // assert_ne!(btree.root_addr, NULL); + fn from_bytes(bytes: Cow<[u8]>) -> Self { + assert_eq!(bytes.to_vec(), vec![1, 2, 3]); + T2 + } - // btree.clear_new(); + const BOUND: StorableBound = StorableBound::Unbounded; + } - // let header_actual = BTreeMap::::read_header(&mem); + // Create a v1 btreemap with the bounded type. + let mem = make_memory(); + let mut btree: BTreeMap = BTreeMap::new_v1(mem); + btree.insert(T, T); - // BTreeMap::::new(mem.clone()); + // Migrate to v2 and the unbounded type. + let btree: BTreeMap = BTreeMap::init(btree.into_memory()); + btree.save_header(); - // let header_expected = BTreeMap::::read_header(&mem); + // Reload the BTree again and try to read the value. + let btree: BTreeMap = BTreeMap::init(btree.into_memory()); + assert_eq!(btree.get(&T2), Some(T2)); - // assert_eq!(header_actual, header_expected); - // } - // btree_test!(test_, ); + // Reload the BTree again with bounded type. + let btree: BTreeMap = BTreeMap::init(btree.into_memory()); + assert_eq!(btree.get(&T), Some(T)); + } - // fn deallocating_node_with_overflows() { - // let mem = make_memory(); - // let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); + #[test] + fn test_clear_new_bounded_type() { + let mem = make_memory(); + let mut btree: BTreeMap, Blob<4>, _> = BTreeMap::new(mem.clone()); + + btree.insert( + [1u8; 4].as_slice().try_into().unwrap(), + [1u8; 4].as_slice().try_into().unwrap(), + ); - // // No allocated chunks yet. - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + assert_ne!(btree.len(), 0); + assert_ne!(btree.allocator.num_allocated_chunks(), 0); + assert_ne!(btree.root_addr, NULL); - // // Insert and remove an entry that's large and requires overflow pages. - // btree.insert(vec![0; 10_000], vec![]); + btree.clear_new(); - // // At least two chunks should be allocated. - // // One for the node itself and at least one overflow page. - // assert!(btree.allocator.num_allocated_chunks() >= 2); - // btree.remove(&vec![0; 10_000]); + let header_actual = BTreeMap::, Blob<4>, _>::read_header(&mem); - // // All chunks have been deallocated. - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // } - // btree_test!(test_, ); + BTreeMap::, Blob<4>, _>::new(mem.clone()); + + let header_expected = BTreeMap::, Blob<4>, _>::read_header(&mem); - // fn repeatedly_deallocating_nodes_with_overflows() { - // let mem = make_memory(); - // let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); + assert_eq!(header_actual, header_expected); + } - // // No allocated chunks yet. - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); + #[test] + fn test_clear_new_unbounded_type() { + let mem = make_memory(); + let mut btree: BTreeMap = BTreeMap::new(mem.clone()); + btree.insert("asd".into(), "bce".into()); - // for _ in 0..100 { - // for i in 0..100 { - // btree.insert(vec![i; 10_000], vec![]); - // } + assert_ne!(btree.len(), 0); + assert_ne!(btree.allocator.num_allocated_chunks(), 0); + assert_ne!(btree.root_addr, NULL); - // for i in 0..100 { - // btree.remove(&vec![i; 10_000]); - // } - // } + btree.clear_new(); - // // All chunks have been deallocated. - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // } - // btree_test!(test_, ); + let header_actual = BTreeMap::::read_header(&mem); - // fn deallocating_root_does_not_leak_memory() { - // let mem = make_memory(); - // let mut btree: BTreeMap, _, _> = BTreeMap::new(mem.clone()); - - // for i in 1..=11 { - // // Large keys are stored so that each node overflows. - // assert_eq!(btree.insert(vec![i; 10_000], ()), None); - // } - - // // Should now split a node. - // assert_eq!(btree.insert(vec![0; 10_000], ()), None); - - // // The btree should look like this: - // // [6] - // // / \ - // // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.keys(), vec![vec![6; 10_000]]); - // assert_eq!(root.children_len(), 2); - - // // Remove the element in the root. - // btree.remove(&vec![6; 10_000]); - - // // The btree should look like this: - // // [5] - // // / \ - // // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Internal); - // assert_eq!(root.keys(), vec![vec![5; 10_000]]); - // assert_eq!(root.children_len(), 2); - - // // Remove the element in the root. This triggers the case where the root - // // node is deallocated and the children are merged into a single node. - // btree.remove(&vec![5; 10_000]); - - // // The btree should look like this: - // // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11] - // let root = btree.load_node(btree.root_addr); - // assert_eq!(root.node_type(), NodeType::Leaf); - // assert_eq!( - // root.keys(), - // vec![ - // vec![0; 10_000], - // vec![1; 10_000], - // vec![2; 10_000], - // vec![3; 10_000], - // vec![4; 10_000], - // vec![7; 10_000], - // vec![8; 10_000], - // vec![9; 10_000], - // vec![10; 10_000], - // vec![11; 10_000], - // ] - // ); - - // // Delete everything else. - // for i in 0..=11 { - // btree.remove(&vec![i; 10_000]); - // } - - // assert_eq!(btree.allocator.num_allocated_chunks(), 0); - // } + BTreeMap::::new(mem.clone()); + + let header_expected = BTreeMap::::read_header(&mem); + + assert_eq!(header_actual, header_expected); + } + + #[test] + fn deallocating_node_with_overflows() { + let mem = make_memory(); + let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); + + // No allocated chunks yet. + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + // Insert and remove an entry that's large and requires overflow pages. + btree.insert(vec![0; 10_000], vec![]); + + // At least two chunks should be allocated. + // One for the node itself and at least one overflow page. + assert!(btree.allocator.num_allocated_chunks() >= 2); + btree.remove(&vec![0; 10_000]); + + // All chunks have been deallocated. + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + } + + #[test] + fn repeatedly_deallocating_nodes_with_overflows() { + let mem = make_memory(); + let mut btree: BTreeMap, Vec, _> = BTreeMap::new(mem.clone()); + + // No allocated chunks yet. + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + + for _ in 0..100 { + for i in 0..100 { + btree.insert(vec![i; 10_000], vec![]); + } + + for i in 0..100 { + btree.remove(&vec![i; 10_000]); + } + } + + // All chunks have been deallocated. + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + } + + #[test] + fn deallocating_root_does_not_leak_memory() { + let mem = make_memory(); + let mut btree: BTreeMap, _, _> = BTreeMap::new(mem.clone()); + + for i in 1..=11 { + // Large keys are stored so that each node overflows. + assert_eq!(btree.insert(vec![i; 10_000], ()), None); + } + + // Should now split a node. + assert_eq!(btree.insert(vec![0; 10_000], ()), None); + + // The btree should look like this: + // [6] + // / \ + // [0, 1, 2, 3, 4, 5] [7, 8, 9, 10, 11] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.keys(), vec![vec![6; 10_000]]); + assert_eq!(root.children_len(), 2); + + // Remove the element in the root. + btree.remove(&vec![6; 10_000]); + + // The btree should look like this: + // [5] + // / \ + // [0, 1, 2, 3, 4] [7, 8, 9, 10, 11] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Internal); + assert_eq!(root.keys(), vec![vec![5; 10_000]]); + assert_eq!(root.children_len(), 2); + + // Remove the element in the root. This triggers the case where the root + // node is deallocated and the children are merged into a single node. + btree.remove(&vec![5; 10_000]); + + // The btree should look like this: + // [0, 1, 2, 3, 4, 7, 8, 9, 10, 11] + let root = btree.load_node(btree.root_addr); + assert_eq!(root.node_type(), NodeType::Leaf); + assert_eq!( + root.keys(), + vec![ + vec![0; 10_000], + vec![1; 10_000], + vec![2; 10_000], + vec![3; 10_000], + vec![4; 10_000], + vec![7; 10_000], + vec![8; 10_000], + vec![9; 10_000], + vec![10; 10_000], + vec![11; 10_000], + ] + ); + + // Delete everything else. + for i in 0..=11 { + btree.remove(&vec![i; 10_000]); + } + + assert_eq!(btree.allocator.num_allocated_chunks(), 0); + } } From e57b39362b3b48a96bc63a8de18bc6723f6109c4 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:37:33 +0200 Subject: [PATCH 45/66] . --- src/btreemap.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 04c54698..61159d5a 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2503,10 +2503,10 @@ mod test { fn range_various_prefixes_with_offset_2() { let (key, value) = (|i| K::make(i), |i| V::make(i)); run_btree_test(|mut btree| { - btree.insert(key(01), value(0)); - btree.insert(key(02), value(0)); - btree.insert(key(03), value(0)); - btree.insert(key(04), value(0)); + btree.insert(key(1), value(0)); + btree.insert(key(2), value(0)); + btree.insert(key(3), value(0)); + btree.insert(key(4), value(0)); btree.insert(key(12), value(0)); btree.insert(key(14), value(0)); btree.insert(key(16), value(0)); From 97de8a295e68910f8310f028790b1a50ff830c6b Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:39:06 +0200 Subject: [PATCH 46/66] cleanup --- src/btreemap.rs | 57 +++++++++++-------------------------------------- 1 file changed, 12 insertions(+), 45 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 61159d5a..f008192e 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1160,7 +1160,6 @@ mod test { storable::{Blob, Bound as StorableBound, Storable}, VectorMemory, }; - use core::panic; use std::borrow::Cow; use std::cell::RefCell; use std::convert::TryFrom; @@ -1204,19 +1203,6 @@ mod test { object.to_bytes_checked().into_owned() } - /// Decodes a byte vector into an object. - fn decode(bytes: Vec) -> T { - T::from_bytes(Cow::Owned(bytes)) - } - - // // TODO: remove obsolete code. - // /// A helper method to succinctly create an entry. - // fn e(x: u8) -> (Blob<10>, Vec) { - // (b(&[x]), vec![]) - // } - // btree_test!(test_, ); - - // TODO: remove obsolete code. /// A helper method to succinctly create a blob. pub(crate) fn b(x: &[u8]) -> Blob<10> { Blob::<10>::try_from(x).unwrap() @@ -1260,42 +1246,23 @@ mod test { } } - macro_rules! btree_test_body { - ($runner_fn:ident) => {{ - // first key/value combo - { - type K = u32; - type V = Blob<20>; - verify_monotonic::(); - $runner_fn::(); - } - // second key/value combo - { - type K = Blob<10>; - type V = Blob<20>; - verify_monotonic::(); - $runner_fn::(); - } - }}; - } - /// Macro to apply a test function to a predefined grid of key/value types. macro_rules! btree_test { ($name:ident, $runner_fn:ident) => { #[test] fn $name() { - btree_test_body!($runner_fn); - } - }; - } - - /// Macro to apply a test function to a predefined grid of key/value types. - macro_rules! btree_test_ignored { - ($name:ident, $runner_fn:ident) => { - #[test] - #[ignore] - fn $name() { - btree_test_body!($runner_fn); + { + type K = u32; + type V = Blob<20>; + verify_monotonic::(); + $runner_fn::(); + } + { + type K = Blob<10>; + type V = Blob<20>; + verify_monotonic::(); + $runner_fn::(); + } } }; } From 7dc8f219ca1ea7fed6ef084e65819b36f5f3c4c7 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:40:32 +0200 Subject: [PATCH 47/66] . --- src/btreemap.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index f008192e..066540e8 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1160,7 +1160,6 @@ mod test { storable::{Blob, Bound as StorableBound, Storable}, VectorMemory, }; - use std::borrow::Cow; use std::cell::RefCell; use std::convert::TryFrom; use std::rc::Rc; From 47a29e07d1889a0c2331f1e8eb9868afee3263d4 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:40:56 +0200 Subject: [PATCH 48/66] . --- src/btreemap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 066540e8..19a86766 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1157,7 +1157,7 @@ where mod test { use super::*; use crate::{ - storable::{Blob, Bound as StorableBound, Storable}, + storable::{Blob, Bound as StorableBound}, VectorMemory, }; use std::cell::RefCell; From a264e9481f802ff271a7811a2021266075ed6e73 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:42:58 +0200 Subject: [PATCH 49/66] . --- src/btreemap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 19a86766..72649282 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1165,7 +1165,7 @@ mod test { use std::rc::Rc; /// Returns a fixed‑size buffer for the given u32. - fn make_buffer(i: u32) -> [u8; N] { + fn make_monotonic_buffer(i: u32) -> [u8; N] { let mut buf = [0u8; N]; let bytes = i.to_be_bytes(); buf[N - bytes.len()..].copy_from_slice(&bytes); @@ -1189,7 +1189,7 @@ mod test { impl Make for Blob { fn make(i: u32) -> Self { - Blob::try_from(&make_buffer::(i)[..]).unwrap() + Blob::try_from(&make_monotonic_buffer::(i)[..]).unwrap() } fn empty() -> Self { let x: &[u8] = &[]; From 2ad85af5fd1df3ff1f242a188d3fe9b175d300ee Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Wed, 16 Apr 2025 21:59:13 +0200 Subject: [PATCH 50/66] MonotonicString32 --- src/btreemap.rs | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 72649282..62938f3c 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1197,6 +1197,16 @@ mod test { } } + type MonotonicString32 = String; + impl Make for MonotonicString32 { + fn make(i: u32) -> Self { + format!("{i:0>32}") + } + fn empty() -> Self { + String::new() + } + } + /// Encodes an object into a byte vector. fn encode(object: T) -> Vec { object.to_bytes_checked().into_owned() @@ -1219,16 +1229,18 @@ mod test { V: Storable, F: Fn(BTreeMap) -> R, { - // Test with V1. - let mem = make_memory(); - let tree_v1 = BTreeMap::new_v1(mem); - f(tree_v1); - - // Test with V2 migrated from V1. - let mem = make_memory(); - let tree_v1: BTreeMap = BTreeMap::new_v1(mem); - let tree_v2_migrated = BTreeMap::load_helper(tree_v1.into_memory(), true); - f(tree_v2_migrated); + if K::BOUND != StorableBound::Unbounded { + // Test with V1. + let mem = make_memory(); + let tree_v1 = BTreeMap::new_v1(mem); + f(tree_v1); + + // Test with V2 migrated from V1. + let mem = make_memory(); + let tree_v1: BTreeMap = BTreeMap::new_v1(mem); + let tree_v2_migrated = BTreeMap::load_helper(tree_v1.into_memory(), true); + f(tree_v2_migrated); + } // Test with direct V2. let mem = make_memory(); @@ -1262,6 +1274,12 @@ mod test { verify_monotonic::(); $runner_fn::(); } + { + type K = MonotonicString32; + type V = String; + verify_monotonic::(); + $runner_fn::(); + } } }; } @@ -1593,11 +1611,11 @@ mod test { run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); - assert_eq!(btree.insert(key(1), value(1)), None); + assert_eq!(btree.insert(key(1), V::empty()), None); assert!(!btree.is_empty()); assert_eq!(btree.allocator.num_allocated_chunks(), 1); - assert_eq!(btree.pop_first(), Some((key(1), value(1)))); + assert_eq!(btree.pop_first(), Some((key(1), V::empty()))); assert!(btree.is_empty()); assert_eq!(btree.allocator.num_allocated_chunks(), 0); }); From 6e3ab136eb99bda3ddd30f192f692fb460cb98d6 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 07:58:30 +0200 Subject: [PATCH 51/66] . --- src/btreemap.rs | 53 +++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 62938f3c..1cf70123 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1178,6 +1178,11 @@ mod test { fn empty() -> Self; } + impl Make for () { + fn make(_i: u32) -> Self {} + fn empty() -> Self {} + } + impl Make for u32 { fn make(i: u32) -> Self { i @@ -1207,6 +1212,16 @@ mod test { } } + type MonotonicVec32 = Vec; + impl Make for MonotonicVec32 { + fn make(i: u32) -> Self { + make_monotonic_buffer::<32>(i).to_vec() + } + fn empty() -> Self { + Vec::new() + } + } + /// Encodes an object into a byte vector. fn encode(object: T) -> Vec { object.to_bytes_checked().into_owned() @@ -1257,29 +1272,29 @@ mod test { } } + macro_rules! verify_and_run { + ($runner:ident, $K:ty, $V:ty) => {{ + verify_monotonic::<$K>(); + $runner::<$K, $V>(); + }}; + } + /// Macro to apply a test function to a predefined grid of key/value types. macro_rules! btree_test { - ($name:ident, $runner_fn:ident) => { + ($name:ident, $runner:ident) => { #[test] fn $name() { - { - type K = u32; - type V = Blob<20>; - verify_monotonic::(); - $runner_fn::(); - } - { - type K = Blob<10>; - type V = Blob<20>; - verify_monotonic::(); - $runner_fn::(); - } - { - type K = MonotonicString32; - type V = String; - verify_monotonic::(); - $runner_fn::(); - } + // Set. + verify_and_run!($runner, u32, ()); + verify_and_run!($runner, Blob<10>, ()); + verify_and_run!($runner, MonotonicString32, ()); + verify_and_run!($runner, MonotonicVec32, ()); + + // Map. + verify_and_run!($runner, u32, Blob<20>); + verify_and_run!($runner, Blob<10>, Blob<20>); + verify_and_run!($runner, MonotonicString32, Blob<20>); + verify_and_run!($runner, MonotonicVec32, Blob<20>); } }; } From a34dab5d6610f0d27e9787b619b8544e3fe7d777 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 07:59:24 +0200 Subject: [PATCH 52/66] . --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index cbad8b17..707f8413 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,3 @@ .vscode/ .idea/ **/*~ - -tmp/ From 322f9ee6b74c24a7b74efd301462fa72ab415030 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 08:02:30 +0200 Subject: [PATCH 53/66] . --- .gitignore | 2 ++ src/btreemap.rs | 11 ++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 707f8413..cbad8b17 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ .vscode/ .idea/ **/*~ + +tmp/ diff --git a/src/btreemap.rs b/src/btreemap.rs index 1cf70123..e269c358 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1381,15 +1381,12 @@ mod test { let right_child = btree.load_node(root.child(1)); assert!(right_child.is_full()); let median_index = right_child.entries_len() / 2; - let expected_median_key = key(12); - assert_eq!(right_child.key(median_index), &expected_median_key); + let median_key = key(12); + assert_eq!(right_child.key(median_index), &median_key); // Overwrite the value of the median key. - assert_eq!( - btree.insert(expected_median_key.clone(), value(123)), - Some(value(0)) - ); - assert_eq!(btree.get(&expected_median_key), Some(value(123))); + assert_eq!(btree.insert(median_key.clone(), value(123)), Some(value(0))); + assert_eq!(btree.get(&median_key), Some(value(123))); // The child has not been split and is still full. let right_child = btree.load_node(root.child(1)); From a7ad7387952162e54ca88410389b49f1d4d96103 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 08:06:14 +0200 Subject: [PATCH 54/66] FromId --- src/btreemap.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index e269c358..83dc0715 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1173,17 +1173,17 @@ mod test { } /// A trait to construct a value from a u32. - trait Make { + trait FromId { fn make(i: u32) -> Self; fn empty() -> Self; } - impl Make for () { + impl FromId for () { fn make(_i: u32) -> Self {} fn empty() -> Self {} } - impl Make for u32 { + impl FromId for u32 { fn make(i: u32) -> Self { i } @@ -1192,7 +1192,7 @@ mod test { } } - impl Make for Blob { + impl FromId for Blob { fn make(i: u32) -> Self { Blob::try_from(&make_monotonic_buffer::(i)[..]).unwrap() } @@ -1203,7 +1203,7 @@ mod test { } type MonotonicString32 = String; - impl Make for MonotonicString32 { + impl FromId for MonotonicString32 { fn make(i: u32) -> Self { format!("{i:0>32}") } @@ -1213,7 +1213,7 @@ mod test { } type MonotonicVec32 = Vec; - impl Make for MonotonicVec32 { + impl FromId for MonotonicVec32 { fn make(i: u32) -> Self { make_monotonic_buffer::<32>(i).to_vec() } @@ -1265,7 +1265,7 @@ mod test { /// Checks that objects from boundary u32 values are strictly increasing. /// This ensures multi-byte conversions preserve order. - fn verify_monotonic() { + fn verify_monotonic() { for shift_bits in [8, 16, 24] { let i = (1 << shift_bits) - 1; assert!(T::make(i) < T::make(i + 1), "Monotonicity failed at i: {i}",); @@ -1300,12 +1300,12 @@ mod test { } // Define a trait for keys that need the full set of bounds. - trait TestKey: Storable + Ord + Clone + Make + std::fmt::Debug {} - impl TestKey for T where T: Storable + Ord + Clone + Make + std::fmt::Debug {} + trait TestKey: Storable + Ord + Clone + FromId + std::fmt::Debug {} + impl TestKey for T where T: Storable + Ord + Clone + FromId + std::fmt::Debug {} // Define a trait for values that need the full set of bounds. - trait TestValue: Storable + Clone + Make + std::fmt::Debug + PartialEq {} - impl TestValue for T where T: Storable + Clone + Make + std::fmt::Debug + PartialEq {} + trait TestValue: Storable + Clone + FromId + std::fmt::Debug + PartialEq {} + impl TestValue for T where T: Storable + Clone + FromId + std::fmt::Debug + PartialEq {} fn insert_get_init_preserves_data() { let (key, value) = (|i| K::make(i), |i| V::make(i)); From f7c56d8c9dae7d317be394b59f4a8bad254969bb Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 08:12:41 +0200 Subject: [PATCH 55/66] builder --- src/btreemap.rs | 109 +++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 83dc0715..94950aee 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1173,18 +1173,18 @@ mod test { } /// A trait to construct a value from a u32. - trait FromId { - fn make(i: u32) -> Self; + trait Builder { + fn build(i: u32) -> Self; fn empty() -> Self; } - impl FromId for () { - fn make(_i: u32) -> Self {} + impl Builder for () { + fn build(_i: u32) -> Self {} fn empty() -> Self {} } - impl FromId for u32 { - fn make(i: u32) -> Self { + impl Builder for u32 { + fn build(i: u32) -> Self { i } fn empty() -> Self { @@ -1192,8 +1192,8 @@ mod test { } } - impl FromId for Blob { - fn make(i: u32) -> Self { + impl Builder for Blob { + fn build(i: u32) -> Self { Blob::try_from(&make_monotonic_buffer::(i)[..]).unwrap() } fn empty() -> Self { @@ -1203,8 +1203,8 @@ mod test { } type MonotonicString32 = String; - impl FromId for MonotonicString32 { - fn make(i: u32) -> Self { + impl Builder for MonotonicString32 { + fn build(i: u32) -> Self { format!("{i:0>32}") } fn empty() -> Self { @@ -1213,8 +1213,8 @@ mod test { } type MonotonicVec32 = Vec; - impl FromId for MonotonicVec32 { - fn make(i: u32) -> Self { + impl Builder for MonotonicVec32 { + fn build(i: u32) -> Self { make_monotonic_buffer::<32>(i).to_vec() } fn empty() -> Self { @@ -1265,10 +1265,13 @@ mod test { /// Checks that objects from boundary u32 values are strictly increasing. /// This ensures multi-byte conversions preserve order. - fn verify_monotonic() { + fn verify_monotonic() { for shift_bits in [8, 16, 24] { let i = (1 << shift_bits) - 1; - assert!(T::make(i) < T::make(i + 1), "Monotonicity failed at i: {i}",); + assert!( + T::build(i) < T::build(i + 1), + "Monotonicity failed at i: {i}", + ); } } @@ -1300,15 +1303,15 @@ mod test { } // Define a trait for keys that need the full set of bounds. - trait TestKey: Storable + Ord + Clone + FromId + std::fmt::Debug {} - impl TestKey for T where T: Storable + Ord + Clone + FromId + std::fmt::Debug {} + trait TestKey: Storable + Ord + Clone + Builder + std::fmt::Debug {} + impl TestKey for T where T: Storable + Ord + Clone + Builder + std::fmt::Debug {} // Define a trait for values that need the full set of bounds. - trait TestValue: Storable + Clone + FromId + std::fmt::Debug + PartialEq {} - impl TestValue for T where T: Storable + Clone + FromId + std::fmt::Debug + PartialEq {} + trait TestValue: Storable + Clone + Builder + std::fmt::Debug + PartialEq {} + impl TestValue for T where T: Storable + Clone + Builder + std::fmt::Debug + PartialEq {} fn insert_get_init_preserves_data() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 1_000; for i in 0..n { @@ -1329,7 +1332,7 @@ mod test { ); fn insert_overwrites_previous_value() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 1_000; for i in 0..n { @@ -1345,7 +1348,7 @@ mod test { ); fn insert_same_key_many() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 1_000; assert_eq!(btree.insert(key(1), value(2)), None); @@ -1358,7 +1361,7 @@ mod test { btree_test!(test_insert_same_key_many, insert_same_key_many); fn insert_overwrite_median_key_in_full_child_node() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { for i in 1..=17 { assert_eq!(btree.insert(key(i), value(0)), None); @@ -1400,7 +1403,7 @@ mod test { ); fn insert_overwrite_key_in_full_root_node() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(key(i), value(0)), None); @@ -1427,7 +1430,7 @@ mod test { ); fn allocations_without_split() { - let key = |i| K::make(i); + let key = |i| K::build(i); run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); @@ -1441,7 +1444,7 @@ mod test { btree_test!(test_allocations_without_split, allocations_without_split); fn allocations_with_split() { - let key = |i| K::make(i); + let key = |i| K::build(i); run_btree_test(|mut btree| { // Insert entries until the root node is full. let mut i = 0; @@ -1466,7 +1469,7 @@ mod test { btree_test!(test_allocations_with_split, allocations_with_split); fn insert_split_node() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(key(i), value(10)), None); @@ -1490,7 +1493,7 @@ mod test { btree_test!(test_insert_split_node, insert_split_node); fn insert_split_multiple_nodes() { - let key = |i| K::make(i); + let key = |i| K::build(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1575,7 +1578,7 @@ mod test { ); fn first_key_value() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree: BTreeMap| { assert_eq!(btree.first_key_value(), None); @@ -1597,7 +1600,7 @@ mod test { btree_test!(test_first_key_value, first_key_value); fn last_key_value() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree: BTreeMap| { assert_eq!(btree.last_key_value(), None); @@ -1619,7 +1622,7 @@ mod test { btree_test!(test_last_key_value, last_key_value); fn pop_first_single_entry() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); @@ -1635,7 +1638,7 @@ mod test { btree_test!(test_pop_first_single_entry, pop_first_single_entry); fn pop_last_single_entry() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); @@ -1651,7 +1654,7 @@ mod test { btree_test!(test_pop_last_single_entry, pop_last_single_entry); fn remove_case_2a_and_2c() { - let key = |i| K::make(i); + let key = |i| K::build(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1719,7 +1722,7 @@ mod test { btree_test!(test_remove_case_2a_and_2c, remove_case_2a_and_2c); fn remove_case_2b() { - let key = |i| K::make(i); + let key = |i| K::build(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1784,7 +1787,7 @@ mod test { btree_test!(test_remove_case_2b, remove_case_2b); fn remove_case_3a_right() { - let key = |i| K::make(i); + let key = |i| K::build(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1832,7 +1835,7 @@ mod test { btree_test!(test_remove_case_3a_right, remove_case_3a_right); fn remove_case_3a_left() { - let key = |i| K::make(i); + let key = |i| K::build(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1879,7 +1882,7 @@ mod test { btree_test!(test_remove_case_3a_left, remove_case_3a_left); fn remove_case_3b_merge_into_right() { - let key = |i| K::make(i); + let key = |i| K::build(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1954,7 +1957,7 @@ mod test { ); fn remove_case_3b_merge_into_left() { - let key = |i| K::make(i); + let key = |i| K::build(i); let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -2028,7 +2031,7 @@ mod test { ); fn insert_remove_many() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 10_000; for i in 0..n { @@ -2049,7 +2052,7 @@ mod test { btree_test!(test_insert_remove_many, insert_remove_many); fn pop_first_many() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 10_000; @@ -2075,7 +2078,7 @@ mod test { btree_test!(test_pop_first_many, pop_first_many); fn pop_last_many() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 10_000; @@ -2101,7 +2104,7 @@ mod test { btree_test!(test_pop_last_many, pop_last_many); fn reloading() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 1_000; for i in 0..n { @@ -2131,7 +2134,7 @@ mod test { btree_test!(test_reloading, reloading); fn len() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 1_000; for i in 0..n { @@ -2152,7 +2155,7 @@ mod test { btree_test!(test_len, len); fn contains_key() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { let n = 1_000; for i in (0..n).step_by(2) { @@ -2168,7 +2171,7 @@ mod test { btree_test!(test_contains_key, contains_key); fn range_empty() { - let key = |i| K::make(i); + let key = |i| K::build(i); run_btree_test(|btree| { // Test prefixes that don't exist in the map. assert_eq!(btree.range(key(0)..).collect::>(), vec![]); @@ -2180,7 +2183,7 @@ mod test { // Tests the case where the prefix is larger than all the entries in a leaf node. fn range_leaf_prefix_greater_than_all_entries() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { btree.insert(key(0), value(0)); @@ -2195,7 +2198,7 @@ mod test { // Tests the case where the prefix is larger than all the entries in an internal node. fn range_internal_prefix_greater_than_all_entries() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { for i in 1..=12 { assert_eq!(btree.insert(key(i), value(i)), None); @@ -2219,7 +2222,7 @@ mod test { ); fn range_various_prefixes() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { btree.insert(key(1), value(100)); btree.insert(key(2), value(200)); @@ -2284,7 +2287,7 @@ mod test { btree_test!(test_range_various_prefixes, range_various_prefixes); fn range_various_prefixes_2() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { btree.insert(key(1), value(100)); btree.insert(key(2), value(200)); @@ -2412,7 +2415,7 @@ mod test { btree_test!(test_range_various_prefixes_2, range_various_prefixes_2); fn range_large() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { const TOTAL: u32 = 2_000; const MID: u32 = TOTAL / 2; @@ -2443,7 +2446,7 @@ mod test { btree_test!(test_range_large, range_large); fn range_various_prefixes_with_offset() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { btree.insert(key(1), value(100)); btree.insert(key(2), value(200)); @@ -2497,7 +2500,7 @@ mod test { ); fn range_various_prefixes_with_offset_2() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { btree.insert(key(1), value(0)); btree.insert(key(2), value(0)); @@ -2669,7 +2672,7 @@ mod test { } fn bruteforce_range_search() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); fn collect_kv<'a, K: Clone + 'a, V: Clone + 'a>( iter: impl Iterator, @@ -2727,7 +2730,7 @@ mod test { btree_test!(test_bruteforce_range_search, bruteforce_range_search); fn test_iter_upper_bound() { - let (key, value) = (|i| K::make(i), |i| V::make(i)); + let (key, value) = (|i| K::build(i), |i| V::build(i)); run_btree_test(|mut btree| { for j in 0..100 { btree.insert(key(j), value(j)); From 6365caf4b50255d7a300829355157c09de500602 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 08:15:34 +0200 Subject: [PATCH 56/66] . --- src/btreemap.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 94950aee..341b47ab 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1197,8 +1197,7 @@ mod test { Blob::try_from(&make_monotonic_buffer::(i)[..]).unwrap() } fn empty() -> Self { - let x: &[u8] = &[]; - Blob::try_from(x).unwrap() + Blob::try_from(&[][..]).unwrap() } } @@ -1622,7 +1621,7 @@ mod test { btree_test!(test_last_key_value, last_key_value); fn pop_first_single_entry() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let key = |i| K::build(i); run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); From cce474756420f5cd44bf3348c204c4fc6bea12a6 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 08:21:35 +0200 Subject: [PATCH 57/66] test_monotonic_buffer --- src/btreemap.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 341b47ab..b1f4f3ca 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1165,13 +1165,36 @@ mod test { use std::rc::Rc; /// Returns a fixed‑size buffer for the given u32. - fn make_monotonic_buffer(i: u32) -> [u8; N] { + fn monotonic_buffer(i: u32) -> [u8; N] { let mut buf = [0u8; N]; let bytes = i.to_be_bytes(); buf[N - bytes.len()..].copy_from_slice(&bytes); buf } + #[test] + fn test_monotonic_buffer() { + let cases: &[(u32, [u8; 4])] = &[ + (1, [0, 0, 0, 1]), + (2, [0, 0, 0, 2]), + ((1 << 8) - 1, [0, 0, 0, 255]), + ((1 << 8), [0, 0, 1, 0]), + ((1 << 16) - 1, [0, 0, 255, 255]), + (1 << 16, [0, 1, 0, 0]), + ((1 << 24) - 1, [0, 255, 255, 255]), + (1 << 24, [1, 0, 0, 0]), + ]; + + for &(input, expected) in cases { + let output = monotonic_buffer::<4>(input); + assert_eq!( + output, expected, + "monotonic_buffer::<4>({}) returned {:?}, expected {:?}", + input, output, expected + ); + } + } + /// A trait to construct a value from a u32. trait Builder { fn build(i: u32) -> Self; @@ -1194,7 +1217,7 @@ mod test { impl Builder for Blob { fn build(i: u32) -> Self { - Blob::try_from(&make_monotonic_buffer::(i)[..]).unwrap() + Blob::try_from(&monotonic_buffer::(i)[..]).unwrap() } fn empty() -> Self { Blob::try_from(&[][..]).unwrap() @@ -1214,7 +1237,7 @@ mod test { type MonotonicVec32 = Vec; impl Builder for MonotonicVec32 { fn build(i: u32) -> Self { - make_monotonic_buffer::<32>(i).to_vec() + monotonic_buffer::<32>(i).to_vec() } fn empty() -> Self { Vec::new() From a9276e70104639e1e40012c818ec75779dc468ba Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 08:54:14 +0200 Subject: [PATCH 58/66] . --- src/btreemap.rs | 65 ++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index b1f4f3ca..cccb46f7 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1164,6 +1164,16 @@ mod test { use std::convert::TryFrom; use std::rc::Rc; + fn collect_kv<'a, K: Clone + 'a, V: Clone + 'a>( + iter: impl Iterator, + ) -> Vec<(K, V)> { + iter.map(|(k, v)| (k.clone(), v.clone())).collect() + } + + fn collect(it: impl Iterator) -> Vec<(K, V)> { + it.collect() + } + /// Returns a fixed‑size buffer for the given u32. fn monotonic_buffer(i: u32) -> [u8; N] { let mut buf = [0u8; N]; @@ -1797,10 +1807,7 @@ mod test { assert_eq!(root.node_type(), NodeType::Leaf); assert_eq!( root.entries(btree.memory()), - [1, 2, 3, 4, 5, 8, 9, 10, 11, 12] - .into_iter() - .map(e) - .collect::>() + collect([1, 2, 3, 4, 5, 8, 9, 10, 11, 12].into_iter().map(e)) ); assert_eq!(btree.allocator.num_allocated_chunks(), 1); @@ -1963,10 +1970,7 @@ mod test { assert_eq!(root.node_type(), NodeType::Leaf); assert_eq!( root.entries(btree.memory()), - [1, 2, 4, 5, 7, 8, 9, 10, 11, 12] - .into_iter() - .map(e) - .collect::>() + collect([1, 2, 4, 5, 7, 8, 9, 10, 11, 12].into_iter().map(e)) ); // There is only one allocated node remaining. @@ -2194,11 +2198,11 @@ mod test { fn range_empty() { let key = |i| K::build(i); - run_btree_test(|btree| { + run_btree_test(|btree: BTreeMap| { // Test prefixes that don't exist in the map. - assert_eq!(btree.range(key(0)..).collect::>(), vec![]); - assert_eq!(btree.range(key(10)..).collect::>(), vec![]); - assert_eq!(btree.range(key(100)..).collect::>(), vec![]); + assert_eq!(collect(btree.range(key(0)..)), vec![]); + assert_eq!(collect(btree.range(key(10)..)), vec![]); + assert_eq!(collect(btree.range(key(100)..)), vec![]); }); } btree_test!(test_range_empty, range_empty); @@ -2233,7 +2237,7 @@ mod test { // Test a prefix that's larger than the key in the internal node. assert_eq!( - btree.range(key(7)..key(8)).collect::>(), + collect(btree.range(key(7)..key(8))), vec![(key(7), value(7))] ); }); @@ -2274,7 +2278,7 @@ mod test { // Tests a prefix that's smaller than the key in the internal node. assert_eq!( - btree.range(key(0)..key(11)).collect::>(), + collect(btree.range(key(0)..key(11))), vec![ (key(1), value(100)), (key(2), value(200)), @@ -2285,7 +2289,7 @@ mod test { // Tests a prefix that crosses several nodes. assert_eq!( - btree.range(key(10)..key(20)).collect::>(), + collect(btree.range(key(10)..key(20))), vec![ (key(11), value(500)), (key(12), value(600)), @@ -2296,7 +2300,7 @@ mod test { // Tests a prefix that's larger than the key in the internal node. assert_eq!( - btree.range(key(20)..key(30)).collect::>(), + collect(btree.range(key(20)..key(30))), vec![ (key(21), value(900)), (key(22), value(1_000)), @@ -2386,11 +2390,11 @@ mod test { ); // Tests a prefix that doesn't exist, but is in the middle of the root node. - assert_eq!(btree.range(key(15)..key(16)).collect::>(), vec![]); + assert_eq!(collect(btree.range(key(15)..key(16))), vec![]); // Tests a prefix beginning in the middle of the tree and crossing several nodes. assert_eq!( - btree.range(key(15)..=key(26)).collect::>(), + collect(btree.range(key(15)..=key(26))), vec![ (key(16), value(700)), (key(18), value(800)), @@ -2406,7 +2410,7 @@ mod test { // Tests a prefix that crosses several nodes. assert_eq!( - btree.range(key(10)..key(20)).collect::>(), + collect(btree.range(key(10)..key(20))), vec![ (key(12), value(500)), (key(14), value(600)), @@ -2419,7 +2423,7 @@ mod test { // Tests a prefix that starts from a leaf node, then iterates through the root and right // sibling. assert_eq!( - btree.range(key(20)..key(30)).collect::>(), + collect(btree.range(key(20)..key(30))), vec![ (key(21), value(1000)), (key(22), value(1100)), @@ -2497,7 +2501,7 @@ mod test { assert_eq!(root.children_len(), 2); assert_eq!( - btree.range(key(0)..key(10)).collect::>(), + collect(btree.range(key(0)..key(10))), vec![ (key(1), value(100)), (key(2), value(200)), @@ -2508,12 +2512,12 @@ mod test { // Tests an offset that has a keys somewhere in the range of keys of an internal node. assert_eq!( - btree.range(key(13)..key(20)).collect::>(), + collect(btree.range(key(13)..key(20))), vec![(key(13), value(700)), (key(14), value(800))] ); // Tests an offset that's larger than the key in the internal node. - assert_eq!(btree.range(key(25)..).collect::>(), vec![]); + assert_eq!(collect(btree.range(key(25)..)), vec![]); }); } btree_test!( @@ -2598,7 +2602,7 @@ mod test { // Tests a offset that crosses several nodes. assert_eq!( - btree.range(key(14)..key(20)).collect::>(), + collect(btree.range(key(14)..key(20))), vec![ (key(14), value(0)), (key(16), value(0)), @@ -2610,7 +2614,7 @@ mod test { // Tests a offset that starts from a leaf node, then iterates through the root and right // sibling. assert_eq!( - btree.range(key(22)..key(30)).collect::>(), + collect(btree.range(key(22)..key(30))), vec![ (key(22), value(0)), (key(23), value(0)), @@ -2695,17 +2699,6 @@ mod test { fn bruteforce_range_search() { let (key, value) = (|i| K::build(i), |i| V::build(i)); - - fn collect_kv<'a, K: Clone + 'a, V: Clone + 'a>( - iter: impl Iterator, - ) -> Vec<(K, V)> { - iter.map(|(k, v)| (k.clone(), v.clone())).collect() - } - - fn collect(it: impl Iterator) -> Vec<(K, V)> { - it.collect() - } - run_btree_test(|mut stable_map| { use std::collections::BTreeMap; const NKEYS: u32 = 60; From 50f1f0f4e943d3395f4d051295b72757ddf9662d Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 08:57:36 +0200 Subject: [PATCH 59/66] . --- src/btreemap.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/btreemap.rs b/src/btreemap.rs index cccb46f7..8a56368f 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1164,12 +1164,14 @@ mod test { use std::convert::TryFrom; use std::rc::Rc; + /// A helper function to clone and collect borrowed key/value pairs into a `Vec`. fn collect_kv<'a, K: Clone + 'a, V: Clone + 'a>( iter: impl Iterator, ) -> Vec<(K, V)> { iter.map(|(k, v)| (k.clone(), v.clone())).collect() } + /// A helper function to collect owned key/value pairs into a `Vec`. fn collect(it: impl Iterator) -> Vec<(K, V)> { it.collect() } From ac4250e2223b4f7dbcbd045b6310d5ee36d5daad Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 10:19:02 +0200 Subject: [PATCH 60/66] . --- src/btreemap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 8a56368f..11000a5e 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -2216,7 +2216,7 @@ mod test { btree.insert(key(0), value(0)); // Test a prefix that's larger than the value in the leaf node. Should be empty. - assert_eq!(btree.range(key(1)..).collect::>(), vec![]); + assert_eq!(collect(btree.range(key(1)..)), vec![]); }); } btree_test!( From e40272f17f6f33860b21420172d1dd61bdcda025 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 13:46:13 +0200 Subject: [PATCH 61/66] . --- src/btreemap.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 11000a5e..dadd5dd3 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1236,23 +1236,23 @@ mod test { } } - type MonotonicString32 = String; - impl Builder for MonotonicString32 { + type MonotonicVec32 = Vec; + impl Builder for MonotonicVec32 { fn build(i: u32) -> Self { - format!("{i:0>32}") + monotonic_buffer::<32>(i).to_vec() } fn empty() -> Self { - String::new() + Vec::new() } } - type MonotonicVec32 = Vec; - impl Builder for MonotonicVec32 { + type MonotonicString32 = String; + impl Builder for MonotonicString32 { fn build(i: u32) -> Self { - monotonic_buffer::<32>(i).to_vec() + format!("{i:0>32}") } fn empty() -> Self { - Vec::new() + String::new() } } @@ -1324,14 +1324,14 @@ mod test { // Set. verify_and_run!($runner, u32, ()); verify_and_run!($runner, Blob<10>, ()); - verify_and_run!($runner, MonotonicString32, ()); verify_and_run!($runner, MonotonicVec32, ()); + verify_and_run!($runner, MonotonicString32, ()); // Map. verify_and_run!($runner, u32, Blob<20>); verify_and_run!($runner, Blob<10>, Blob<20>); - verify_and_run!($runner, MonotonicString32, Blob<20>); verify_and_run!($runner, MonotonicVec32, Blob<20>); + verify_and_run!($runner, MonotonicString32, Blob<20>); } }; } From 9e725fb930912f6f1497f3dafd9a52189763a5ca Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 14:43:11 +0200 Subject: [PATCH 62/66] neat trick --- src/btreemap.rs | 70 ++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index dadd5dd3..e20b7cbf 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1345,7 +1345,7 @@ mod test { impl TestValue for T where T: Storable + Clone + Builder + std::fmt::Debug + PartialEq {} fn insert_get_init_preserves_data() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 1_000; for i in 0..n { @@ -1366,7 +1366,7 @@ mod test { ); fn insert_overwrites_previous_value() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 1_000; for i in 0..n { @@ -1382,7 +1382,7 @@ mod test { ); fn insert_same_key_many() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 1_000; assert_eq!(btree.insert(key(1), value(2)), None); @@ -1395,7 +1395,7 @@ mod test { btree_test!(test_insert_same_key_many, insert_same_key_many); fn insert_overwrite_median_key_in_full_child_node() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { for i in 1..=17 { assert_eq!(btree.insert(key(i), value(0)), None); @@ -1437,7 +1437,7 @@ mod test { ); fn insert_overwrite_key_in_full_root_node() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(key(i), value(0)), None); @@ -1464,7 +1464,7 @@ mod test { ); fn allocations_without_split() { - let key = |i| K::build(i); + let key = K::build; run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); @@ -1478,7 +1478,7 @@ mod test { btree_test!(test_allocations_without_split, allocations_without_split); fn allocations_with_split() { - let key = |i| K::build(i); + let key = K::build; run_btree_test(|mut btree| { // Insert entries until the root node is full. let mut i = 0; @@ -1503,7 +1503,7 @@ mod test { btree_test!(test_allocations_with_split, allocations_with_split); fn insert_split_node() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { for i in 1..=11 { assert_eq!(btree.insert(key(i), value(10)), None); @@ -1527,7 +1527,7 @@ mod test { btree_test!(test_insert_split_node, insert_split_node); fn insert_split_multiple_nodes() { - let key = |i| K::build(i); + let key = K::build; let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1612,7 +1612,7 @@ mod test { ); fn first_key_value() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree: BTreeMap| { assert_eq!(btree.first_key_value(), None); @@ -1634,7 +1634,7 @@ mod test { btree_test!(test_first_key_value, first_key_value); fn last_key_value() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree: BTreeMap| { assert_eq!(btree.last_key_value(), None); @@ -1656,7 +1656,7 @@ mod test { btree_test!(test_last_key_value, last_key_value); fn pop_first_single_entry() { - let key = |i| K::build(i); + let key = K::build; run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); @@ -1672,7 +1672,7 @@ mod test { btree_test!(test_pop_first_single_entry, pop_first_single_entry); fn pop_last_single_entry() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { assert_eq!(btree.allocator.num_allocated_chunks(), 0); @@ -1688,7 +1688,7 @@ mod test { btree_test!(test_pop_last_single_entry, pop_last_single_entry); fn remove_case_2a_and_2c() { - let key = |i| K::build(i); + let key = K::build; let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1756,7 +1756,7 @@ mod test { btree_test!(test_remove_case_2a_and_2c, remove_case_2a_and_2c); fn remove_case_2b() { - let key = |i| K::build(i); + let key = K::build; let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1818,7 +1818,7 @@ mod test { btree_test!(test_remove_case_2b, remove_case_2b); fn remove_case_3a_right() { - let key = |i| K::build(i); + let key = K::build; let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1866,7 +1866,7 @@ mod test { btree_test!(test_remove_case_3a_right, remove_case_3a_right); fn remove_case_3a_left() { - let key = |i| K::build(i); + let key = K::build; let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1913,7 +1913,7 @@ mod test { btree_test!(test_remove_case_3a_left, remove_case_3a_left); fn remove_case_3b_merge_into_right() { - let key = |i| K::build(i); + let key = K::build; let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -1985,7 +1985,7 @@ mod test { ); fn remove_case_3b_merge_into_left() { - let key = |i| K::build(i); + let key = K::build; let e = |i: u32| (key(i), encode(V::empty())); run_btree_test(|mut btree| { for i in 1..=11 { @@ -2059,7 +2059,7 @@ mod test { ); fn insert_remove_many() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 10_000; for i in 0..n { @@ -2080,7 +2080,7 @@ mod test { btree_test!(test_insert_remove_many, insert_remove_many); fn pop_first_many() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 10_000; @@ -2106,7 +2106,7 @@ mod test { btree_test!(test_pop_first_many, pop_first_many); fn pop_last_many() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 10_000; @@ -2132,7 +2132,7 @@ mod test { btree_test!(test_pop_last_many, pop_last_many); fn reloading() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 1_000; for i in 0..n { @@ -2162,7 +2162,7 @@ mod test { btree_test!(test_reloading, reloading); fn len() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 1_000; for i in 0..n { @@ -2183,7 +2183,7 @@ mod test { btree_test!(test_len, len); fn contains_key() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { let n = 1_000; for i in (0..n).step_by(2) { @@ -2199,7 +2199,7 @@ mod test { btree_test!(test_contains_key, contains_key); fn range_empty() { - let key = |i| K::build(i); + let key = K::build; run_btree_test(|btree: BTreeMap| { // Test prefixes that don't exist in the map. assert_eq!(collect(btree.range(key(0)..)), vec![]); @@ -2211,7 +2211,7 @@ mod test { // Tests the case where the prefix is larger than all the entries in a leaf node. fn range_leaf_prefix_greater_than_all_entries() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { btree.insert(key(0), value(0)); @@ -2226,7 +2226,7 @@ mod test { // Tests the case where the prefix is larger than all the entries in an internal node. fn range_internal_prefix_greater_than_all_entries() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { for i in 1..=12 { assert_eq!(btree.insert(key(i), value(i)), None); @@ -2250,7 +2250,7 @@ mod test { ); fn range_various_prefixes() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { btree.insert(key(1), value(100)); btree.insert(key(2), value(200)); @@ -2315,7 +2315,7 @@ mod test { btree_test!(test_range_various_prefixes, range_various_prefixes); fn range_various_prefixes_2() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { btree.insert(key(1), value(100)); btree.insert(key(2), value(200)); @@ -2443,7 +2443,7 @@ mod test { btree_test!(test_range_various_prefixes_2, range_various_prefixes_2); fn range_large() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { const TOTAL: u32 = 2_000; const MID: u32 = TOTAL / 2; @@ -2474,7 +2474,7 @@ mod test { btree_test!(test_range_large, range_large); fn range_various_prefixes_with_offset() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { btree.insert(key(1), value(100)); btree.insert(key(2), value(200)); @@ -2528,7 +2528,7 @@ mod test { ); fn range_various_prefixes_with_offset_2() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { btree.insert(key(1), value(0)); btree.insert(key(2), value(0)); @@ -2700,7 +2700,7 @@ mod test { } fn bruteforce_range_search() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut stable_map| { use std::collections::BTreeMap; const NKEYS: u32 = 60; @@ -2747,7 +2747,7 @@ mod test { btree_test!(test_bruteforce_range_search, bruteforce_range_search); fn test_iter_upper_bound() { - let (key, value) = (|i| K::build(i), |i| V::build(i)); + let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { for j in 0..100 { btree.insert(key(j), value(j)); From 58778105bd858f6bb77ce41318b38749f0d741cd Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 14:48:13 +0200 Subject: [PATCH 63/66] typo --- src/btreemap.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index e20b7cbf..66cdf7fb 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1506,13 +1506,13 @@ mod test { let (key, value) = (K::build, V::build); run_btree_test(|mut btree| { for i in 1..=11 { - assert_eq!(btree.insert(key(i), value(10)), None); + assert_eq!(btree.insert(key(i), value(i)), None); } // Should now split a node. let root = btree.load_node(btree.root_addr); assert!(root.is_full()); - assert_eq!(btree.insert(key(12), value(10)), None); + assert_eq!(btree.insert(key(12), value(12)), None); // The result should look like this: // [6] @@ -1520,7 +1520,7 @@ mod test { // [1, 2, 3, 4, 5] [7, 8, 9, 10, 11, 12] for i in 1..=12 { - assert_eq!(btree.get(&key(i)), Some(value(10))); + assert_eq!(btree.get(&key(i)), Some(value(i))); } }); } From f7e607dc2fe8674b3ed98c48f268779d17ee1dfc Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 14:54:57 +0200 Subject: [PATCH 64/66] v1 does not support unbounded types --- src/btreemap.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 66cdf7fb..c166fe1c 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1278,7 +1278,8 @@ mod test { V: Storable, F: Fn(BTreeMap) -> R, { - if K::BOUND != StorableBound::Unbounded { + // V1 does not support unbounded types. + if K::BOUND != StorableBound::Unbounded && V::BOUND != StorableBound::Unbounded { // Test with V1. let mem = make_memory(); let tree_v1 = BTreeMap::new_v1(mem); @@ -1321,17 +1322,23 @@ mod test { ($name:ident, $runner:ident) => { #[test] fn $name() { - // Set. + // Set, empty value. verify_and_run!($runner, u32, ()); verify_and_run!($runner, Blob<10>, ()); verify_and_run!($runner, MonotonicVec32, ()); verify_and_run!($runner, MonotonicString32, ()); - // Map. + // Map, bounded value. verify_and_run!($runner, u32, Blob<20>); verify_and_run!($runner, Blob<10>, Blob<20>); verify_and_run!($runner, MonotonicVec32, Blob<20>); verify_and_run!($runner, MonotonicString32, Blob<20>); + + // Map, unbounded value. + verify_and_run!($runner, u32, MonotonicVec32); + verify_and_run!($runner, Blob<10>, MonotonicVec32); + verify_and_run!($runner, MonotonicVec32, MonotonicVec32); + verify_and_run!($runner, MonotonicString32, MonotonicVec32); } }; } From 6362066a5467eac0beeb1e78d069707cef081030 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 14:55:56 +0200 Subject: [PATCH 65/66] . --- src/btreemap.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index c166fe1c..2a3e1d8b 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1329,10 +1329,10 @@ mod test { verify_and_run!($runner, MonotonicString32, ()); // Map, bounded value. - verify_and_run!($runner, u32, Blob<20>); - verify_and_run!($runner, Blob<10>, Blob<20>); - verify_and_run!($runner, MonotonicVec32, Blob<20>); - verify_and_run!($runner, MonotonicString32, Blob<20>); + verify_and_run!($runner, u32, u32); + verify_and_run!($runner, Blob<10>, u32); + verify_and_run!($runner, MonotonicVec32, u32); + verify_and_run!($runner, MonotonicString32, u32); // Map, unbounded value. verify_and_run!($runner, u32, MonotonicVec32); From 6e558f5904520959a6d47dce8dbbf90c78087462 Mon Sep 17 00:00:00 2001 From: Maksym Arutyunyan Date: Thu, 17 Apr 2025 15:04:14 +0200 Subject: [PATCH 66/66] . --- src/btreemap.rs | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/btreemap.rs b/src/btreemap.rs index 2a3e1d8b..7d7caa3a 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1322,23 +1322,37 @@ mod test { ($name:ident, $runner:ident) => { #[test] fn $name() { - // Set, empty value. - verify_and_run!($runner, u32, ()); - verify_and_run!($runner, Blob<10>, ()); - verify_and_run!($runner, MonotonicVec32, ()); - verify_and_run!($runner, MonotonicString32, ()); + use StorableBound::Unbounded; + + // Set, empty value, bounded. + { + type Value = (); + assert_ne!(::BOUND, Unbounded, "Must be Bounded"); + verify_and_run!($runner, u32, Value); + verify_and_run!($runner, Blob<10>, Value); + verify_and_run!($runner, MonotonicVec32, Value); + verify_and_run!($runner, MonotonicString32, Value); + } // Map, bounded value. - verify_and_run!($runner, u32, u32); - verify_and_run!($runner, Blob<10>, u32); - verify_and_run!($runner, MonotonicVec32, u32); - verify_and_run!($runner, MonotonicString32, u32); + { + type Value = u32; + assert_ne!(Value::BOUND, Unbounded, "Must be Bounded"); + verify_and_run!($runner, u32, Value); + verify_and_run!($runner, Blob<10>, Value); + verify_and_run!($runner, MonotonicVec32, Value); + verify_and_run!($runner, MonotonicString32, Value); + } // Map, unbounded value. - verify_and_run!($runner, u32, MonotonicVec32); - verify_and_run!($runner, Blob<10>, MonotonicVec32); - verify_and_run!($runner, MonotonicVec32, MonotonicVec32); - verify_and_run!($runner, MonotonicString32, MonotonicVec32); + { + type Value = MonotonicVec32; + assert_eq!(Value::BOUND, Unbounded, "Must be Unbounded"); + verify_and_run!($runner, u32, Value); + verify_and_run!($runner, Blob<10>, Value); + verify_and_run!($runner, MonotonicVec32, Value); + verify_and_run!($runner, MonotonicString32, Value); + } } }; }