use crate::Error;
fn floor_log2(x: u32) -> u32 {
if x == 0 {
0
} else {
31 - x.leading_zeros()
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct BitReader<'a> {
bytes: &'a [u8],
pos: usize,
}
impl<'a> BitReader<'a> {
pub(crate) fn new(bytes: &'a [u8]) -> Self {
Self { bytes, pos: 0 }
}
pub(crate) fn position(&self) -> usize {
self.pos
}
fn read_bit(&mut self) -> Result<u8, Error> {
let byte_idx = self.pos >> 3;
let bit_idx = 7 - (self.pos & 0x7); let byte = *self.bytes.get(byte_idx).ok_or(Error::UnexpectedEnd)?;
self.pos += 1;
Ok((byte >> bit_idx) & 0x1)
}
pub(crate) fn f(&mut self, n: u32) -> Result<u64, Error> {
debug_assert!(n <= 64);
let mut x: u64 = 0;
for _ in 0..n {
x = (x << 1) | u64::from(self.read_bit()?);
}
Ok(x)
}
pub(crate) fn su(&mut self, n: u32) -> Result<i32, Error> {
debug_assert!((1..=32).contains(&n));
let value = self.f(n)? as u32;
let sign_mask: u32 = 1 << (n - 1);
if value & sign_mask != 0 {
let v = i64::from(value) - (i64::from(sign_mask) << 1);
Ok(v as i32)
} else {
Ok(value as i32)
}
}
pub(crate) fn ns(&mut self, n: u32) -> Result<u32, Error> {
debug_assert!(n >= 1);
let w = floor_log2(n) + 1;
let m = (1u32 << w) - n;
let v = self.f(w - 1)? as u32;
if v < m {
return Ok(v);
}
let extra_bit = self.f(1)? as u32;
Ok((v << 1) - m + extra_bit)
}
pub(crate) fn uvlc(&mut self) -> Result<u32, Error> {
let mut leading_zeros: u32 = 0;
loop {
let done = self.f(1)?;
if done == 1 {
break;
}
leading_zeros += 1;
if leading_zeros >= 32 {
return Ok(u32::MAX);
}
}
let value = self.f(leading_zeros)?;
let sum = value + ((1u64) << leading_zeros) - 1;
Ok(u32::try_from(sum.min(u64::from(u32::MAX))).expect("clamped"))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn f1_walks_bits_msb_first() {
let mut br = BitReader::new(&[0xAC]);
assert_eq!(br.f(1).unwrap(), 1);
assert_eq!(br.f(1).unwrap(), 0);
assert_eq!(br.f(1).unwrap(), 1);
assert_eq!(br.f(1).unwrap(), 0);
assert_eq!(br.f(1).unwrap(), 1);
assert_eq!(br.f(1).unwrap(), 1);
assert_eq!(br.f(1).unwrap(), 0);
assert_eq!(br.f(1).unwrap(), 0);
assert_eq!(br.position(), 8);
}
#[test]
fn fn_reads_multi_bit_field() {
let mut br = BitReader::new(&[0xAC, 0x53]);
let v = br.f(12).unwrap();
assert_eq!(v, 0xAC5);
assert_eq!(br.position(), 12);
}
#[test]
fn f_n_equals_zero_returns_zero_no_advance() {
let mut br = BitReader::new(&[0xFF]);
assert_eq!(br.f(0).unwrap(), 0);
assert_eq!(br.position(), 0);
}
#[test]
fn f_returns_unexpected_end_past_buffer() {
let mut br = BitReader::new(&[0x80]);
let _ = br.f(8).unwrap();
let err = br.f(1).unwrap_err();
assert_eq!(err, Error::UnexpectedEnd);
}
#[test]
fn uvlc_decodes_zero() {
let mut br = BitReader::new(&[0b1000_0000]);
assert_eq!(br.uvlc().unwrap(), 0);
assert_eq!(br.position(), 1);
}
#[test]
fn uvlc_decodes_one_two_three() {
let mut br = BitReader::new(&[0b0100_0000]);
assert_eq!(br.uvlc().unwrap(), 1);
assert_eq!(br.position(), 3);
let mut br = BitReader::new(&[0b0110_0000]);
assert_eq!(br.uvlc().unwrap(), 2);
let mut br = BitReader::new(&[0b0010_0000]);
assert_eq!(br.uvlc().unwrap(), 3);
assert_eq!(br.position(), 5);
}
#[test]
fn su_positive_value() {
let mut br = BitReader::new(&[0b0010_1010]);
assert_eq!(br.su(7).unwrap(), 21);
assert_eq!(br.position(), 7);
}
#[test]
fn su_negative_value() {
let mut br = BitReader::new(&[0b1111_1110]);
assert_eq!(br.su(7).unwrap(), -1);
}
#[test]
fn su_min_negative() {
let mut br = BitReader::new(&[0b1000_0000]);
assert_eq!(br.su(7).unwrap(), -64);
}
#[test]
fn ns_n_equals_1_reads_zero_bits() {
let mut br = BitReader::new(&[0xFF]);
assert_eq!(br.ns(1).unwrap(), 0);
assert_eq!(br.position(), 0);
}
#[test]
fn ns_n_equals_5_table_matches_spec() {
let bytes = [0b0001_1011u8, 0b0111_0000u8];
let mut br = BitReader::new(&bytes);
assert_eq!(br.ns(5).unwrap(), 0);
assert_eq!(br.ns(5).unwrap(), 1);
assert_eq!(br.ns(5).unwrap(), 2);
assert_eq!(br.ns(5).unwrap(), 3);
assert_eq!(br.ns(5).unwrap(), 4);
}
#[test]
fn ns_n_equals_power_of_two_collapses_to_fn() {
let mut br = BitReader::new(&[0x1B]);
assert_eq!(br.ns(4).unwrap(), 0);
assert_eq!(br.ns(4).unwrap(), 1);
assert_eq!(br.ns(4).unwrap(), 2);
assert_eq!(br.ns(4).unwrap(), 3);
assert_eq!(br.position(), 8);
}
#[test]
fn uvlc_returns_sentinel_on_32_leading_zeros() {
let mut br = BitReader::new(&[0x00, 0x00, 0x00, 0x00, 0x80]);
assert_eq!(br.uvlc().unwrap(), u32::MAX);
}
}