use crate::index::tree::{
IndexLimits, IndexOrd, PosRef, ToMergeCheck,
lock_group::LockItem,
nodes::{TreeNodeRef, block_counts_for_split},
path::{Path, PathItem, Position},
};
#[derive(Clone)]
enum Op {
Add(usize),
Remove,
Nothing,
}
#[derive(Clone)]
pub(crate) struct ChildChanged<K> {
item: PathItem<K>,
search_key: K,
operation: Op,
check_key: bool,
}
impl<K: Clone> ChildChanged<K> {
fn new(item: PathItem<K>, search_key: K, operation: Op, check_key: bool) -> Self {
Self {
item,
search_key,
operation,
check_key,
}
}
pub(crate) fn to_check(&self, parent: PosRef<K>) -> ToMergeCheck<K> {
ToMergeCheck::new(
parent,
self.item.pos_ref().clone(),
self.check_key || self.item.position() == Position::First,
)
}
pub(crate) fn search_key(&self) -> &K {
&self.search_key
}
pub(crate) fn replace_item(&mut self, item: PathItem<K>) {
self.item = item;
}
pub(crate) fn item(&self) -> &PathItem<K> {
&self.item
}
}
pub(crate) struct ParentChange<K> {
path: Path<K>,
children: Vec<ChildChanged<K>>,
remove: usize,
add: usize,
change_prev_key: bool,
change_next_key: bool,
}
impl<K: IndexOrd + Clone> ParentChange<K> {
pub(crate) fn new_children(path: Path<K>, children: Vec<ChildChanged<K>>) -> Self {
debug_assert!(!path.is_empty());
let mut add = 0;
let mut remove = 0;
let mut is_same_prev_key = false;
let mut is_same_next_key = false;
for child in &children {
if path.last_position() == Position::First || child.check_key {
is_same_prev_key = true;
}
if child.item.position() == Position::Last {
is_same_next_key = true;
}
match child.operation {
Op::Add(counts) => add += counts,
Op::Remove => remove += 1,
Op::Nothing => (),
}
}
Self {
path,
children,
remove,
add,
change_prev_key: is_same_prev_key,
change_next_key: is_same_next_key,
}
}
pub(crate) fn replace(&mut self, path: Path<K>, children: Vec<ChildChanged<K>>) {
debug_assert!(!path.is_empty());
let mut add = 0;
let mut remove = 0;
let mut is_same_prev_key = false;
let mut is_same_next_key = false;
for child in &children {
if child.item.position() == Position::First || child.check_key {
is_same_prev_key = true;
}
if child.item.position() == Position::Last {
is_same_next_key = true;
}
match child.operation {
Op::Add(counts) => add += counts,
Op::Remove => remove += 1,
Op::Nothing => (),
}
}
self.path = path;
self.children = children;
self.add = add;
self.remove = remove;
self.change_prev_key = is_same_prev_key;
self.change_next_key = is_same_next_key;
}
pub(crate) fn new_child(child: &LockItem<K>, limits: &IndexLimits) -> Self {
let mut path = child.path().clone();
path.pop();
debug_assert!(!path.is_empty());
let mut inst = Self {
path,
children: Vec::new(),
add: 0,
remove: 0,
change_prev_key: false,
change_next_key: false,
};
inst.add_child(child, limits);
inst
}
pub(crate) fn add_child(&mut self, child: &LockItem<K>, limits: &IndexLimits) {
if child.path().last_position() == Position::First || child.check_key() {
self.change_prev_key = true;
true
} else {
false
};
let check_key = child.check_key();
if child.path().last_position() == Position::Last {
self.change_next_key = true;
}
let operation = if child.len() < limits.bottom() {
self.remove += 1;
Op::Remove
} else if child.len() > limits.top() {
let add = block_counts_for_split(child.len(), limits.top());
self.add += add;
Op::Add(add)
} else {
Op::Nothing
};
self.children.push(ChildChanged::new(
child.path().last().cloned().unwrap(),
child.path().search_key().clone(),
operation,
check_key,
));
}
pub fn to_lock(&self) -> bool {
self.add != 0 || self.remove != 0 || self.change_prev_key || self.change_next_key
}
pub(crate) fn id(&self) -> TreeNodeRef {
self.path.last_id().unwrap()
}
pub(crate) fn children_checks(&self) -> Vec<ToMergeCheck<K>> {
let parent = self.path.last_pos_ref().unwrap();
self.children
.iter()
.map(|i| i.to_check(parent.clone()))
.collect::<Vec<_>>()
}
pub(crate) fn path(&self) -> &Path<K> {
&self.path
}
pub fn add_count(&self) -> usize {
self.add
}
pub fn remove_count(&self) -> usize {
self.remove
}
pub fn change_prev_key(&self) -> bool {
self.change_prev_key
}
pub(crate) fn children(&self) -> &Vec<ChildChanged<K>> {
&self.children
}
}