pub struct BitReader<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> BitReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data, pos: 0 }
}
pub fn byte_pos(&self) -> usize {
self.pos / 8
}
pub fn is_byte_aligned(&self) -> bool {
self.pos % 8 == 0
}
fn bits_left(&self) -> usize {
self.data.len() * 8 - self.pos
}
pub fn read_raw_u32(&mut self, bits: u32) -> Option<u32> {
debug_assert!(bits <= 32);
if bits == 0 {
return Some(0);
}
if bits as usize > self.bits_left() {
return None;
}
let mut v = 0u32;
for _ in 0..bits {
let byte = self.data[self.pos >> 3];
let bit = (byte >> (7 - (self.pos & 7))) & 1;
v = (v << 1) | bit as u32;
self.pos += 1;
}
Some(v)
}
pub fn read_raw_u64(&mut self, bits: u32) -> Option<u64> {
debug_assert!(bits <= 64);
if bits > 32 {
let hi = self.read_raw_u32(bits - 32)? as u64;
let lo = self.read_raw_u32(32)? as u64;
Some((hi << 32) | lo)
} else {
Some(self.read_raw_u32(bits)? as u64)
}
}
pub fn read_signed(&mut self, bits: u32) -> Option<i64> {
let v = self.read_raw_u64(bits)?;
Some(sign_extend(v, bits))
}
pub fn read_unary(&mut self) -> Option<u32> {
let mut count = 0u32;
loop {
if self.read_raw_u32(1)? == 1 {
return Some(count);
}
count += 1;
}
}
pub fn read_rice_signed(&mut self, parameter: u32) -> Option<i32> {
let msbs = self.read_unary()?;
let lsbs = self.read_raw_u32(parameter)?;
let uval = (msbs << parameter) | lsbs;
Some(((uval >> 1) as i32) ^ -((uval & 1) as i32))
}
pub fn read_rice_signed_block(&mut self, out: &mut [i32], parameter: u32) -> Option<()> {
for o in out.iter_mut() {
*o = self.read_rice_signed(parameter)?;
}
Some(())
}
pub fn read_utf8_u32(&mut self) -> Option<u32> {
let x = self.read_raw_u32(8)?;
let (mut v, n) = if x & 0x80 == 0 {
(x, 0)
} else if x & 0xC0 != 0 && x & 0x20 == 0 {
(x & 0x1F, 1)
} else if x & 0xE0 != 0 && x & 0x10 == 0 {
(x & 0x0F, 2)
} else if x & 0xF0 != 0 && x & 0x08 == 0 {
(x & 0x07, 3)
} else if x & 0xF8 != 0 && x & 0x04 == 0 {
(x & 0x03, 4)
} else if x & 0xFC != 0 && x & 0x02 == 0 {
(x & 0x01, 5)
} else {
return Some(0xFFFF_FFFF);
};
for _ in 0..n {
let x = self.read_raw_u32(8)?;
if x & 0x80 == 0 || x & 0x40 != 0 {
return Some(0xFFFF_FFFF);
}
v = (v << 6) | (x & 0x3F);
}
Some(v)
}
pub fn read_utf8_u64(&mut self) -> Option<u64> {
let x = self.read_raw_u32(8)? as u64;
let (mut v, n) = if x & 0x80 == 0 {
(x, 0)
} else if x & 0xC0 != 0 && x & 0x20 == 0 {
(x & 0x1F, 1)
} else if x & 0xE0 != 0 && x & 0x10 == 0 {
(x & 0x0F, 2)
} else if x & 0xF0 != 0 && x & 0x08 == 0 {
(x & 0x07, 3)
} else if x & 0xF8 != 0 && x & 0x04 == 0 {
(x & 0x03, 4)
} else if x & 0xFC != 0 && x & 0x02 == 0 {
(x & 0x01, 5)
} else if x & 0xFE != 0 && x & 0x01 == 0 {
(0, 6) } else {
return Some(0xFFFF_FFFF_FFFF_FFFF);
};
for _ in 0..n {
let x = self.read_raw_u32(8)? as u64;
if x & 0x80 == 0 || x & 0x40 != 0 {
return Some(0xFFFF_FFFF_FFFF_FFFF);
}
v = (v << 6) | (x & 0x3F);
}
Some(v)
}
pub fn align_to_byte(&mut self) {
self.pos = (self.pos + 7) & !7;
}
pub fn skip_bytes(&mut self, n: usize) -> Option<()> {
debug_assert!(self.is_byte_aligned());
if n * 8 > self.bits_left() {
return None;
}
self.pos += n * 8;
Some(())
}
pub fn bytes_since(&self, start: usize) -> &'a [u8] {
&self.data[start..self.pos / 8]
}
}
fn sign_extend(v: u64, bits: u32) -> i64 {
if bits == 0 || bits >= 64 {
return v as i64;
}
let shift = 64 - bits;
((v << shift) as i64) >> shift
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bitwriter::BitWriter;
#[test]
fn raw_round_trips() {
let mut bw = BitWriter::new();
bw.write_raw_u32(0xABCD, 16);
bw.write_raw_u32(0b101, 3);
bw.write_raw_u32(0x1FFFFF, 21);
bw.write_raw_u64(0x1_2345_6789, 33);
bw.zero_pad_to_byte_boundary();
let bytes = bw.as_bytes().to_vec();
let mut br = BitReader::new(&bytes);
assert_eq!(br.read_raw_u32(16), Some(0xABCD));
assert_eq!(br.read_raw_u32(3), Some(0b101));
assert_eq!(br.read_raw_u32(21), Some(0x1FFFFF));
assert_eq!(br.read_raw_u64(33), Some(0x1_2345_6789));
}
#[test]
fn signed_round_trips() {
let mut bw = BitWriter::new();
for &(v, bits) in &[
(-1i64, 4),
(-2, 4),
(32767, 16),
(-32768, 16),
(-(1 << 32), 33),
] {
bw.write_raw_i64(v, bits);
}
bw.zero_pad_to_byte_boundary();
let bytes = bw.as_bytes().to_vec();
let mut br = BitReader::new(&bytes);
for &(v, bits) in &[
(-1i64, 4),
(-2, 4),
(32767, 16),
(-32768, 16),
(-(1 << 32), 33),
] {
assert_eq!(br.read_signed(bits), Some(v), "{v} @ {bits} bits");
}
}
#[test]
fn unary_round_trips() {
let mut bw = BitWriter::new();
for v in [0u32, 1, 3, 10, 0, 200] {
bw.write_unary_unsigned(v);
}
bw.zero_pad_to_byte_boundary();
let bytes = bw.as_bytes().to_vec();
let mut br = BitReader::new(&bytes);
for v in [0u32, 1, 3, 10, 0, 200] {
assert_eq!(br.read_unary(), Some(v));
}
}
#[test]
fn rice_block_round_trips() {
let vals: Vec<i32> = vec![0, -1, 1, -2, 2, 100, -100, 5000, -5000, 7, -3];
for param in [0u32, 1, 4, 8, 14, 30] {
let mut bw = BitWriter::new();
bw.write_rice_signed_block(&vals, param);
bw.zero_pad_to_byte_boundary();
let bytes = bw.as_bytes().to_vec();
let mut br = BitReader::new(&bytes);
let mut out = vec![0i32; vals.len()];
br.read_rice_signed_block(&mut out, param).unwrap();
assert_eq!(out, vals, "param {param}");
}
}
#[test]
fn utf8_round_trips() {
for v in [
0u32, 0x7F, 0x80, 0x7FF, 0x800, 0xFFFF, 0x10_FFFF, 0x1F_FFFF, 0x20_0000,
] {
let mut bw = BitWriter::new();
bw.write_utf8_u32(v);
bw.zero_pad_to_byte_boundary();
let bytes = bw.as_bytes().to_vec();
let mut br = BitReader::new(&bytes);
assert_eq!(br.read_utf8_u32(), Some(v), "utf8 {v:#x}");
}
}
#[test]
fn utf8_u64_round_trips() {
for v in [
0u64,
0x7F,
0x80,
0x7FF,
0x800,
0xFFFF,
0x1F_FFFF,
0x20_0000,
0x7FFF_FFFF,
0x8000_0000,
0xF_FFFF_FFFF,
] {
let mut bw = BitWriter::new();
bw.write_utf8_u64(v);
bw.zero_pad_to_byte_boundary();
let bytes = bw.as_bytes().to_vec();
let mut br = BitReader::new(&bytes);
assert_eq!(br.read_utf8_u64(), Some(v), "utf8_u64 {v:#x}");
}
}
}