use crate::{Position, storage::Storage};
pub(crate) fn root<S: Storage + ?Sized>(data: &S) -> Option<Position> {
(data.len() != 0).then_some(0)
}
pub(crate) fn parent<S: Storage + ?Sized>(_data: &S, pos: Position) -> Option<Position> {
Some(pos.checked_sub(1)? / 2)
}
pub(crate) fn child<S: Storage + ?Sized>(
data: &S,
pos: Position,
index: usize,
) -> Option<Position> {
assert!(index < 2);
let child = 2 * pos + 1 + index;
(child < data.len()).then_some(child)
}
pub(crate) fn select_sibling<S: Storage + ?Sized>(
_data: &S,
pos: Position,
cond: bool,
) -> Option<Position> {
Some(pos + (cond as usize))
}
pub(crate) fn is_whole_node<S: Storage + ?Sized>(data: &S, pos: Position) -> bool {
child(data, pos, 1).is_some()
}
pub(crate) fn nchildren<S: Storage + ?Sized>(data: &S, pos: Position) -> usize {
let first = 2 * pos + 1;
let len = data.len();
let s = len.saturating_sub(first);
s.min(2)
}
pub(crate) fn children<S: Storage + ?Sized>(
data: &S,
pos: Position,
) -> impl Iterator<Item = Position> {
let n = nchildren(data, pos);
(0..n).map(move |index| child(data, pos, index).unwrap())
}
pub(crate) fn rebuild_range<S: Storage + ?Sized>(data: &S) -> std::ops::Range<Position> {
let len = data.len();
let n = len / 2;
0..n
}
pub(crate) fn better_to_rebuild<S: Storage + ?Sized>(data: &S, start: Position) -> bool {
let len = data.len();
let tail_len = len - start;
if start < tail_len {
true
} else if len <= 2048 {
2 * len < tail_len * log2_fast(start)
} else {
2 * len < tail_len * 11
}
}
fn log2_fast(x: usize) -> usize {
(usize::BITS - x.leading_zeros() - 1) as usize
}
#[cfg(test)]
mod tests {
#[test]
fn children() {
assert_eq!(super::nchildren([0u32; 3].as_slice(), 0), 2);
assert_eq!(super::nchildren([0u32; 3].as_slice(), 1), 0);
assert_eq!(super::nchildren([0u32; 4].as_slice(), 1), 1);
assert_eq!(super::nchildren([0u32; 5].as_slice(), 1), 2);
assert_eq!(super::nchildren([0u32; 6].as_slice(), 1), 2);
}
}