#![deny(missing_docs)]
#![feature(external_doc)]
#![doc(include = "../README.md")]
#![cfg_attr(test, feature(plugin))]
#![cfg_attr(test, plugin(clippy))]
mod iterator;
pub use iterator::Iterator;
pub fn index(depth: usize, offset: usize) -> usize {
(offset << (depth + 1)) | ((1 << depth) - 1)
}
pub fn depth(i: usize) -> usize {
let mut depth = 0;
let mut i = i;
while is_odd(i) {
i >>= 1;
depth += 1;
}
depth
}
pub fn offset_with_depth(i: usize, depth: usize) -> usize {
if is_even(i) {
i / 2
} else {
i >> (depth + 1)
}
}
pub fn offset(i: usize) -> usize {
offset_with_depth(i, depth(i))
}
pub fn parent_with_depth(i: usize, depth: usize) -> usize {
index(depth + 1, offset_with_depth(i, depth) >> 1)
}
pub fn parent(i: usize) -> usize {
parent_with_depth(i, depth(i))
}
pub fn sibling_with_depth(i: usize, depth: usize) -> usize {
index(depth, offset(i) ^ 1)
}
pub fn sibling(i: usize) -> usize {
sibling_with_depth(i, depth(i))
}
pub fn uncle_with_depth(i: usize, depth: usize) -> usize {
sibling_with_depth(parent_with_depth(i, depth), depth + 1)
}
pub fn uncle(i: usize) -> usize {
uncle_with_depth(i, depth(i))
}
pub fn children_with_depth(i: usize, depth: usize) -> Option<(usize, usize)> {
if is_even(i) {
None
} else if depth == 0 {
Some((i, i))
} else {
let offset = offset_with_depth(i, depth) * 2;
Some((
index(depth - 1, offset),
index(depth - 1, offset + 1),
))
}
}
pub fn children(i: usize) -> Option<(usize, usize)> {
children_with_depth(i, depth(i))
}
pub fn left_child_with_depth(i: usize, depth: usize) -> Option<usize> {
if is_even(i) {
None
} else if depth == 0 {
Some(i)
} else {
Some(index(
depth - 1,
offset_with_depth(i, depth) << 1,
))
}
}
pub fn left_child(i: usize) -> Option<usize> {
left_child_with_depth(i, depth(i))
}
pub fn right_child_with_depth(i: usize, depth: usize) -> Option<usize> {
if is_even(i) {
None
} else if depth == 0 {
Some(i)
} else {
Some(index(
depth - 1,
(offset_with_depth(i, depth) << 1) + 1,
))
}
}
pub fn right_child(i: usize) -> Option<usize> {
right_child_with_depth(i, depth(i))
}
pub fn right_span_with_depth(i: usize, depth: usize) -> usize {
if depth == 0 {
i
} else {
(offset_with_depth(i, depth) + 1) * (2 << depth) - 2
}
}
pub fn right_span(i: usize) -> usize {
right_span_with_depth(i, depth(i))
}
pub fn left_span_with_depth(i: usize, depth: usize) -> usize {
if depth == 0 {
i
} else {
offset_with_depth(i, depth) * (2 << depth)
}
}
pub fn left_span(i: usize) -> usize {
left_span_with_depth(i, depth(i))
}
pub fn spans_with_depth(i: usize, depth: usize) -> (usize, usize) {
(
left_span_with_depth(i, depth),
right_span_with_depth(i, depth),
)
}
pub fn spans(i: usize) -> (usize, usize) {
spans_with_depth(i, depth(i))
}
pub fn count_with_depth(_: usize, depth: usize) -> usize {
(2 << depth) - 1
}
pub fn count(i: usize) -> usize {
count_with_depth(i, depth(i))
}
pub fn full_roots(i: usize, nodes: &mut Vec<usize>) {
assert!(
is_even(i),
format!(
"You can only look up roots for depth 0 blocks, got index {}",
i
)
);
let mut tmp = i >> 1;
let mut offset = 0;
let mut factor = 1;
loop {
if tmp == 0 {
break;
}
while factor * 2 <= tmp {
factor *= 2;
}
nodes.push(offset + factor - 1);
offset += 2 * factor;
tmp -= factor;
factor = 1;
}
}
#[inline]
fn is_even(num: usize) -> bool {
(num & 1) == 0
}
#[test]
fn test_is_even() {
assert_eq!(is_even(0), true);
assert_eq!(is_even(1), false);
assert_eq!(is_even(2), true);
assert_eq!(is_even(3), false);
}
#[inline]
fn is_odd(num: usize) -> bool {
(num & 1) != 0
}
#[test]
fn test_is_odd() {
assert_eq!(is_odd(0), false);
assert_eq!(is_odd(1), true);
assert_eq!(is_odd(2), false);
assert_eq!(is_odd(3), true);
}
#[test]
fn test_parent_gt_int32() {
assert_eq!(parent(10_000_000_000), 10_000_000_001);
}
#[test]
fn test_child_to_parent_to_child() {
let mut child = 0;
for _ in 0..50 {
child = parent(child)
}
assert_eq!(child, 1_125_899_906_842_623);
for _ in 0..50 {
child = left_child(child).expect("no valid number returned");
}
assert_eq!(child, 0);
}