use super::*;
use captains_log::logfn;
use rstest::rstest;
#[logfn]
#[rstest]
fn test_inter_underflow_merge_right_height_3_2(setup_log: ()) {
reset_alive_count();
let mut builder = TreeBuilder::<CounterI32, CounterI32>::default();
{
let mut leaf_1 = builder.new_leaf();
let mut leaf_2 = builder.new_leaf();
let mut leaf_3 = builder.new_leaf();
let mut leaf_4 = builder.new_leaf();
for i in 0..3 {
builder.insert_leaf(&mut leaf_1, CounterI32::new(i * 2), CounterI32::new(i * 10));
builder.insert_leaf(
&mut leaf_2,
CounterI32::new((10 + i) * 2),
CounterI32::new((10 + i) * 10),
);
builder.insert_leaf(
&mut leaf_3,
CounterI32::new((20 + i) * 2),
CounterI32::new((20 + i) * 10),
);
builder.insert_leaf(
&mut leaf_4,
CounterI32::new((30 + i) * 2),
CounterI32::new((30 + i) * 10),
);
}
let leaf_1_first = leaf_1.get_keys()[0].clone();
let leaf_2_first = leaf_2.get_keys()[0].clone();
let leaf_3_first = leaf_3.get_keys()[0].clone();
let mut internal_a = builder.new_inter(1);
internal_a.set_left_ptr(leaf_1.get_ptr());
internal_a.insert_no_split(leaf_2_first, leaf_2.get_ptr());
debug_assert_eq!(internal_a.key_count(), 1);
let mut internal_b = builder.new_inter(1);
internal_b.set_left_ptr(leaf_3.get_ptr());
internal_b.insert_no_split(leaf_4.get_keys()[0].clone(), leaf_4.get_ptr());
debug_assert_eq!(internal_b.key_count(), 1);
let mut root = builder.new_inter(2);
root.set_left_ptr(internal_a.get_ptr());
root.insert_no_split(leaf_3_first, internal_b.get_ptr());
debug_assert_eq!(root.key_count(), 1);
let alive_before = alive_count();
println!("Alive count before handle_inter_underflow: {}", alive_before);
let mut map = builder.build(root.into());
assert_eq!(map.len(), 12);
map.validate();
assert_eq!(map.height(), 3);
let cache = map.clear_cache();
let _ = map.get_root_unwrap().into_inter().find_leaf_with_cache(cache, &leaf_1_first);
let (popped_node, _) = cache.pop().unwrap();
debug_assert_eq!(popped_node.height(), 1);
debug_assert_eq!(popped_node.key_count(), 1);
assert_eq!(popped_node, internal_a);
map.handle_inter_underflow(internal_a);
map.validate();
assert_eq!(map.height(), 2, "Tree height should be 2 after merge");
for i in 0..3 {
assert!(map.contains_key(&CounterI32::new(i * 2)), "Key {} should exist", i * 2);
assert!(
map.contains_key(&CounterI32::new((10 + i) * 2)),
"Key {} should exist",
(10 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((20 + i) * 2)),
"Key {} should exist",
(20 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((30 + i) * 2)),
"Key {} should exist",
(30 + i) * 2
);
}
assert_eq!(map.height(), 2);
assert_eq!(map.leaf_count(), 4);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, TestFlag::InterMergeRight as u32);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped after cleanup");
}
#[logfn]
#[rstest]
fn test_inter_underflow_merge_left_height_3_2(setup_log: ()) {
reset_alive_count();
let mut builder = TreeBuilder::<CounterI32, CounterI32>::default();
{
let mut leaf_1 = builder.new_leaf();
let mut leaf_2 = builder.new_leaf();
let mut leaf_3 = builder.new_leaf();
let mut leaf_4 = builder.new_leaf();
for i in 0..3 {
builder.insert_leaf(&mut leaf_1, CounterI32::new(i * 2), CounterI32::new(i * 10));
builder.insert_leaf(
&mut leaf_2,
CounterI32::new((10 + i) * 2),
CounterI32::new((10 + i) * 10),
);
builder.insert_leaf(
&mut leaf_3,
CounterI32::new((20 + i) * 2),
CounterI32::new((20 + i) * 10),
);
builder.insert_leaf(
&mut leaf_4,
CounterI32::new((30 + i) * 2),
CounterI32::new((30 + i) * 10),
);
}
let _leaf_1_first = leaf_1.get_keys()[0].clone();
let leaf_2_first = leaf_2.get_keys()[0].clone();
let leaf_3_first = leaf_3.get_keys()[0].clone();
let mut internal_a = builder.new_inter(1);
internal_a.set_left_ptr(leaf_1.get_ptr());
internal_a.insert_no_split(leaf_2_first, leaf_2.get_ptr());
debug_assert_eq!(internal_a.key_count(), 1);
let mut internal_b = builder.new_inter(1);
internal_b.set_left_ptr(leaf_3.get_ptr());
internal_b.insert_no_split(leaf_4.get_keys()[0].clone(), leaf_4.get_ptr());
debug_assert_eq!(internal_b.key_count(), 1);
let mut root = builder.new_inter(2);
root.set_left_ptr(internal_a.get_ptr());
root.insert_no_split(leaf_3_first, internal_b.get_ptr());
debug_assert_eq!(root.key_count(), 1);
let mut map = builder.build(root.into());
assert_eq!(map.len(), 12);
map.validate();
assert_eq!(map.height(), 3);
let cache = map.clear_cache();
let leaf_3_lookup = &leaf_3.get_keys()[0];
let _ = map.get_root_unwrap().into_inter().find_leaf_with_cache(cache, leaf_3_lookup);
let (popped_node, _) = cache.pop().unwrap();
debug_assert_eq!(popped_node.height(), 1);
debug_assert_eq!(popped_node.key_count(), 1);
assert_eq!(popped_node, internal_b);
map.handle_inter_underflow(internal_b);
map.validate();
assert_eq!(map.height(), 2, "Tree height should be 2 after merge");
for i in 0..3 {
assert!(map.contains_key(&CounterI32::new(i * 2)), "Key {} should exist", i * 2);
assert!(
map.contains_key(&CounterI32::new((10 + i) * 2)),
"Key {} should exist",
(10 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((20 + i) * 2)),
"Key {} should exist",
(20 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((30 + i) * 2)),
"Key {} should exist",
(30 + i) * 2
);
}
assert_eq!(map.height(), 2);
assert_eq!(map.leaf_count(), 4);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, TestFlag::InterMergeLeft as u32);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped after cleanup");
}
#[logfn]
#[rstest]
fn test_inter_underflow_merge_right_height_3(setup_log: ()) {
reset_alive_count();
let mut builder = TreeBuilder::<CounterI32, CounterI32>::default();
{
let mut leaf_1 = builder.new_leaf();
let mut leaf_2 = builder.new_leaf();
let mut leaf_3 = builder.new_leaf();
let mut leaf_4 = builder.new_leaf();
let mut leaf_5 = builder.new_leaf();
let mut leaf_6 = builder.new_leaf();
for i in 0..3 {
builder.insert_leaf(&mut leaf_1, CounterI32::new(i * 2), CounterI32::new(i * 10));
builder.insert_leaf(
&mut leaf_2,
CounterI32::new((10 + i) * 2),
CounterI32::new((10 + i) * 10),
);
builder.insert_leaf(
&mut leaf_3,
CounterI32::new((20 + i) * 2),
CounterI32::new((20 + i) * 10),
);
builder.insert_leaf(
&mut leaf_4,
CounterI32::new((30 + i) * 2),
CounterI32::new((30 + i) * 10),
);
builder.insert_leaf(
&mut leaf_5,
CounterI32::new((40 + i) * 2),
CounterI32::new((40 + i) * 10),
);
builder.insert_leaf(
&mut leaf_6,
CounterI32::new((50 + i) * 2),
CounterI32::new((50 + i) * 10),
);
}
let _leaf_1_first = leaf_1.get_keys()[0].clone();
let leaf_2_first = leaf_2.get_keys()[0].clone();
let leaf_3_first = leaf_3.get_keys()[0].clone();
let leaf_4_first = leaf_4.get_keys()[0].clone();
let leaf_5_first = leaf_5.get_keys()[0].clone();
let leaf_6_first = leaf_6.get_keys()[0].clone();
let mut internal_a = builder.new_inter(1);
internal_a.set_left_ptr(leaf_1.get_ptr());
internal_a.insert_no_split(leaf_2_first, leaf_2.get_ptr());
debug_assert_eq!(internal_a.key_count(), 1);
let mut internal_b = builder.new_inter(1);
internal_b.set_left_ptr(leaf_3.get_ptr());
internal_b.insert_no_split(leaf_4_first, leaf_4.get_ptr());
debug_assert_eq!(internal_b.key_count(), 1);
let mut internal_c = builder.new_inter(1);
internal_c.set_left_ptr(leaf_5.get_ptr());
internal_c.insert_no_split(leaf_6_first, leaf_6.get_ptr());
debug_assert_eq!(internal_c.key_count(), 1);
let mut root = builder.new_inter(2);
root.set_left_ptr(internal_a.get_ptr());
root.insert_no_split(leaf_3_first, internal_b.get_ptr());
root.insert_no_split(leaf_5_first, internal_c.get_ptr());
debug_assert_eq!(root.key_count(), 2);
let mut map = builder.build(root.into());
assert_eq!(map.len(), 18);
map.validate();
assert_eq!(map.height(), 3, "Tree height should remain 3");
let cache = map.clear_cache();
let _ =
map.get_root_unwrap().into_inter().find_leaf_with_cache(cache, &leaf_1.get_keys()[0]);
let (popped_node, _) = cache.pop().unwrap();
assert_eq!(popped_node, internal_a);
debug_assert_eq!(popped_node.height(), 1);
debug_assert_eq!(popped_node.key_count(), 1);
map.handle_inter_underflow(internal_a);
map.validate();
assert_eq!(map.height(), 3, "Tree height should remain 3");
for i in 0..3 {
assert!(map.contains_key(&CounterI32::new(i * 2)), "Key {} should exist", i * 2);
assert!(
map.contains_key(&CounterI32::new((10 + i) * 2)),
"Key {} should exist",
(10 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((20 + i) * 2)),
"Key {} should exist",
(20 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((30 + i) * 2)),
"Key {} should exist",
(30 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((40 + i) * 2)),
"Key {} should exist",
(40 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((50 + i) * 2)),
"Key {} should exist",
(50 + i) * 2
);
assert_eq!(map.leaf_count(), 6);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, TestFlag::InterMergeRight as u32);
}
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped after cleanup");
}
#[logfn]
#[rstest]
fn test_inter_underflow_merge_left_height_3(setup_log: ()) {
reset_alive_count();
let mut builder = TreeBuilder::<CounterI32, CounterI32>::default();
{
let mut leaf_1 = builder.new_leaf();
let mut leaf_2 = builder.new_leaf();
let mut leaf_3 = builder.new_leaf();
let mut leaf_4 = builder.new_leaf();
let mut leaf_5 = builder.new_leaf();
let mut leaf_6 = builder.new_leaf();
for i in 0..3 {
builder.insert_leaf(&mut leaf_1, CounterI32::new(i * 2), CounterI32::new(i * 10));
builder.insert_leaf(
&mut leaf_2,
CounterI32::new((10 + i) * 2),
CounterI32::new((10 + i) * 10),
);
builder.insert_leaf(
&mut leaf_3,
CounterI32::new((20 + i) * 2),
CounterI32::new((20 + i) * 10),
);
builder.insert_leaf(
&mut leaf_4,
CounterI32::new((30 + i) * 2),
CounterI32::new((30 + i) * 10),
);
builder.insert_leaf(
&mut leaf_5,
CounterI32::new((40 + i) * 2),
CounterI32::new((40 + i) * 10),
);
builder.insert_leaf(
&mut leaf_6,
CounterI32::new((50 + i) * 2),
CounterI32::new((50 + i) * 10),
);
}
let _leaf_1_first = leaf_1.get_keys()[0].clone();
let leaf_2_first = leaf_2.get_keys()[0].clone();
let leaf_3_first = leaf_3.get_keys()[0].clone();
let leaf_4_first = leaf_4.get_keys()[0].clone();
let leaf_5_first = leaf_5.get_keys()[0].clone();
let leaf_6_first = leaf_6.get_keys()[0].clone();
let mut internal_a = builder.new_inter(1);
internal_a.set_left_ptr(leaf_1.get_ptr());
internal_a.insert_no_split(leaf_2_first, leaf_2.get_ptr());
debug_assert_eq!(internal_a.key_count(), 1);
let mut internal_b = builder.new_inter(1);
internal_b.set_left_ptr(leaf_3.get_ptr());
internal_b.insert_no_split(leaf_4_first, leaf_4.get_ptr());
debug_assert_eq!(internal_b.key_count(), 1);
let mut internal_c = builder.new_inter(1);
internal_c.set_left_ptr(leaf_5.get_ptr());
internal_c.insert_no_split(leaf_6_first, leaf_6.get_ptr());
debug_assert_eq!(internal_c.key_count(), 1);
let mut root = builder.new_inter(2);
root.set_left_ptr(internal_a.get_ptr());
root.insert_no_split(leaf_3_first, internal_b.get_ptr());
root.insert_no_split(leaf_5_first, internal_c.get_ptr());
debug_assert_eq!(root.key_count(), 2);
let mut map = builder.build(root.into());
assert_eq!(map.len(), 18);
map.validate();
assert_eq!(map.height(), 3, "Tree height should remain 3");
let cache = map.clear_cache();
let leaf_3_lookup = &leaf_3.get_keys()[0];
let _ = map.get_root_unwrap().into_inter().find_leaf_with_cache(cache, leaf_3_lookup);
let (popped_node, _) = cache.pop().unwrap();
debug_assert_eq!(popped_node.height(), 1);
debug_assert_eq!(popped_node.key_count(), 1);
assert_eq!(popped_node, internal_b);
map.handle_inter_underflow(internal_b);
map.validate();
assert_eq!(map.height(), 3, "Tree height should remain 3");
for i in 0..3 {
assert!(map.contains_key(&CounterI32::new(i * 2)), "Key {} should exist", i * 2);
assert!(
map.contains_key(&CounterI32::new((10 + i) * 2)),
"Key {} should exist",
(10 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((20 + i) * 2)),
"Key {} should exist",
(20 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((30 + i) * 2)),
"Key {} should exist",
(30 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((40 + i) * 2)),
"Key {} should exist",
(40 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((50 + i) * 2)),
"Key {} should exist",
(50 + i) * 2
);
assert_eq!(map.leaf_count(), 6);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, TestFlag::InterMergeLeft as u32);
}
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped after cleanup");
}
#[logfn]
#[rstest]
fn test_inter_underflow_root_becomes_leaf(setup_log: ()) {
reset_alive_count();
let mut builder = TreeBuilder::<CounterI32, CounterI32>::default();
{
let mut leaf_1 = builder.new_leaf();
for i in 0..3 {
builder.insert_leaf(&mut leaf_1, CounterI32::new(i * 2), CounterI32::new(i * 10));
}
let leaf_1_first = leaf_1.get_keys()[0].clone();
let mut internal_b = builder.new_inter(1);
internal_b.set_left_ptr(leaf_1.get_ptr());
debug_assert_eq!(internal_b.key_count(), 0);
let mut internal_a = builder.new_inter(2);
internal_a.set_left_ptr(internal_b.get_ptr());
debug_assert_eq!(internal_a.key_count(), 0);
let mut root = builder.new_inter(3);
root.set_left_ptr(internal_a.get_ptr());
debug_assert_eq!(root.key_count(), 0);
let mut map = builder.build(root.into());
assert_eq!(map.len(), 3);
map.validate();
assert_eq!(map.height(), 4);
let cache = map.clear_cache();
let _ = map.get_root_unwrap().into_inter().find_leaf_with_cache(cache, &leaf_1_first);
let (popped_node, _) = cache.pop().unwrap();
assert_eq!(popped_node, internal_b);
debug_assert_eq!(popped_node.height(), 1);
debug_assert_eq!(popped_node.key_count(), 0);
map.handle_inter_underflow(internal_b);
map.validate();
assert_eq!(map.height(), 1, "Root should become leaf after cascade merge");
for i in 0..3 {
assert!(map.contains_key(&CounterI32::new(i * 2)), "Key {} should exist", i * 2);
}
assert_eq!(map.leaf_count(), 1);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, 0);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped after cleanup");
}
#[logfn]
#[rstest]
fn test_inter_underflow_single_leaf_inter_nodes_height_3(setup_log: ()) {
reset_alive_count();
let mut builder = TreeBuilder::<CounterI32, CounterI32>::default();
{
let mut leaf_1 = builder.new_leaf();
let mut leaf_2 = builder.new_leaf();
let mut leaf_3 = builder.new_leaf();
for i in 0..3 {
builder.insert_leaf(&mut leaf_1, CounterI32::new(i * 2), CounterI32::new(i * 10));
builder.insert_leaf(
&mut leaf_2,
CounterI32::new((10 + i) * 2),
CounterI32::new((10 + i) * 10),
);
builder.insert_leaf(
&mut leaf_3,
CounterI32::new((20 + i) * 2),
CounterI32::new((20 + i) * 10),
);
}
let leaf_1_first = leaf_1.get_keys()[0].clone();
let leaf_2_first = leaf_2.get_keys()[0].clone();
let leaf_3_first = leaf_3.get_keys()[0].clone();
let mut internal_a = builder.new_inter(1);
internal_a.set_left_ptr(leaf_1.get_ptr());
debug_assert_eq!(internal_a.key_count(), 0);
let mut internal_b = builder.new_inter(1);
internal_b.set_left_ptr(leaf_2.get_ptr());
debug_assert_eq!(internal_b.key_count(), 0);
let mut internal_c = builder.new_inter(1);
internal_c.set_left_ptr(leaf_3.get_ptr());
debug_assert_eq!(internal_c.key_count(), 0);
let mut root = builder.new_inter(2);
root.set_left_ptr(internal_a.get_ptr());
root.insert_no_split(leaf_2_first, internal_b.get_ptr());
root.insert_no_split(leaf_3_first, internal_c.get_ptr());
debug_assert_eq!(root.key_count(), 2);
let mut map = builder.build(root.into());
assert_eq!(map.len(), 9);
map.validate();
assert_eq!(map.height(), 3, "Tree height should be 3");
let cache = map.clear_cache();
let _ = map.get_root_unwrap().into_inter().find_leaf_with_cache(cache, &leaf_1_first);
let (popped_node, _) = cache.pop().unwrap();
assert_eq!(popped_node, internal_a);
debug_assert_eq!(popped_node.height(), 1);
debug_assert_eq!(popped_node.key_count(), 0);
let alive_before = alive_count();
println!("Alive count before handle_inter_underflow: {}", alive_before);
map.handle_inter_underflow(internal_a);
map.validate();
assert_eq!(map.height(), 3, "Tree height should remain 3");
println!("Alive count after handle_inter_underflow: {}", alive_count());
for i in 0..3 {
assert!(map.contains_key(&CounterI32::new(i * 2)), "Key {} should exist", i * 2);
assert!(
map.contains_key(&CounterI32::new((10 + i) * 2)),
"Key {} should exist",
(10 + i) * 2
);
assert!(
map.contains_key(&CounterI32::new((20 + i) * 2)),
"Key {} should exist",
(20 + i) * 2
);
}
assert_eq!(map.leaf_count(), 3);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, 0);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped after cleanup");
}