use alloc::vec::Vec;
pub fn padded_count(n: usize) -> usize {
let n = n.max(1);
n.next_power_of_two()
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccessPlan {
pub order: Vec<u32>,
pub real_positions: Vec<usize>,
}
pub fn build_access_plan<F>(real: &[u32], pool_size: u32, mut rand: F) -> AccessPlan
where
F: FnMut(u32) -> Vec<u8>,
{
let bucket = padded_count(real.len());
let mut slots: Vec<u32> = real.to_vec();
let need = bucket - slots.len();
if need > 0 && pool_size > 0 {
let cover_bytes = rand((need as u32) * 4);
for i in 0..need {
let b = i * 4;
let v = u32::from_be_bytes([
cover_bytes[b],
cover_bytes[b + 1],
cover_bytes[b + 2],
cover_bytes[b + 3],
]);
slots.push(v % pool_size);
}
} else {
let _ = rand(4);
}
let mut positions: Vec<usize> = (0..real.len()).collect();
let shuffle_bytes = rand((bucket as u32) * 4);
for i in (1..slots.len()).rev() {
let b = (i % bucket) * 4;
let r = u32::from_be_bytes([
shuffle_bytes[b],
shuffle_bytes[b + 1],
shuffle_bytes[b + 2],
shuffle_bytes[b + 3],
]) as usize;
let j = r % (i + 1);
slots.swap(i, j);
for p in positions.iter_mut() {
if *p == i {
*p = j;
} else if *p == j {
*p = i;
}
}
}
AccessPlan {
order: slots,
real_positions: positions,
}
}