use super::error::{BrineTreeError, ProgramResult};
#[inline]
pub fn check_condition(condition: bool, err: BrineTreeError) -> ProgramResult {
if condition {
Ok(())
} else {
Err(err)
}
}
pub fn first_index_in_layer(layer: usize, height: usize) -> usize {
if layer == 0 {
0
} else {
(1usize << (height + 1)) - (1usize << (height + 1 - layer))
}
}
pub fn find_ancestor(target_layer: usize, node_index: usize, height: usize) -> usize {
assert!(target_layer <= height, "target_layer exceeds tree height");
let mut src_layer = 0usize;
while src_layer < height && node_index >= first_index_in_layer(src_layer + 1, height) {
src_layer += 1;
}
assert!(
target_layer >= src_layer,
"target_layer must be >= the node's current layer (ancestor lookup)"
);
let pos_in_src = node_index - first_index_in_layer(src_layer, height);
let up = target_layer - src_layer;
first_index_in_layer(target_layer, height) + (pos_in_src >> up)
}
pub fn descendant_range(node_index: usize, target_layer: usize, height: usize) -> (usize, usize) {
assert!(target_layer <= height, "target_layer exceeds tree height");
let last_index = (1usize << (height + 1)) - 2;
assert!(
node_index <= last_index,
"node_index out of range for given height"
);
let mut src_layer = 0usize;
while src_layer < height && node_index >= first_index_in_layer(src_layer + 1, height) {
src_layer += 1;
}
assert!(
target_layer <= src_layer,
"target_layer must be <= the node's current layer (descendant lookup)"
);
let pos_in_src = node_index - first_index_in_layer(src_layer, height);
let down = src_layer - target_layer;
let count = 1usize << down;
let start = first_index_in_layer(target_layer, height) + (pos_in_src << down);
(start, count)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn group_to_parents_layer1_height_3() {
assert_eq!(find_ancestor(1, 0, 3), 8);
assert_eq!(find_ancestor(1, 1, 3), 8);
assert_eq!(find_ancestor(1, 2, 3), 9);
assert_eq!(find_ancestor(1, 3, 3), 9);
assert_eq!(find_ancestor(1, 4, 3), 10);
assert_eq!(find_ancestor(1, 5, 3), 10);
assert_eq!(find_ancestor(1, 6, 3), 11);
assert_eq!(find_ancestor(1, 7, 3), 11);
}
#[test]
fn group_to_parents_layer2_height_3() {
assert_eq!(find_ancestor(2, 8, 3), 12);
assert_eq!(find_ancestor(2, 9, 3), 12);
assert_eq!(find_ancestor(2, 10, 3), 13);
assert_eq!(find_ancestor(2, 11, 3), 13);
}
#[test]
fn all_to_root_height_3() {
for idx in 0..=14 {
assert_eq!(find_ancestor(3, idx, 3), 14);
}
}
#[test]
fn same_layer_identity_height_3() {
assert_eq!(find_ancestor(0, 5, 3), 5);
assert_eq!(find_ancestor(1, 8, 3), 8);
assert_eq!(find_ancestor(2, 13, 3), 13);
assert_eq!(find_ancestor(3, 14, 3), 14);
}
fn expand((start, count): (usize, usize)) -> Vec<usize> {
(start..start + count).collect()
}
#[test]
fn left_and_right_subtrees_height_3() {
assert_eq!(descendant_range(12, 0, 3), (0, 4));
assert_eq!(expand(descendant_range(12, 0, 3)), (0..4).collect::<Vec<_>>());
assert_eq!(descendant_range(12, 1, 3), (8, 2));
assert_eq!(descendant_range(12, 2, 3), (12, 1));
assert_eq!(descendant_range(13, 0, 3), (4, 4));
assert_eq!(expand(descendant_range(13, 0, 3)), (4..8).collect::<Vec<_>>());
assert_eq!(descendant_range(13, 1, 3), (10, 2));
assert_eq!(descendant_range(13, 2, 3), (13, 1)); }
#[test]
fn mid_level_node_to_leaves_height_3() {
assert_eq!(descendant_range(9, 0, 3), (2, 2));
assert_eq!(expand(descendant_range(9, 0, 3)), vec![2, 3]);
assert_eq!(descendant_range(9, 1, 3), (9, 1)); }
#[test]
#[should_panic(expected = "target_layer exceeds tree height")]
fn panics_when_target_layer_too_high() {
let _ = find_ancestor(4, 0, 3);
}
}