use crate::Hash;
use digest::Digest;
const ALL_ONES: usize = std::usize::MAX;
pub fn node_index(leaf_index: usize) -> usize {
if leaf_index == 0 {
return 0;
}
2 * leaf_index - leaf_index.count_ones() as usize
}
pub fn leaf_index(node_index: usize) -> u32 {
n_leaves(node_index) as u32
}
pub fn is_leaf(pos: usize) -> bool {
bintree_height(pos) == 0
}
pub fn find_peaks(size: usize) -> Vec<usize> {
if size == 0 {
return vec![];
}
let mut peak_size = ALL_ONES >> size.leading_zeros();
let mut num_left = size;
let mut sum_prev_peaks = 0;
let mut peaks = vec![];
while peak_size != 0 {
if num_left >= peak_size {
peaks.push(sum_prev_peaks + peak_size - 1);
sum_prev_peaks += peak_size;
num_left -= peak_size;
}
peak_size >>= 1;
}
if num_left > 0 {
return vec![];
}
peaks
}
pub fn family(pos: usize) -> (usize, usize) {
let (peak_map, height) = peak_map_height(pos);
let peak = 1 << height;
if (peak_map & peak) != 0 {
(pos + 1, pos + 1 - 2 * peak)
} else {
(pos + 2 * peak, pos + 2 * peak - 1)
}
}
pub fn family_branch(pos: usize, last_pos: usize) -> Vec<(usize, usize)> {
let (peak_map, height) = peak_map_height(pos);
let mut peak = 1 << height;
let mut branch = vec![];
let mut current = pos;
let mut sibling;
while current < last_pos {
if (peak_map & peak) != 0 {
current += 1;
sibling = current - 2 * peak;
} else {
current += 2 * peak;
sibling = current - 1;
};
if current > last_pos {
break;
}
branch.push((current, sibling));
peak <<= 1;
}
branch
}
#[inline(always)]
pub fn bintree_height(num: usize) -> usize {
if num == 0 {
return 0;
}
peak_map_height(num).1
}
pub fn peak_map_height(mut pos: usize) -> (usize, usize) {
if pos == 0 {
return (0, 0);
}
let mut peak_size = ALL_ONES >> pos.leading_zeros();
let mut bitmap = 0;
while peak_size != 0 {
bitmap <<= 1;
if pos >= peak_size {
pos -= peak_size;
bitmap |= 1;
}
peak_size >>= 1;
}
(bitmap, pos)
}
pub fn peak_sizes_height(size: usize) -> (Vec<usize>, usize) {
if size == 0 {
return (vec![], 0);
}
let mut peak_size = ALL_ONES >> size.leading_zeros();
let mut sizes = vec![];
let mut size_left = size;
while peak_size != 0 {
if size_left >= peak_size {
sizes.push(peak_size);
size_left -= peak_size;
}
peak_size >>= 1;
}
(sizes, size_left)
}
pub fn is_left_sibling(pos: usize) -> bool {
let (peak_map, height) = peak_map_height(pos);
let peak = 1 << height;
(peak_map & peak) == 0
}
pub fn hash_together<D: Digest>(left: &[u8], right: &[u8]) -> Hash {
D::new().chain(left).chain(right).result().to_vec()
}
pub fn n_leaves(size: usize) -> usize {
let (sizes, height) = peak_sizes_height(size);
let nleaves = sizes.iter().map(|n| (n + 1) / 2).sum();
if height == 0 {
nleaves
} else {
nleaves + 1
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn leaf_to_node_indices() {
assert_eq!(node_index(0), 0);
assert_eq!(node_index(1), 1);
assert_eq!(node_index(2), 3);
assert_eq!(node_index(3), 4);
assert_eq!(node_index(5), 8);
assert_eq!(node_index(6), 10);
assert_eq!(node_index(7), 11);
assert_eq!(node_index(8), 15);
}
#[test]
fn n_leaf_nodes() {
assert_eq!(n_leaves(0), 0);
assert_eq!(n_leaves(1), 1);
assert_eq!(n_leaves(3), 2);
assert_eq!(n_leaves(4), 3);
assert_eq!(n_leaves(8), 5);
assert_eq!(n_leaves(10), 6);
assert_eq!(n_leaves(11), 7);
assert_eq!(n_leaves(15), 8);
}
#[test]
fn peak_vectors() {
assert_eq!(find_peaks(0), Vec::<usize>::new());
assert_eq!(find_peaks(1), vec![0]);
assert_eq!(find_peaks(3), vec![2]);
assert_eq!(find_peaks(4), vec![2, 3]);
assert_eq!(find_peaks(15), vec![14]);
assert_eq!(find_peaks(23), vec![14, 21, 22]);
}
#[test]
fn peak_map_heights() {
assert_eq!(peak_map_height(0), (0, 0));
assert_eq!(peak_map_height(4), (0b11, 0));
assert_eq!(peak_map_height(9), (0b101, 1));
assert_eq!(peak_map_height(10), (0b110, 0));
assert_eq!(peak_map_height(12), (0b111, 1));
assert_eq!(peak_map_height(33), (0b10001, 1));
assert_eq!(peak_map_height(34), (0b10010, 0));
}
#[test]
fn is_sibling_left() {
assert_eq!(is_left_sibling(0), true);
assert_eq!(is_left_sibling(1), false);
assert_eq!(is_left_sibling(2), true);
assert_eq!(is_left_sibling(3), true);
assert_eq!(is_left_sibling(4), false);
assert_eq!(is_left_sibling(5), false);
assert_eq!(is_left_sibling(6), true);
assert_eq!(is_left_sibling(7), true);
assert_eq!(is_left_sibling(8), false);
assert_eq!(is_left_sibling(9), true);
assert_eq!(is_left_sibling(10), true);
assert_eq!(is_left_sibling(11), false);
assert_eq!(is_left_sibling(12), false);
assert_eq!(is_left_sibling(13), false);
assert_eq!(is_left_sibling(14), true);
assert_eq!(is_left_sibling(15), true);
}
#[test]
fn families() {
assert_eq!(family(1), (2, 0));
assert_eq!(family(0), (2, 1));
assert_eq!(family(3), (5, 4));
assert_eq!(family(9), (13, 12));
assert_eq!(family(15), (17, 16));
assert_eq!(family(6), (14, 13));
assert_eq!(family(13), (14, 6));
}
#[test]
fn family_branches() {
assert_eq!(family_branch(0, 2), [(2, 1)]);
assert_eq!(family_branch(1, 2), [(2, 0)]);
assert_eq!(family_branch(2, 2), []);
assert_eq!(family_branch(0, 6), [(2, 1), (6, 5)]);
assert_eq!(family_branch(0, 3), [(2, 1)]);
assert_eq!(family_branch(3, 3), []);
assert_eq!(family_branch(3, 4), []);
assert_eq!(family_branch(3, 5), [(5, 4)]);
assert_eq!(family_branch(3, 6), [(5, 4), (6, 2)]);
assert_eq!(family_branch(0, 1_048_999), [
(2, 1),
(6, 5),
(14, 13),
(30, 29),
(62, 61),
(126, 125),
(254, 253),
(510, 509),
(1022, 1021),
(2046, 2045),
(4094, 4093),
(8190, 8189),
(16382, 16381),
(32766, 32765),
(65534, 65533),
(131_070, 131_069),
(262_142, 262_141),
(524_286, 524_285),
(1_048_574, 1_048_573),
]);
}
}