use super::super::{inter::*, leaf::*, node::*, *};
use super::{CounterI32, alive_count, reset_alive_count};
use core::cell::UnsafeCell;
#[test]
fn test_leaf_del_merge_with_left_height_2() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let min_count = (leaf_cap + 1) / 2;
assert!(min_count > 2);
let mut left_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
let mut middle_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
let mut right_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..min_count {
left_leaf.insert_no_split((i as i32 * 2).into(), (i as i32 * 10).into());
}
for i in 0..min_count {
let key = (min_count + i) as i32 * 2;
middle_leaf.insert_no_split(key.into(), ((min_count + i) as i32 * 10).into());
}
for i in 0..leaf_cap {
let key = (2 * min_count + i) as i32 * 2;
right_leaf.insert_no_split(key.into(), ((2 * min_count + i) as i32 * 10).into());
}
(*left_leaf.brothers()).next = middle_leaf.get_ptr();
(*middle_leaf.brothers()).prev = left_leaf.get_ptr();
(*middle_leaf.brothers()).next = right_leaf.get_ptr();
(*right_leaf.brothers()).prev = middle_leaf.get_ptr();
let middle_first_key = middle_leaf.get_keys()[0].clone();
let right_first_key = right_leaf.get_keys()[0].clone();
let left_last_key = left_leaf.get_keys()[left_leaf.key_count() as usize - 1].clone();
let mut root = InterNode::<CounterI32, CounterI32>::new_root(
1,
middle_first_key,
left_leaf.get_ptr(),
middle_leaf.get_ptr(),
);
root.insert_no_split(right_first_key.clone(), right_leaf.get_ptr());
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root)),
len: (2 * min_count + leaf_cap) as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 3,
#[cfg(feature = "trace_log")]
triggers: 0,
};
map.validate();
let middle_remaining_key = middle_leaf.get_keys()[0].clone();
println!("begin test");
let delete_key = (1 + min_count) as i32 * 2;
println!("remove {delete_key}");
assert!(map.remove(&delete_key).is_some());
map.validate();
let root = map.get_root_unwrap().as_inter();
assert_eq!(root.key_count(), 1); assert_eq!(map.len(), (2 * min_count - 1 + leaf_cap) as usize);
assert_eq!(
root.get_keys()[0],
right_first_key,
"Parent split key should change from middle_first_key to right_first_key after merge"
);
for i in 0..(min_count * 2 + leaf_cap) {
let key = i as i32 * 2;
if key != delete_key {
assert_eq!(
map.get(&key).map(|v| **v),
Some(i as i32 * 10),
"Original left leaf key {} should be accessible",
key
);
}
}
assert_eq!(
map.get(&middle_remaining_key).map(|v| **v),
Some(*middle_remaining_key * 10 / 2),
"Remaining middle leaf key {} should be merged into left leaf",
middle_remaining_key
);
assert!(
left_last_key < middle_remaining_key,
"Left last key should be less than merged middle key"
);
assert!(
middle_remaining_key < right_first_key,
"Merged middle key should be less than right first key"
);
assert_eq!(map.height(), 2);
assert_eq!(map.leaf_count, 2);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, TestFlag::LeafMergeLeft as u32 | TestFlag::RemoveChildMid as u32);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped");
}
#[test]
fn test_merge_left_with_right_height_2() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let min_count = (leaf_cap + 1) / 2;
assert!(min_count > 2);
let mut left_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
let mut middle_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
let mut right_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..leaf_cap {
let key = i as i32 * 2;
left_leaf.insert_no_split((i as i32 * 2).into(), (key * 10).into());
}
for i in 0..min_count {
let key = (leaf_cap + i) as i32 * 2;
middle_leaf.insert_no_split(key.into(), (key * 10).into());
}
for i in 0..min_count {
let key = (leaf_cap + min_count + i) as i32 * 2;
right_leaf.insert_no_split(key.into(), (key * 10).into());
}
(*left_leaf.brothers()).next = middle_leaf.get_ptr();
(*middle_leaf.brothers()).prev = left_leaf.get_ptr();
(*middle_leaf.brothers()).next = right_leaf.get_ptr();
(*right_leaf.brothers()).prev = middle_leaf.get_ptr();
let middle_first_key = middle_leaf.get_keys()[0].clone();
let right_first_key = right_leaf.get_keys()[0].clone();
let mut root = InterNode::<CounterI32, CounterI32>::alloc(1);
root.set_left_ptr(left_leaf.get_ptr());
root.insert_no_split(middle_first_key, middle_leaf.get_ptr());
root.insert_no_split(right_first_key.clone(), right_leaf.get_ptr());
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root)),
len: (leaf_cap + 2 * min_count) as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 3,
#[cfg(feature = "trace_log")]
triggers: 0,
};
map.validate();
let delete_key = (leaf_cap) as i32 * 2;
assert!(map.remove(&delete_key).is_some());
map.validate();
let root = map.get_root_unwrap().as_inter();
assert_eq!(root.key_count(), 1);
assert_eq!(map.len(), (leaf_cap + 2 * min_count - 1) as usize);
assert!(
root.get_keys()[0] != right_first_key,
"root sep key should changed, expected {}",
root.get_keys()[0]
);
for i in 0..(min_count * 2 + leaf_cap) {
let key = i as i32 * 2;
if key != delete_key {
assert_eq!(map.get(&key).map(|v| **v), Some(key * 10));
}
}
assert_eq!(map.height(), 2);
assert_eq!(map.leaf_count, 2);
#[cfg(feature = "trace_log")]
assert_eq!(
map.triggers,
TestFlag::LeafMergeRight as u32
| TestFlag::RemoveChildMid as u32
| TestFlag::UpdateSepKey as u32
);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped");
}
#[test]
fn test_leaf_del_merge_3_2_height_2() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let _min_count = (leaf_cap + 1) / 2;
let small_count = leaf_cap / 3;
if small_count == 0 {
return; }
println!("leaf_cap {leaf_cap}");
let mut left_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
let mut middle_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
let mut right_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..leaf_cap - 1 {
let key = i as i32 * 2;
left_leaf.insert_no_split(key.into(), (key * 10).into());
}
for i in 0..3 {
let key = (leaf_cap - 1 + i) as i32 * 2;
middle_leaf.insert_no_split(key.into(), (key * 10).into());
}
for i in 0..(leaf_cap - 1) {
let key = (leaf_cap - 1 + 3 + i) as i32 * 2;
right_leaf.insert_no_split(key.into(), (key * 10).into());
}
(*left_leaf.brothers()).next = middle_leaf.get_ptr();
(*middle_leaf.brothers()).prev = left_leaf.get_ptr();
(*middle_leaf.brothers()).next = right_leaf.get_ptr();
(*right_leaf.brothers()).prev = middle_leaf.get_ptr();
let middle_first_key = middle_leaf.get_keys()[0].clone();
let right_first_key = right_leaf.get_keys()[0].clone();
let mut root = InterNode::<CounterI32, CounterI32>::alloc(1);
root.set_left_ptr(left_leaf.get_ptr());
root.insert_no_split(middle_first_key, middle_leaf.get_ptr());
root.insert_no_split(right_first_key.clone(), right_leaf.get_ptr());
let total_keys = leaf_cap * 2 - 2 + 3;
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root.clone())),
len: total_keys as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 3,
#[cfg(feature = "trace_log")]
triggers: 0,
};
map.validate();
let delete_key = (leaf_cap - 1) as i32 * 2;
assert!(map.remove(&delete_key).is_some());
println!("delete key {delete_key}");
map.validate();
assert_eq!(map.len(), total_keys as usize - 1);
for i in 0..total_keys {
let key = i as i32 * 2;
if key != delete_key {
assert_eq!(map.get(&key).map(|v| **v), Some(key * 10), "key {key}");
} else {
assert_eq!(map.get(&key), None);
}
}
assert_eq!(root.get_keys()[0], (leaf_cap as i32 + 1) * 2);
assert!(root.get_keys()[0] != right_first_key);
assert_eq!(map.height(), 2);
assert_eq!(map.leaf_count, 2);
#[cfg(feature = "trace_log")]
assert_eq!(
map.triggers,
TestFlag::LeafMergeLeft as u32
| TestFlag::LeafMergeRight as u32
| TestFlag::RemoveChildMid as u32
| TestFlag::UpdateSepKey as u32
);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped");
}
#[test]
fn test_leaf_del_leftmost_merge_right_height_2() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let min_count = (leaf_cap + 1) / 2;
assert!(min_count > 2);
let mut left_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
let mut right_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..min_count {
left_leaf.insert_no_split((i as i32 * 2).into(), (i as i32 * 10).into());
}
for i in 0..min_count {
let key = (min_count + i) as i32 * 2;
right_leaf.insert_no_split(key.into(), ((min_count + i) as i32 * 10).into());
}
(*left_leaf.brothers()).next = right_leaf.get_ptr();
(*right_leaf.brothers()).prev = left_leaf.get_ptr();
let right_first_key = right_leaf.get_keys()[0].clone();
let left_first_key = left_leaf.get_keys()[0].clone();
let mut root = InterNode::<CounterI32, CounterI32>::alloc(1);
root.set_left_ptr(left_leaf.get_ptr());
root.insert_no_split(right_first_key.clone(), right_leaf.get_ptr());
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root)),
len: (2 * min_count) as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 2,
#[cfg(feature = "trace_log")]
triggers: 0,
};
map.validate();
assert_eq!(map.height(), 2);
for i in 1..min_count {
let key = i as i32 * 2;
assert!(map.remove(&key).is_some());
}
map.validate();
println!("alive count after remove: {}", alive_count());
assert_eq!(map.len(), (min_count + 1) as usize);
assert_eq!(
map.get(&left_first_key).map(|v| **v),
Some(*left_first_key * 10 / 2),
"Leftmost key {} should be accessible after merge",
left_first_key
);
for i in 0..min_count {
let key = (min_count + i) as i32 * 2;
assert_eq!(
map.get(&key).map(|v| **v),
Some(key * 5),
"Right leaf key {} should be accessible after merge",
key
);
}
for i in 0..min_count {
let right_key = (min_count + i) as i32 * 2;
assert!(
*left_first_key < right_key,
"Leftmost key {} should be less than right key {}",
left_first_key,
right_key
);
}
assert_eq!(map.height(), 1);
println!("before drop map, alive count: {}", alive_count());
assert_eq!(map.leaf_count, 1);
#[cfg(feature = "trace_log")]
assert_eq!(
map.triggers,
TestFlag::LeafMergeRight as u32 | TestFlag::RemoveChildFirst as u32
);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped");
}
#[test]
fn test_leaf_del_merge_left_with_rightmost_height_2() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let min_count = (leaf_cap + 1) / 2;
assert!(min_count > 2);
let mut left_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
let mut right_leaf = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..min_count {
left_leaf.insert_no_split((i as i32 * 2).into(), (i as i32 * 10).into());
}
for i in 0..min_count {
let key = (min_count + i) as i32 * 2;
right_leaf.insert_no_split(key.into(), ((min_count + i) as i32 * 10).into());
}
(*left_leaf.brothers()).next = right_leaf.get_ptr();
(*right_leaf.brothers()).prev = left_leaf.get_ptr();
let right_first_key = right_leaf.get_keys()[0].clone();
let left_last_key = left_leaf.get_keys()[left_leaf.key_count() as usize - 1].clone();
let mut root = InterNode::<CounterI32, CounterI32>::alloc(1);
root.set_left_ptr(left_leaf.get_ptr());
root.insert_no_split(right_first_key.clone(), right_leaf.get_ptr());
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root)),
len: (2 * min_count) as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 2,
#[cfg(feature = "trace_log")]
triggers: 0,
};
assert_eq!(map.height(), 2);
map.validate();
let right_remaining_key = right_leaf.get_keys()[0].clone();
for i in 1..min_count {
let key = (min_count + i) as i32 * 2;
assert!(map.remove(&key).is_some());
}
map.validate();
assert_eq!(map.len(), (min_count + 1) as usize);
for i in 0..min_count {
let key = i as i32 * 2;
assert_eq!(
map.get(&key).map(|v| **v),
Some(i as i32 * 10),
"Left leaf key {} should be accessible",
key
);
}
assert_eq!(
map.get(&right_remaining_key).map(|v| **v),
Some(*right_remaining_key * 10 / 2),
"Right leaf remaining key {} should be merged into left",
right_remaining_key
);
assert!(
*left_last_key < *right_remaining_key,
"Left last key {} should be less than right remaining key {}",
left_last_key,
right_remaining_key
);
assert_eq!(map.height(), 1);
assert_eq!(map.leaf_count, 1);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, TestFlag::LeafMergeLeft as u32 | TestFlag::RemoveChildLast as u32);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped");
}
#[test]
fn test_leaf_del_merge_with_left_height_3() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let min_count = (leaf_cap + 1) / 2;
assert!(min_count > 2);
let mut leaf_0 = LeafNode::<CounterI32, CounterI32>::alloc();
let mut leaf_1 = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..min_count {
leaf_0.insert_no_split((i as i32 * 2).into(), (i as i32 * 10).into());
}
for i in 0..min_count {
leaf_1.insert_no_split(
((min_count + i) as i32 * 2).into(),
((min_count + i) as i32 * 10).into(),
);
}
let mut leaf_2 = LeafNode::<CounterI32, CounterI32>::alloc();
let mut leaf_3 = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..min_count {
leaf_2.insert_no_split(
((2 * min_count + i) as i32 * 2).into(),
((2 * min_count + i) as i32 * 10).into(),
);
leaf_3.insert_no_split(
((3 * min_count + i) as i32 * 2).into(),
((3 * min_count + i) as i32 * 10).into(),
);
}
(*leaf_0.brothers()).next = leaf_1.get_ptr();
(*leaf_1.brothers()).prev = leaf_0.get_ptr();
(*leaf_1.brothers()).next = leaf_2.get_ptr();
(*leaf_2.brothers()).prev = leaf_1.get_ptr();
(*leaf_2.brothers()).next = leaf_3.get_ptr();
(*leaf_3.brothers()).prev = leaf_2.get_ptr();
let leaf1_first_key = leaf_1.get_keys()[0].clone();
let leaf2_first_key = leaf_2.get_keys()[0].clone();
let leaf3_first_key = leaf_3.get_keys()[0].clone();
let mut internal_left = InterNode::<CounterI32, CounterI32>::alloc(1);
internal_left.set_left_ptr(leaf_0.get_ptr());
internal_left.insert_no_split(leaf1_first_key, leaf_1.get_ptr());
let mut internal_right = InterNode::<CounterI32, CounterI32>::alloc(1);
internal_right.set_left_ptr(leaf_2.get_ptr());
internal_right.insert_no_split(leaf3_first_key, leaf_3.get_ptr());
let mut root = InterNode::<CounterI32, CounterI32>::alloc(2);
root.set_left_ptr(internal_left.get_ptr());
root.insert_no_split(leaf2_first_key.clone(), internal_right.get_ptr());
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root)),
len: (4 * min_count) as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 4,
#[cfg(feature = "trace_log")]
triggers: 0,
};
map.validate();
assert_eq!(map.height(), 3);
let leaf_1_remaining_key = leaf_1.get_keys()[0].clone();
let leaf_0_last_key = leaf_0.get_keys()[leaf_0.key_count() as usize - 1].clone();
for i in 1..min_count {
let key = (min_count + i) as i32 * 2;
assert!(map.remove(&key).is_some());
}
println!("removed");
map.validate();
assert_eq!(map.height(), 3);
assert_eq!(map.len(), (3 * min_count + 1) as usize);
assert_eq!(internal_left.key_count(), 0, "internal_left should have 1 child after merge");
let root_node = map.get_root_unwrap().as_inter();
assert_eq!(root_node.key_count(), 1, "Root should still have 2 children");
for i in 0..min_count {
let key = i as i32 * 2;
assert_eq!(
map.get(&key).map(|v| **v),
Some(i as i32 * 10),
"leaf_0 key {} should be accessible",
key
);
}
assert_eq!(
map.get(&leaf_1_remaining_key).map(|v| **v),
Some(*leaf_1_remaining_key * 10 / 2),
"leaf_1 remaining key {} should be merged into leaf_0",
leaf_1_remaining_key
);
assert!(
*leaf_0_last_key < *leaf_1_remaining_key,
"leaf_0 last key {} should be less than merged leaf_1 key {}",
leaf_0_last_key,
leaf_1_remaining_key
);
assert_eq!(map.leaf_count, 3);
#[cfg(feature = "trace_log")]
assert_eq!(map.triggers, TestFlag::LeafMergeLeft as u32 | TestFlag::RemoveChildLast as u32);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped");
}
#[test]
fn test_leaf_del_merge_with_right_height_3() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let min_count = (leaf_cap + 1) / 2;
assert!(min_count > 2);
let mut leaf_0 = LeafNode::<CounterI32, CounterI32>::alloc(); let mut leaf_1 = LeafNode::<CounterI32, CounterI32>::alloc(); let mut leaf_2 = LeafNode::<CounterI32, CounterI32>::alloc(); let mut leaf_3 = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..leaf_cap {
leaf_0.insert_no_split((i as i32 * 2).into(), (i as i32 * 10).into());
}
for i in 0..min_count {
let key = (leaf_cap + i) as i32 * 2;
leaf_1.insert_no_split(key.into(), (key * 10).into());
}
for i in 0..min_count {
let key = (leaf_cap + min_count + i) as i32 * 2;
leaf_2.insert_no_split(key.into(), (key * 10).into());
}
for i in 0..min_count {
let key = (leaf_cap + 2 * min_count + i) as i32 * 2;
leaf_3.insert_no_split(key.into(), (key * 10).into());
}
(*leaf_0.brothers()).next = leaf_1.get_ptr();
(*leaf_1.brothers()).prev = leaf_0.get_ptr();
(*leaf_1.brothers()).next = leaf_2.get_ptr();
(*leaf_2.brothers()).prev = leaf_1.get_ptr();
(*leaf_2.brothers()).next = leaf_3.get_ptr();
(*leaf_3.brothers()).prev = leaf_2.get_ptr();
let leaf_1_first_key = leaf_1.get_keys()[0].clone();
let leaf_2_first_key = leaf_2.get_keys()[0].clone();
let leaf_3_first_key = leaf_3.get_keys()[0].clone();
let mut internal_left = InterNode::<CounterI32, CounterI32>::alloc(1);
internal_left.set_left_ptr(leaf_0.get_ptr());
internal_left.insert_no_split(leaf_1_first_key, leaf_1.get_ptr());
let mut internal_right = InterNode::<CounterI32, CounterI32>::alloc(1);
internal_right.set_left_ptr(leaf_2.get_ptr());
internal_right.insert_no_split(leaf_3_first_key, leaf_3.get_ptr());
let root = InterNode::<CounterI32, CounterI32>::new_root(
2,
leaf_2_first_key.clone(),
internal_left.get_ptr(),
internal_right.get_ptr(),
);
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root)),
len: (leaf_cap + 3 * min_count) as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 4,
#[cfg(feature = "trace_log")]
triggers: 0,
};
assert_eq!(map.height(), 3);
println!("leaf_2_first_key = {}", leaf_2_first_key);
let delete_key = (leaf_cap + 1) as i32 * 2;
println!("delete_key = {}", delete_key);
assert!(map.remove(&delete_key).is_some());
map.validate();
assert_eq!(map.height(), 3);
assert_eq!(map.len(), (leaf_cap + 3 * min_count - 1) as usize);
for i in 0..leaf_cap {
let key = i as i32 * 2;
assert_eq!(
map.get(&key).map(|v| **v),
Some(i as i32 * 10),
"leaf_0 key {} should be accessible",
key
);
}
for i in 0..(3 * min_count) {
let key = (leaf_cap + i) as i32 * 2;
if key != delete_key {
let expected_value = key * 10;
assert_eq!(
map.get(&key).map(|v| **v),
Some(expected_value),
"key {} should be accessible after merge",
key
);
}
}
assert_eq!(map.leaf_count, 3);
#[cfg(feature = "trace_log")]
assert_eq!(
map.triggers,
TestFlag::LeafMergeRight as u32
| TestFlag::RemoveChildLast as u32
| TestFlag::UpdateSepKey as u32
);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped");
}
#[test]
fn test_leaf_del_merge_2_3_height_3() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let min_count = (leaf_cap + 1) / 2;
assert!(min_count > 2);
let mut leaf_0 = LeafNode::<CounterI32, CounterI32>::alloc(); let mut leaf_1 = LeafNode::<CounterI32, CounterI32>::alloc(); let mut leaf_2 = LeafNode::<CounterI32, CounterI32>::alloc(); let mut leaf_3 = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..leaf_cap {
let key = i as i32 * 2;
leaf_0.insert_no_split(key.into(), (key * 5).into());
}
for i in 0..(leaf_cap - 1) {
let key = (leaf_cap + i) as i32 * 2;
leaf_1.insert_no_split(key.into(), (key * 5).into());
}
for i in 0..3 {
let key = (leaf_cap + leaf_cap - 1 + i) as i32 * 2;
leaf_2.insert_no_split(key.into(), (key * 5).into());
}
for i in 0..(leaf_cap - 1) {
let key = (leaf_cap + leaf_cap - 1 + 3 + i) as i32 * 2;
leaf_3.insert_no_split(key.into(), (key * 5).into());
}
(*leaf_0.brothers()).next = leaf_1.get_ptr();
(*leaf_1.brothers()).prev = leaf_0.get_ptr();
(*leaf_1.brothers()).next = leaf_2.get_ptr();
(*leaf_2.brothers()).prev = leaf_1.get_ptr();
(*leaf_2.brothers()).next = leaf_3.get_ptr();
(*leaf_3.brothers()).prev = leaf_2.get_ptr();
let leaf_1_first_key = leaf_1.get_keys()[0].clone();
let leaf_2_first_key = leaf_2.get_keys()[0].clone();
let leaf_3_first_key = leaf_3.get_keys()[0].clone();
let mut internal_left = InterNode::<CounterI32, CounterI32>::alloc(1);
internal_left.set_left_ptr(leaf_0.get_ptr());
internal_left.insert_no_split(leaf_1_first_key, leaf_1.get_ptr());
let mut internal_right = InterNode::<CounterI32, CounterI32>::alloc(1);
internal_right.set_left_ptr(leaf_2.get_ptr());
internal_right.insert_no_split(leaf_3_first_key, leaf_3.get_ptr());
let root = InterNode::<CounterI32, CounterI32>::new_root(
2,
leaf_2_first_key.clone(),
internal_left.get_ptr(),
internal_right.get_ptr(),
);
let total_keys = leaf_cap + (leaf_cap - 1) + 3 + (leaf_cap - 1);
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root)),
len: total_keys as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 4,
#[cfg(feature = "trace_log")]
triggers: 0,
};
map.validate();
assert_eq!(map.height(), 3);
let delete_key = (leaf_cap + leaf_cap - 1 + 1) as i32 * 2;
println!("delete_key = {}", delete_key);
assert!(map.remove(&delete_key).is_some());
map.validate();
assert_eq!(map.len(), (total_keys - 1) as usize);
for i in 0..total_keys {
let key = i as i32 * 2;
if key != delete_key {
let expected_value = key * 5;
assert_eq!(
map.get(&key).map(|v| **v),
Some(expected_value),
"key {} should be accessible after merge",
key
);
}
}
assert_eq!(map.leaf_count, 3);
#[cfg(feature = "trace_log")]
assert_eq!(
map.triggers,
TestFlag::LeafMergeRight as u32
| TestFlag::LeafMergeLeft as u32
| TestFlag::RemoveChildFirst as u32
| TestFlag::UpdateSepKey as u32
);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped");
}
#[test]
fn test_leaf_del_remove_only_child_cascade() {
reset_alive_count();
unsafe {
let leaf_cap = LeafNode::<CounterI32, CounterI32>::cap();
let min_count = (leaf_cap + 1) / 2;
assert!(min_count > 2);
let mut leaf_left = LeafNode::<CounterI32, CounterI32>::alloc();
let mut leaf_mid = LeafNode::<CounterI32, CounterI32>::alloc();
let mut leaf_right = LeafNode::<CounterI32, CounterI32>::alloc();
for i in 0..leaf_cap {
let key = i as i32 * 2;
leaf_left.insert_no_split(key.into(), (key * 10).into());
}
for i in 0..min_count {
let key = (leaf_cap + i) as i32 * 2;
leaf_mid.insert_no_split(key.into(), (key * 10).into());
}
for i in 0..min_count {
let key = (leaf_cap + min_count + i) as i32 * 2;
leaf_right.insert_no_split(key.into(), (key * 10).into());
}
(*leaf_left.brothers()).next = leaf_mid.get_ptr();
(*leaf_mid.brothers()).prev = leaf_left.get_ptr();
(*leaf_mid.brothers()).next = leaf_right.get_ptr();
(*leaf_right.brothers()).prev = leaf_mid.get_ptr();
let leaf_mid_first_key = leaf_mid.get_keys()[0].clone();
let leaf_right_first_key = leaf_right.get_keys()[0].clone();
let mut inter_left1 = InterNode::<CounterI32, CounterI32>::alloc(1);
inter_left1.set_left_ptr(leaf_left.get_ptr());
let mut inter_min1 = InterNode::<CounterI32, CounterI32>::alloc(1);
inter_min1.set_left_ptr(leaf_mid.get_ptr());
let mut inter_right1 = InterNode::<CounterI32, CounterI32>::alloc(1);
inter_right1.set_left_ptr(leaf_right.get_ptr());
let mut inter_left = InterNode::<CounterI32, CounterI32>::alloc(2);
inter_left.set_left_ptr(inter_left1.get_ptr());
let mut inter_min = InterNode::<CounterI32, CounterI32>::alloc(2);
inter_min.set_left_ptr(inter_min1.get_ptr());
let mut inter_right = InterNode::<CounterI32, CounterI32>::alloc(2);
inter_right.set_left_ptr(inter_right1.get_ptr());
debug_assert_eq!(inter_right.key_count(), 0);
let mut root = InterNode::<CounterI32, CounterI32>::alloc(3);
root.set_left_ptr(inter_left.get_ptr());
root.insert_no_split(leaf_mid_first_key.clone(), inter_min.get_ptr());
root.insert_no_split(leaf_right_first_key.clone(), inter_right.get_ptr());
debug_assert_eq!(root.key_count(), 2);
let total_keys = leaf_cap + 2 * min_count;
let mut map = BTreeMap::<CounterI32, CounterI32> {
root: Some(Node::Inter(root)),
len: total_keys as usize,
cache: UnsafeCell::new(PathCache::new()),
leaf_count: 3,
#[cfg(feature = "trace_log")]
triggers: 0,
};
map.validate();
assert_eq!(map.height(), 4, "Initial tree height should be 4");
let delete_key = (leaf_cap + 1) as i32 * 2;
assert!(map.remove(&delete_key).is_some(), "Should remove key successfully");
map.validate();
assert_eq!(map.len(), (total_keys - 1) as usize, "Total keys should decrease by 1");
let root_node = map.get_root_unwrap().as_inter();
assert_eq!(
root_node.key_count(),
1,
"Root should have only 1 key (2 children) after remove_only_child cascade"
);
for i in 0..leaf_cap {
let key = i as i32 * 2;
assert_eq!(
map.get(&key).map(|v| **v),
Some(key * 10),
"leaf_left key {} should be accessible",
key
);
}
for i in 0..min_count {
let key = (leaf_cap + i) as i32 * 2;
if key != delete_key {
assert_eq!(
map.get(&key).map(|v| **v),
Some(key * 10),
"leaf_mid remaining key {} should be accessible after merge",
key
);
}
}
for i in 0..min_count {
let key = (leaf_cap + min_count + i) as i32 * 2;
assert_eq!(
map.get(&key).map(|v| **v),
Some(key * 10),
"leaf_right key {} should be accessible",
key
);
}
assert_eq!(map.leaf_count, 2);
#[cfg(feature = "trace_log")]
assert_eq!(
map.triggers,
TestFlag::RemoveOnlyChild as u32
| TestFlag::RemoveChildMid as u32
| TestFlag::LeafMergeRight as u32
| TestFlag::UpdateSepKey as u32
);
drop(map);
}
assert_eq!(alive_count(), 0, "All CounterI32 should be dropped after cleanup");
}