pub type ChunkCount = u64;
pub type ChunkIndex = ChunkCount;
pub type NodeNumber = u64;
pub type RootedPathLength = u8;
pub type Layer = u8;
pub type ByteCount = u64;
pub type ByteIndex = ByteCount;
pub fn chunk_index_to_node_number(chunk_index: ChunkIndex, chunk_count: ChunkCount) -> NodeNumber {
assert!(chunk_index < chunk_count);
if chunk_count == 1 {
return 0;
} else {
let left_subtree_leaf_count = chunk_count.next_power_of_two() / 2;
if chunk_index < left_subtree_leaf_count {
return 1 + chunk_index_to_node_number(chunk_index, left_subtree_leaf_count);
} else {
return left_subtree_leaf_count * 2
+ chunk_index_to_node_number(
chunk_index - left_subtree_leaf_count,
chunk_count - left_subtree_leaf_count,
);
}
}
}
#[test]
fn test_chunk_index_to_node_number() {
let expected = [
&[0u64][..],
&[1, 2][..],
&[2, 3, 4][..],
&[2, 3, 5, 6][..],
&[3, 4, 6, 7, 8][..],
&[3, 4, 6, 7, 9, 10][..],
&[3, 4, 6, 7, 10, 11, 12][..],
&[3, 4, 6, 7, 10, 11, 13, 14][..],
&[4, 5, 7, 8, 11, 12, 14, 15, 16][..],
];
for (i, testdata) in expected.iter().enumerate() {
for (chunk_index, node_number) in testdata.iter().enumerate() {
assert_eq!(
chunk_index_to_node_number(chunk_index as ChunkIndex, (i as u64) + 1),
*node_number,
);
}
}
}
pub fn node_number_to_chunk_index(node_number: ChunkIndex, chunk_count: ChunkCount) -> NodeNumber {
if node_number > chunk_count.saturating_mul(2) {
panic!("node_number greater than possible for the given chunk_count");
}
node_number_to_chunk_index_(node_number, chunk_count)
}
fn node_number_to_chunk_index_(node_number: ChunkIndex, chunk_count: ChunkCount) -> NodeNumber {
if node_number == 0 {
return 0;
} else {
let left_subtree_node_count = chunk_count.next_power_of_two() - 1;
let left_subtree_leaf_count = chunk_count.next_power_of_two() / 2;
if node_number <= left_subtree_node_count {
return node_number_to_chunk_index(node_number - 1, left_subtree_leaf_count);
} else {
return left_subtree_leaf_count
+ node_number_to_chunk_index(
node_number - (left_subtree_node_count + 1),
chunk_count - left_subtree_leaf_count,
);
}
}
}
#[test]
fn test_node_number_to_chunk_index() {
let expected = [
&[0u64][..],
&[0, 0, 1][..],
&[0, 0, 0, 1, 2][..],
&[0, 0, 0, 1, 2, 2, 3][..],
&[0, 0, 0, 0, 1, 2, 2, 3, 4][..],
&[0, 0, 0, 0, 1, 2, 2, 3, 4, 4, 5][..],
&[0, 0, 0, 0, 1, 2, 2, 3, 4, 4, 4, 5, 6][..],
&[0, 0, 0, 0, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6, 7][..],
&[0, 0, 0, 0, 0, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 8][..],
];
for (i, testdata) in expected.iter().enumerate() {
for (node_number, expected_chunk_index) in testdata.iter().enumerate() {
assert_eq!(
node_number_to_chunk_index(node_number as NodeNumber, (i + 1) as ChunkCount),
*expected_chunk_index,
);
}
}
}
pub(crate) fn node_number_to_left_skip(node_number: NodeNumber, chunk_count: ChunkCount) -> u8 {
if node_number == 0 {
return 0;
} else {
let left_subtree_node_count = chunk_count.next_power_of_two() - 1;
let left_subtree_leaf_count = chunk_count.next_power_of_two() / 2;
if node_number <= left_subtree_node_count {
return 1 + node_number_to_left_skip(node_number - 1, left_subtree_leaf_count);
} else {
return 1 + node_number_to_left_skip(
node_number - (left_subtree_node_count + 1),
chunk_count - left_subtree_leaf_count,
);
}
}
}
#[test]
fn test_node_number_to_left_skip() {
let expected = [
&[0u8][..],
&[0, 1, 1][..],
&[0, 1, 2, 2, 1][..],
&[0, 1, 2, 2, 1, 2, 2][..],
&[0, 1, 2, 3, 3, 2, 3, 3, 1][..],
&[0, 1, 2, 3, 3, 2, 3, 3, 1, 2, 2][..],
&[0, 1, 2, 3, 3, 2, 3, 3, 1, 2, 3, 3, 2][..],
&[0, 1, 2, 3, 3, 2, 3, 3, 1, 2, 3, 3, 2, 3, 3][..],
&[0, 1, 2, 3, 4, 4, 3, 4, 4, 2, 3, 4, 4, 3, 4, 4, 1][..],
];
for (i, testdata) in expected.iter().enumerate() {
for (node_number, expected_left_skip) in testdata.iter().enumerate() {
assert_eq!(
node_number_to_left_skip(node_number as NodeNumber, (i + 1) as ChunkCount),
*expected_left_skip,
);
}
}
}
pub(crate) fn node_number_to_right_skip(
node_number: NodeNumber,
final_chunk_of_slice: ChunkIndex,
chunk_count: ChunkCount,
) -> u8 {
let final_node_number = chunk_index_to_node_number(final_chunk_of_slice, chunk_count);
node_number_to_right_skip_(node_number, final_node_number, chunk_count)
}
fn node_number_to_right_skip_(
node_number: NodeNumber,
final_node_number: NodeNumber,
chunk_count: ChunkCount,
) -> u8 {
if node_number == 0 {
return 0;
} else {
let left_subtree_node_count = chunk_count.next_power_of_two() - 1;
let left_subtree_leaf_count = chunk_count.next_power_of_two() / 2;
if node_number <= left_subtree_node_count {
if final_node_number > left_subtree_node_count {
return 1;
} else {
return 1 + node_number_to_right_skip_(
node_number - 1,
final_node_number - 1,
left_subtree_leaf_count,
);
}
} else {
return 1 + node_number_to_right_skip_(
node_number - (left_subtree_node_count + 1),
final_node_number - (left_subtree_node_count + 1),
chunk_count - left_subtree_leaf_count,
);
}
}
}
#[test]
fn test_node_number_to_right_skip() {
let expected = [
&[0, 0, 0, 0, 0, 0][..],
&[1, 1, 1, 1, 1, 1][..],
&[2, 2, 2, 2, 1, 1][..],
&[3, 3, 2, 2, 1, 1][..],
&[3, 2, 2, 1, 1][..],
&[2, 2, 1, 1][..],
&[3, 3, 1, 1][..],
&[3, 1, 1][..],
&[1, 1][..],
&[2, 2][..],
&[2][..],
];
for (i, testdata) in expected.iter().enumerate() {
for (j, expected_right_skip) in testdata.iter().enumerate() {
let final_chunk_of_slice = (j + (6 - testdata.len())) as ChunkIndex;
assert_eq!(
node_number_to_right_skip(i as NodeNumber, final_chunk_of_slice, 6),
*expected_right_skip,
);
}
}
}
pub fn string_length_to_chunk_count<const CHUNK_SIZE: usize>(len: ByteCount) -> ChunkCount {
if len == 0 {
1
} else {
len.div_ceil(CHUNK_SIZE as u64)
}
}
pub fn optimal_left_skip(
mut chunk_count: ChunkCount,
mut prior_end: ChunkIndex,
mut next_start: ChunkIndex,
) -> RootedPathLength {
debug_assert!(prior_end < next_start);
let mut left_skip = 1;
loop {
let left_subtree_leaf_count = chunk_count.next_power_of_two() / 2;
let right_subtree_leaf_count = chunk_count - left_subtree_leaf_count;
if next_start < left_subtree_leaf_count {
debug_assert!(prior_end < left_subtree_leaf_count);
chunk_count -= right_subtree_leaf_count;
left_skip += 1;
} else if prior_end >= left_subtree_leaf_count {
debug_assert!(next_start >= left_subtree_leaf_count);
chunk_count -= left_subtree_leaf_count;
prior_end -= left_subtree_leaf_count;
next_start -= left_subtree_leaf_count;
left_skip += 1;
} else {
debug_assert!(
prior_end < left_subtree_leaf_count && next_start >= left_subtree_leaf_count
);
return left_skip;
}
}
}
#[test]
fn test_optimal_left_skip() {
let expected = [
(2, 0, 1, 1),
(6, 0, 1, 3),
(6, 0, 2, 2),
(6, 0, 3, 2),
(6, 0, 4, 1),
(6, 0, 5, 1),
(6, 1, 2, 2),
(6, 1, 3, 2),
(6, 1, 4, 1),
(6, 1, 5, 1),
(6, 2, 3, 3),
(6, 2, 4, 1),
(6, 2, 5, 1),
(6, 3, 4, 1),
(6, 3, 5, 1),
(6, 4, 5, 2),
(8, 0, 1, 3),
(8, 0, 2, 2),
(8, 0, 3, 2),
(8, 0, 4, 1),
(8, 0, 5, 1),
(8, 0, 6, 1),
(8, 0, 7, 1),
(8, 1, 2, 2),
(8, 1, 3, 2),
(8, 1, 4, 1),
(8, 1, 5, 1),
(8, 1, 6, 1),
(8, 1, 7, 1),
(8, 2, 3, 3),
(8, 2, 4, 1),
(8, 2, 5, 1),
(8, 2, 6, 1),
(8, 2, 7, 1),
(8, 3, 4, 1),
(8, 3, 5, 1),
(8, 3, 6, 1),
(8, 3, 7, 1),
(8, 4, 5, 3),
(8, 4, 6, 2),
(8, 4, 7, 2),
(8, 5, 6, 2),
(8, 5, 7, 2),
(8, 6, 7, 3),
];
for (chunk_count, prior_end, next_start, expected_optimal_left_skip) in expected.into_iter() {
assert_eq!(
optimal_left_skip(chunk_count, prior_end, next_start),
expected_optimal_left_skip,
"chunk_count {chunk_count}, prior_end {prior_end}, next_start {next_start}, expected_optimal_left_skip {expected_optimal_left_skip}"
);
}
}