pub fn pointers(index: u32) -> u32 {
if index == 0 {
0
} else {
index.trailing_zeros() + 1
}
}
pub fn payload(block_size: u32, index: u32) -> u32 {
block_size - 4 * pointers(index)
}
pub fn npw2(a: u32) -> u32 {
32 - a.wrapping_sub(1).leading_zeros()
}
pub fn index_of(block_size: u32, off: u32) -> (u32, u32) {
let b = block_size - 2 * 4;
let i = off / b;
if i == 0 {
return (0, off);
}
let i = off.saturating_sub(4 * ((i - 1).count_ones() + 2)) / b;
let o = off - b * i - 4 * i.count_ones();
(i, o)
}
pub fn block_start(block_size: u32, index: u32) -> u32 {
if index == 0 {
return 0;
}
index * (block_size - 8) + 8 + 4 * (index - 1).count_ones()
}
pub fn hop(current: u32, target: u32) -> (u32, u32) {
let skip = npw2(current - target + 1)
.saturating_sub(1)
.min(current.trailing_zeros());
(skip, 1 << skip)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn index_math_agrees_with_block_capacities() {
let bs = 256;
let mut off = 0u32;
for index in 0..40u32 {
let cap = payload(bs, index);
for within in 0..cap {
let (i, o) = index_of(bs, off);
assert_eq!(i, index, "offset {off} should be in block {index}");
assert_eq!(o, 4 * pointers(index) + within);
off += 1;
}
}
}
#[test]
fn first_block_holds_a_whole_block() {
assert_eq!(payload(4096, 0), 4096);
assert_eq!(index_of(4096, 0), (0, 0));
assert_eq!(index_of(4096, 4095), (0, 4095));
assert_eq!(index_of(4096, 4096), (1, 4));
}
#[test]
fn block_start_inverts_index_of() {
for index in 0..64u32 {
let start = block_start(512, index);
assert_eq!(index_of(512, start), (index, 4 * pointers(index)));
if index > 0 {
assert_eq!(index_of(512, start - 1).0, index - 1);
}
}
}
#[test]
fn pointer_counts_follow_ctz() {
assert_eq!(pointers(0), 0);
assert_eq!(pointers(1), 1);
assert_eq!(pointers(2), 2);
assert_eq!(pointers(3), 1);
assert_eq!(pointers(4), 3);
assert_eq!(pointers(8), 4);
}
#[test]
fn npw2_matches_ceil_log2() {
assert_eq!(npw2(1), 0);
assert_eq!(npw2(2), 1);
assert_eq!(npw2(3), 2);
assert_eq!(npw2(4), 2);
assert_eq!(npw2(5), 3);
}
#[test]
fn a_hop_never_overshoots_and_always_advances() {
for current in 1..64u32 {
for target in 0..current {
let (slot, step) = hop(current, target);
assert!(step >= 1, "{current}→{target} made no progress");
assert!(
current - step >= target,
"{current}→{target} overshot by slot {slot}"
);
assert!(slot < pointers(current), "{current} has no slot {slot}");
}
}
}
}