use crate::bitreader::BitReader;
use crate::Error;
const EC_PROB_SHIFT: u32 = 6;
const EC_MIN_PROB: u32 = 4;
fn floor_log2(x: u32) -> u32 {
if x == 0 {
0
} else {
31 - x.leading_zeros()
}
}
fn inverse_recenter(r: i64, v: i64) -> i64 {
if v > 2 * r {
v
} else if v & 1 != 0 {
r - ((v + 1) >> 1)
} else {
r + (v >> 1)
}
}
#[derive(Debug)]
pub struct SymbolDecoder<'a> {
reader: BitReader<'a>,
value: u32,
range: u32,
max_bits: i64,
disable_cdf_update: bool,
}
impl<'a> SymbolDecoder<'a> {
pub fn init_symbol(
bytes: &'a [u8],
sz: usize,
disable_cdf_update: bool,
) -> Result<Self, Error> {
let mut reader = BitReader::new(bytes);
let num_bits = core::cmp::min(sz.saturating_mul(8), 15) as u32;
let buf = reader.f(num_bits)? as u32;
let padded_buf = buf << (15 - num_bits);
let value = ((1u32 << 15) - 1) ^ padded_buf;
let range = 1u32 << 15;
let max_bits = (sz as i64) * 8 - 15;
Ok(Self {
reader,
value,
range,
max_bits,
disable_cdf_update,
})
}
pub fn position(&self) -> usize {
self.reader.position()
}
#[cfg(test)]
pub(crate) fn symbol_value(&self) -> u32 {
self.value
}
#[cfg(test)]
pub(crate) fn symbol_range(&self) -> u32 {
self.range
}
#[cfg(test)]
pub(crate) fn symbol_max_bits(&self) -> i64 {
self.max_bits
}
pub fn read_symbol(&mut self, cdf: &mut [u16]) -> Result<u32, Error> {
let n = cdf.len() as u32 - 1;
debug_assert!(n >= 1, "§8.2.6: N must be greater than 1");
let mut cur = self.range;
let mut prev;
let mut symbol: i64 = -1;
loop {
symbol += 1;
prev = cur;
let s = symbol as usize;
let f = (1u32 << 15) - u32::from(cdf[s]);
cur = ((self.range >> 8) * (f >> EC_PROB_SHIFT)) >> (7 - EC_PROB_SHIFT);
cur += EC_MIN_PROB * (n - symbol as u32 - 1);
if self.value >= cur {
break;
}
}
let symbol = symbol as u32;
self.range = prev - cur;
self.value -= cur;
self.renormalize()?;
if !self.disable_cdf_update {
update_cdf(cdf, symbol, n);
}
Ok(symbol)
}
fn renormalize(&mut self) -> Result<(), Error> {
let bits = 15 - floor_log2(self.range);
self.range <<= bits;
let avail = self.max_bits.max(0);
let num_bits = core::cmp::min(i64::from(bits), avail) as u32;
let new_data = self.reader.f(num_bits)? as u32;
let padded_data = new_data << (bits - num_bits);
self.value = padded_data ^ (((self.value + 1) << bits) - 1);
self.max_bits -= i64::from(bits);
self.check_post_renorm_invariants()
}
fn check_post_renorm_invariants(&self) -> Result<(), Error> {
const SYMBOL_RANGE_MIN: u32 = 1 << 15; const SYMBOL_RANGE_MAX: u32 = (1 << 16) - 1; if self.range < SYMBOL_RANGE_MIN || self.range > SYMBOL_RANGE_MAX {
return Err(Error::SymbolStateInvariantBroken);
}
if self.value >= self.range {
return Err(Error::SymbolStateInvariantBroken);
}
Ok(())
}
pub fn read_bool(&mut self) -> Result<u32, Error> {
let mut cdf: [u16; 3] = [1 << 14, 1 << 15, 0];
self.read_symbol(&mut cdf)
}
pub fn read_literal(&mut self, n: u32) -> Result<u32, Error> {
let mut x: u32 = 0;
for _ in 0..n {
x = 2 * x + self.read_bool()?;
}
Ok(x)
}
pub fn read_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.read_literal(w - 1)?;
if v < m {
return Ok(v);
}
let extra_bit = self.read_literal(1)?;
Ok((v << 1) - m + extra_bit)
}
pub fn decode_subexp_bool(&mut self, num_syms: u32, k: u32) -> Result<u32, Error> {
let mut i: u32 = 0;
let mut mk: u32 = 0;
loop {
let b2 = if i != 0 { k + i - 1 } else { k };
let a = 1u32 << b2;
if num_syms <= mk + 3 * a {
let subexp_unif_bools = self.read_ns(num_syms - mk)?;
return Ok(subexp_unif_bools + mk);
}
let subexp_more_bools = self.read_literal(1)?;
if subexp_more_bools != 0 {
i += 1;
mk += a;
} else {
let subexp_bools = self.read_literal(b2)?;
return Ok(subexp_bools + mk);
}
}
}
pub fn decode_unsigned_subexp_with_ref_bool(
&mut self,
mx: i64,
k: u32,
r: i64,
) -> Result<i64, Error> {
let v = i64::from(self.decode_subexp_bool(mx as u32, k)?);
if (r << 1) <= mx {
Ok(inverse_recenter(r, v))
} else {
Ok(mx - 1 - inverse_recenter(mx - 1 - r, v))
}
}
pub fn decode_signed_subexp_with_ref_bool(
&mut self,
low: i64,
high: i64,
k: u32,
r: i64,
) -> Result<i64, Error> {
let x = self.decode_unsigned_subexp_with_ref_bool(high - low, k, r - low)?;
Ok(x + low)
}
pub fn exit_symbol(&mut self) -> Result<(usize, usize), Error> {
if self.max_bits < -14 {
return Err(Error::SymbolExitUnderflow);
}
let pos = self.reader.position() as i64;
let trailing = pos - core::cmp::min(15, self.max_bits + 15);
let trailing_bit_position = trailing as usize;
let advance = self.max_bits.max(0) as usize;
let mut remaining = advance;
while remaining > 0 {
let chunk = core::cmp::min(remaining, 32) as u32;
self.reader.f(chunk)?;
remaining -= chunk as usize;
}
let padding_end_position = self.reader.position();
Ok((trailing_bit_position, padding_end_position))
}
}
pub(crate) fn update_cdf(cdf: &mut [u16], symbol: u32, n: u32) {
let count = u32::from(cdf[n as usize]);
let rate = 3 + u32::from(count > 15) + u32::from(count > 31) + core::cmp::min(floor_log2(n), 2);
let mut tmp: u32 = 0;
for i in 0..(n - 1) {
if i == symbol {
tmp = 1 << 15;
}
let c = u32::from(cdf[i as usize]);
let updated = if tmp < c {
c - ((c - tmp) >> rate)
} else {
c + ((tmp - c) >> rate)
};
cdf[i as usize] = updated as u16;
}
if count < 32 {
cdf[n as usize] = (count + 1) as u16;
}
}
pub(crate) fn update_cdf_for_encoder(cdf: &mut [u16], symbol: u32, n: u32) {
update_cdf(cdf, symbol, n);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn init_symbol_full_window() {
let bytes = [0b1010_1010u8, 0b1100_1100u8];
let d = SymbolDecoder::init_symbol(&bytes, 2, false).unwrap();
let buf: u32 = 0b101010101100110;
assert_eq!(buf, 21862);
assert_eq!(d.symbol_value(), 0x7FFF ^ 21862);
assert_eq!(d.symbol_range(), 1 << 15);
assert_eq!(d.symbol_max_bits(), 1);
assert_eq!(d.position(), 15);
}
#[test]
fn init_symbol_partial_window_left_shift() {
let bytes = [0b1011_0001u8];
let d = SymbolDecoder::init_symbol(&bytes, 1, false).unwrap();
let buf: u32 = 0b1011_0001; let padded = buf << (15 - 8); assert_eq!(d.symbol_value(), 0x7FFF ^ padded);
assert_eq!(d.symbol_range(), 1 << 15);
assert_eq!(d.symbol_max_bits(), 8 - 15); assert_eq!(d.position(), 8);
}
#[test]
fn read_symbol_boolean_cdf_trace() {
let bytes = [0x00u8, 0x02u8];
let mut d = SymbolDecoder::init_symbol(&bytes, 2, true).unwrap();
assert_eq!(d.symbol_value(), 0x7FFE);
let mut cdf: [u16; 3] = [1 << 14, 1 << 15, 0];
let sym = d.read_symbol(&mut cdf).unwrap();
assert_eq!(sym, 0);
assert_eq!(d.symbol_range(), 65520);
assert_eq!(d.symbol_value(), 65515);
assert_eq!(d.symbol_max_bits(), -1);
assert_eq!(d.position(), 16);
}
#[test]
fn read_bool_matches_boolean_trace() {
let bytes = [0x00u8, 0x02u8];
let mut d = SymbolDecoder::init_symbol(&bytes, 2, false).unwrap();
let bit = d.read_bool().unwrap();
assert_eq!(bit, 0);
assert_eq!(d.symbol_range(), 65520);
assert_eq!(d.symbol_value(), 65515);
}
#[test]
fn read_literal_composes_bits_msb_first() {
let bytes = [0x12u8, 0x34u8, 0x56u8, 0x78u8];
let mut d_lit = SymbolDecoder::init_symbol(&bytes, 4, true).unwrap();
let lit = d_lit.read_literal(3).unwrap();
let mut d_bits = SymbolDecoder::init_symbol(&bytes, 4, true).unwrap();
let b0 = d_bits.read_bool().unwrap();
let b1 = d_bits.read_bool().unwrap();
let b2 = d_bits.read_bool().unwrap();
let composed = (b0 << 2) | (b1 << 1) | b2;
assert_eq!(lit, composed);
assert_eq!(d_lit.symbol_value(), d_bits.symbol_value());
assert_eq!(d_lit.symbol_range(), d_bits.symbol_range());
assert_eq!(d_lit.position(), d_bits.position());
}
#[test]
fn update_cdf_adapts_toward_symbol() {
let mut cdf: [u16; 4] = [10000, 20000, 32768, 0];
update_cdf(&mut cdf, 1, 3);
assert_eq!(cdf, [9375, 20798, 32768, 1]);
}
#[test]
fn update_cdf_counter_caps_at_32() {
let mut cdf: [u16; 3] = [16384, 32768, 31];
update_cdf(&mut cdf, 0, 2);
assert_eq!(cdf[2], 32); let mut cdf2: [u16; 3] = [16384, 32768, 32];
update_cdf(&mut cdf2, 0, 2);
assert_eq!(cdf2[2], 32);
}
#[test]
fn read_symbol_adapts_cdf_when_enabled() {
let bytes = [0x80u8, 0x00u8, 0x00u8, 0x00u8];
let mut d = SymbolDecoder::init_symbol(&bytes, 4, false).unwrap();
let mut cdf: [u16; 4] = [10923, 21845, 32768, 0];
let before = cdf;
let _ = d.read_symbol(&mut cdf).unwrap();
assert_ne!(cdf, before, "§8.3 update should have mutated the CDF");
assert_eq!(cdf[3], 1, "counter incremented");
let mut d2 = SymbolDecoder::init_symbol(&bytes, 4, true).unwrap();
let mut cdf2: [u16; 4] = [10923, 21845, 32768, 0];
let before2 = cdf2;
let _ = d2.read_symbol(&mut cdf2).unwrap();
assert_eq!(cdf2, before2, "disable_cdf_update must leave CDF intact");
}
#[test]
fn read_ns_n_equals_1_consumes_no_arithmetic_bits() {
let bytes = [0xFFu8, 0x00u8];
let mut d = SymbolDecoder::init_symbol(&bytes, 2, true).unwrap();
let pos_before = d.position();
let v = d.read_ns(1).unwrap();
assert_eq!(v, 0);
assert_eq!(d.position(), pos_before);
}
#[test]
fn decode_subexp_bool_immediate_uniform_branch() {
let bytes = [0x00u8, 0x00u8, 0x00u8, 0x00u8];
let mut d = SymbolDecoder::init_symbol(&bytes, 4, true).unwrap();
let result = d.decode_subexp_bool(2, 0).unwrap();
assert!(result < 2);
let mut d2 = SymbolDecoder::init_symbol(&bytes, 4, true).unwrap();
let ns2 = d2.read_ns(2).unwrap();
assert_eq!(result, ns2);
assert_eq!(d.position(), d2.position());
}
#[test]
fn exit_symbol_advances_to_byte_boundary() {
let bytes = [0x80u8, 0x01u8];
let mut d = SymbolDecoder::init_symbol(&bytes, 2, true).unwrap();
assert_eq!(d.position(), 15);
let (trailing, padding_end) = d.exit_symbol().unwrap();
assert_eq!(trailing, 0);
assert_eq!(padding_end, 16);
assert_eq!(d.position(), 16);
assert_eq!(padding_end % 8, 0);
}
#[test]
fn exit_symbol_rejects_underflow() {
let bytes = [0x55u8];
let mut d = SymbolDecoder::init_symbol(&bytes, 1, true).unwrap();
for _ in 0..16 {
if d.symbol_max_bits() < -14 {
break;
}
let _ = d.read_bool().unwrap();
}
assert!(d.symbol_max_bits() < -14);
assert_eq!(d.exit_symbol().unwrap_err(), Error::SymbolExitUnderflow);
}
#[test]
fn decode_past_buffer_uses_padding_zeros() {
let bytes = [0xFFu8];
let mut d = SymbolDecoder::init_symbol(&bytes, 1, true).unwrap();
for _ in 0..8 {
let mut cdf: [u16; 3] = [1 << 14, 1 << 15, 0];
let r = d.read_symbol(&mut cdf);
assert!(r.is_ok());
}
}
#[test]
fn post_renorm_range_in_top_half_across_decodes() {
let starts: [[u8; 4]; 4] = [
[0x00, 0x00, 0x00, 0x00],
[0xFF, 0xFF, 0xFF, 0xFF],
[0x80, 0x01, 0x42, 0x37],
[0x55, 0xAA, 0x33, 0xCC],
];
for bytes in &starts {
let mut d = SymbolDecoder::init_symbol(bytes, bytes.len(), true).unwrap();
for _ in 0..16 {
let mut cdf: [u16; 3] = [1 << 14, 1 << 15, 0];
d.read_symbol(&mut cdf).unwrap();
let r = d.symbol_range();
assert!(
(1u32 << 15..=u32::from(u16::MAX)).contains(&r),
"§8.2.6 invariant #1 broken: SymbolRange = {r}"
);
}
}
}
#[test]
fn post_renorm_value_below_range_across_decodes() {
let starts: [[u8; 4]; 4] = [
[0x00, 0x00, 0x00, 0x00],
[0xFF, 0xFF, 0xFF, 0xFF],
[0x80, 0x01, 0x42, 0x37],
[0x55, 0xAA, 0x33, 0xCC],
];
for bytes in &starts {
let mut d = SymbolDecoder::init_symbol(bytes, bytes.len(), true).unwrap();
for _ in 0..16 {
let mut cdf: [u16; 3] = [1 << 14, 1 << 15, 0];
d.read_symbol(&mut cdf).unwrap();
assert!(
d.symbol_value() < d.symbol_range(),
"§8.2.6 invariant #2 broken: SymbolValue={}, SymbolRange={}",
d.symbol_value(),
d.symbol_range()
);
}
}
}
#[test]
fn invariant_check_returns_error_on_each_violation() {
let bytes = [0x00u8, 0x00u8];
let mut d = SymbolDecoder::init_symbol(&bytes, 2, true).unwrap();
d.value = 1;
d.range = 1 << 15;
assert!(d.check_post_renorm_invariants().is_ok());
d.value = 65534;
d.range = 65535;
assert!(d.check_post_renorm_invariants().is_ok());
d.value = 0;
d.range = (1 << 15) - 1;
assert_eq!(
d.check_post_renorm_invariants().unwrap_err(),
Error::SymbolStateInvariantBroken
);
d.value = 0;
d.range = (1 << 16) + 1;
assert_eq!(
d.check_post_renorm_invariants().unwrap_err(),
Error::SymbolStateInvariantBroken
);
d.value = 1 << 15;
d.range = 1 << 15;
assert_eq!(
d.check_post_renorm_invariants().unwrap_err(),
Error::SymbolStateInvariantBroken
);
}
#[test]
fn invariants_hold_across_adaptive_multisymbol_run() {
let bytes: [u8; 16] = [
0x9F, 0x12, 0x37, 0xAB, 0x4C, 0xDE, 0x5F, 0x68, 0x71, 0x82, 0x93, 0xA4, 0xB5, 0xC6,
0xD7, 0xE8,
];
let mut d = SymbolDecoder::init_symbol(&bytes, bytes.len(), false).unwrap();
let mut cdf: [u16; 5] = [8192, 16384, 24576, 32768, 0];
for _ in 0..40 {
d.read_symbol(&mut cdf).unwrap();
let r = d.symbol_range();
let v = d.symbol_value();
assert!(
(1u32 << 15..=u32::from(u16::MAX)).contains(&r),
"invariant #1 broken: SymbolRange = {r}"
);
assert!(
v < r,
"invariant #2 broken: SymbolValue={v} SymbolRange={r}"
);
}
}
}