use std::cmp::Ordering;
use crate::{
node::{Address, Balance, WouldUnderflow},
Node, Storage,
};
#[inline]
pub unsafe fn rebalance<T, S: Storage<T>>(
tree: &mut S,
mut root: Option<S::Node>,
mut id: S::Node,
mut addr: Address<S::Node>,
) -> (Option<S::Node>, Option<Address<S::Node>>) {
let mut balance = tree.get(id).balance();
let addr = loop {
match balance {
Balance::Balanced => break Some(addr),
Balance::Overflow => {
assert!(!tree.get_mut(id).is_underflowing());
let (median_offset, median, right_node) = tree.get_mut(id).split();
let right_id = tree.insert_node(right_node);
match tree.get(id).parent() {
Some(parent_id) => {
let parent = tree.get_mut(parent_id);
let offset = parent.child_index(id).unwrap().into();
parent.insert(offset, median, Some(right_id));
if addr.node == id {
match addr.offset.partial_cmp(&median_offset) {
Some(std::cmp::Ordering::Equal) => {
addr = Address {
node: parent_id,
offset,
}
}
Some(std::cmp::Ordering::Greater) => {
addr = Address {
node: right_id,
offset: (addr.offset.unwrap() - median_offset - 1).into(),
}
}
_ => (),
}
} else if addr.node == parent_id && addr.offset >= offset {
addr.offset.incr()
}
id = parent_id;
balance = parent.balance()
}
None => {
let left_id = id;
let new_root = Node::binary(None, left_id, median, right_id);
let root_id = tree.insert_node(new_root);
root = Some(root_id);
tree.get_mut(left_id).set_parent(Some(root_id));
tree.get_mut(right_id).set_parent(Some(root_id));
if addr.node == id {
match addr.offset.partial_cmp(&median_offset) {
Some(std::cmp::Ordering::Equal) => {
addr = Address {
node: root_id,
offset: 0.into(),
}
}
Some(std::cmp::Ordering::Greater) => {
addr = Address {
node: right_id,
offset: (addr.offset.unwrap() - median_offset - 1).into(),
}
}
_ => (),
}
}
break Some(addr);
}
};
}
Balance::Underflow(is_empty) => {
match tree.get(id).parent() {
Some(parent_id) => {
let index = tree.get(parent_id).child_index(id).unwrap();
if try_rotate_left(tree, parent_id, index, &mut addr)
|| try_rotate_right(tree, parent_id, index, &mut addr)
{
break Some(addr);
} else {
let (new_balance, new_addr) = merge(tree, parent_id, index, addr);
balance = new_balance;
addr = new_addr;
id = parent_id
}
}
None => {
let addr = if is_empty {
root = tree.get(id).child_id_opt(0);
let addr = match root {
Some(root) => {
let root_node = tree.get_mut(root);
root_node.set_parent(None);
if addr.node == id {
addr.node = root;
addr.offset = root_node.item_count().into()
}
Some(addr)
}
None => None,
};
tree.release_node(id);
addr
} else {
Some(addr)
};
break addr;
}
}
}
}
};
(root, addr)
}
#[inline]
unsafe fn try_rotate_left<T, S: Storage<T>>(
tree: &mut S,
id: S::Node,
deficient_child_index: usize,
addr: &mut Address<S::Node>,
) -> bool {
let pivot_offset = deficient_child_index.into();
let right_sibling_index = deficient_child_index + 1;
let (right_sibling_id, deficient_child_id) = {
let node = tree.get(id);
if right_sibling_index >= node.child_count() {
return false; }
(
node.child_id(right_sibling_index),
node.child_id(deficient_child_index),
)
};
match tree.get_mut(right_sibling_id).pop_left() {
Ok((mut value, opt_child_id)) => {
std::mem::swap(&mut value, tree.get_mut(id).item_mut(pivot_offset).unwrap());
let left_offset = tree
.get_mut(deficient_child_id)
.push_right(value, opt_child_id);
if let Some(child_id) = opt_child_id {
tree.get_mut(child_id).set_parent(Some(deficient_child_id))
}
if addr.node == right_sibling_id {
if addr.offset == 0 {
addr.node = id;
addr.offset = pivot_offset;
} else {
addr.offset.decr();
}
} else if addr.node == id {
if addr.offset == pivot_offset {
addr.node = deficient_child_id;
addr.offset = left_offset;
}
}
true }
Err(WouldUnderflow) => false, }
}
#[inline]
unsafe fn try_rotate_right<T, S: Storage<T>>(
tree: &mut S,
id: S::Node,
deficient_child_index: usize,
addr: &mut Address<S::Node>,
) -> bool {
if deficient_child_index > 0 {
let left_sibling_index = deficient_child_index - 1;
let pivot_offset = left_sibling_index.into();
let (left_sibling_id, deficient_child_id) = {
let node = tree.get(id);
(
node.child_id(left_sibling_index),
node.child_id(deficient_child_index),
)
};
match tree.get_mut(left_sibling_id).pop_right() {
Ok((left_offset, mut value, opt_child_id)) => {
std::mem::swap(&mut value, tree.get_mut(id).item_mut(pivot_offset).unwrap());
tree.get_mut(deficient_child_id)
.push_left(value, opt_child_id);
if let Some(child_id) = opt_child_id {
tree.get_mut(child_id).set_parent(Some(deficient_child_id))
}
if addr.node == deficient_child_id {
addr.offset.incr();
} else if addr.node == left_sibling_id {
if addr.offset == left_offset {
addr.node = id;
addr.offset = pivot_offset;
}
} else if addr.node == id {
if addr.offset == pivot_offset {
addr.node = deficient_child_id;
addr.offset = 0.into();
}
}
true }
Err(WouldUnderflow) => false, }
} else {
false }
}
#[inline]
unsafe fn merge<T, S: Storage<T>>(
tree: &mut S,
id: S::Node,
deficient_child_index: usize,
mut addr: Address<S::Node>,
) -> (Balance, Address<S::Node>) {
let (offset, left_id, right_id, separator, balance) = if deficient_child_index > 0 {
tree.get_mut(id).merge(deficient_child_index - 1)
} else {
tree.get_mut(id).merge(deficient_child_index)
};
let right_node = tree.release_node(right_id);
for right_child_id in right_node.children() {
tree.get_mut(right_child_id).set_parent(Some(left_id));
}
let left_offset = tree.get_mut(left_id).append(separator, right_node);
if addr.node == id {
match addr.offset.partial_cmp(&offset) {
Some(Ordering::Equal) => {
addr.node = left_id;
addr.offset = left_offset
}
Some(Ordering::Greater) => addr.offset.decr(),
_ => (),
}
} else if addr.node == right_id {
addr.node = left_id;
addr.offset = (addr.offset.unwrap() + left_offset.unwrap() + 1).into();
}
(balance, addr)
}