use crate::bits::BitMap;
include!(concat!(env!("OUT_DIR"), "/imbe_bit_priority.rs"));
pub const IMBE_B_MAX: usize = 59;
pub const L_MIN: u8 = 9;
pub const L_MAX: u8 = 56;
pub fn prioritize(b: &[u16; IMBE_B_MAX], l: u8) -> [u16; 8] {
debug_assert!((L_MIN..=L_MAX).contains(&l), "L out of range");
let l_idx = (l - L_MIN) as usize;
let mut u = [0u16; 8];
for m in &IMBE_BIT_MAP[l_idx] {
let bit = (b[m.src_param as usize] >> m.src_bit) & 1;
u[m.dst_vec as usize] |= bit << m.dst_bit;
}
u
}
pub fn deprioritize(u: &[u16; 8], l: u8) -> [u16; IMBE_B_MAX] {
debug_assert!((L_MIN..=L_MAX).contains(&l), "L out of range");
let l_idx = (l - L_MIN) as usize;
let mut b = [0u16; IMBE_B_MAX];
for m in &IMBE_BIT_MAP[l_idx] {
let bit = (u[m.dst_vec as usize] >> m.dst_bit) & 1;
b[m.src_param as usize] |= bit << m.src_bit;
}
b
}
#[cfg(test)]
mod tests {
use super::*;
fn max_src_param_for(l: u8) -> u8 {
let l_idx = (l - L_MIN) as usize;
IMBE_BIT_MAP[l_idx].iter().map(|m| m.src_param).max().unwrap()
}
fn param_width(l: u8, src_param: u8) -> u8 {
let l_idx = (l - L_MIN) as usize;
let max_bit = IMBE_BIT_MAP[l_idx]
.iter()
.filter(|m| m.src_param == src_param)
.map(|m| m.src_bit)
.max();
max_bit.map_or(0, |b| b + 1)
}
fn sample_b(l: u8, seed: u32) -> [u16; IMBE_B_MAX] {
let mut b = [0u16; IMBE_B_MAX];
let mut state = seed;
for src in 0..=max_src_param_for(l) {
let w = param_width(l, src) as u32;
if w == 0 {
continue;
}
state = state.wrapping_mul(1664525).wrapping_add(1013904223);
let mask = if w == 16 { u16::MAX } else { ((1u32 << w) - 1) as u16 };
b[src as usize] = (state as u16) & mask;
}
b
}
#[test]
fn roundtrip_all_l_values() {
for l in L_MIN..=L_MAX {
for seed in [1u32, 0xDEADBEEF, 0xA5A5A5A5] {
let b = sample_b(l, seed ^ u32::from(l));
let u = prioritize(&b, l);
let widths = [12u8, 12, 12, 12, 11, 11, 11, 7];
for (i, &w) in widths.iter().enumerate() {
let mask = if w == 16 { u16::MAX } else { ((1u16 << w) - 1) as u16 };
assert_eq!(u[i] & !mask, 0,
"L={l}: û{i} has bits beyond width {w}");
}
let b2 = deprioritize(&u, l);
assert_eq!(b2, b, "L={l}, seed=0x{seed:08x}");
}
}
}
#[test]
fn zero_prioritizes_to_zero() {
for l in L_MIN..=L_MAX {
let b = [0u16; IMBE_B_MAX];
let u = prioritize(&b, l);
assert_eq!(u, [0u16; 8]);
}
}
#[test]
fn pitch_msb_goes_to_u0() {
for l in L_MIN..=L_MAX {
let mut b = [0u16; IMBE_B_MAX];
b[0] = 0b1000_0000;
let u = prioritize(&b, l);
assert_ne!(u[0], 0, "L={l}: MSB of b̂₀ did not affect û₀");
}
}
#[test]
fn six_msbs_of_pitch_are_in_u0_at_fixed_positions() {
let l_min_positions: Vec<(u8, u8)> = IMBE_BIT_MAP[0]
.iter()
.filter(|m| m.src_param == 0 && m.src_bit >= 2)
.map(|m| (m.dst_vec, m.dst_bit))
.collect();
assert_eq!(l_min_positions.len(), 6);
for (v, _) in &l_min_positions {
assert_eq!(*v, 0, "pitch MSB not in û₀ for L=9");
}
for l in (L_MIN + 1)..=L_MAX {
let l_idx = (l - L_MIN) as usize;
let positions: Vec<(u8, u8)> = IMBE_BIT_MAP[l_idx]
.iter()
.filter(|m| m.src_param == 0 && m.src_bit >= 2)
.map(|m| (m.dst_vec, m.dst_bit))
.collect();
assert_eq!(positions, l_min_positions, "L={l}: pitch MSB positions differ from L=9");
}
}
#[test]
fn single_bit_propagation() {
for l in [L_MIN, 20, 35, L_MAX] {
let l_idx = (l - L_MIN) as usize;
for m in &IMBE_BIT_MAP[l_idx] {
let mut b = [0u16; IMBE_B_MAX];
b[m.src_param as usize] = 1 << m.src_bit;
let u = prioritize(&b, l);
let ones: u32 = u.iter().map(|x| x.count_ones()).sum();
assert_eq!(ones, 1,
"L={l} (src={}, bit={}) produced {ones} ones",
m.src_param, m.src_bit);
let b2 = deprioritize(&u, l);
assert_eq!(b2, b);
}
}
}
}