pub struct Bits<'a> {
data: &'a [u8],
pos: usize,
buf: u64,
live: u32,
}
impl<'a> Bits<'a> {
pub fn at(data: &'a [u8], bit: u64) -> Self {
let mut b = Bits {
data,
pos: (bit / 8) as usize,
buf: 0,
live: 0,
};
let r = (bit % 8) as u32;
if r != 0 {
b.refill();
b.skip(r);
}
b
}
#[inline(always)]
pub fn refill(&mut self) {
if let Some(w) = self.data.get(self.pos..self.pos + 8) {
let v = u64::from_be_bytes(w.try_into().unwrap());
self.buf |= v >> self.live;
let take = (63 - self.live) >> 3;
self.pos += take as usize;
self.live += take * 8;
} else {
self.refill_slow();
}
}
#[cold]
fn refill_slow(&mut self) {
while self.live <= 56 {
let b = self.data.get(self.pos).copied().unwrap_or(0);
self.pos += 1;
self.buf |= (b as u64) << (56 - self.live);
self.live += 8;
}
}
#[inline(always)]
pub fn peek(&mut self, n: u32) -> u32 {
debug_assert!((1..=32).contains(&n));
if self.live < n {
self.refill();
}
(self.buf >> (64 - n)) as u32
}
#[inline(always)]
pub fn peek_live(&self, n: u32) -> u32 {
debug_assert!((1..=32).contains(&n) && n <= self.live);
(self.buf >> (64 - n)) as u32
}
#[inline(always)]
pub fn skip_short(&mut self, n: u32) {
debug_assert!(n < 64 && n <= self.live);
self.buf <<= n & 63;
self.live -= n;
}
#[inline(always)]
pub fn skip(&mut self, n: u32) {
debug_assert!(n <= self.live);
self.buf = if n >= 64 { 0 } else { self.buf << n };
self.live -= n;
}
#[inline(always)]
pub fn bits(&mut self, n: u32) -> u32 {
let v = self.peek(n);
self.skip(n);
v
}
#[inline(always)]
pub fn bit(&mut self) -> bool {
self.bits(1) == 1
}
pub fn bit_pos(&self) -> u64 {
self.pos as u64 * 8 - self.live as u64
}
pub fn overran(&self) -> bool {
self.bit_pos() > self.data.len() as u64 * 8
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reads_bits_at_any_offset() {
let data: Vec<u8> = (0..40u32).map(|i| (i * 37 + 11) as u8).collect();
let all: Vec<bool> = data
.iter()
.flat_map(|&b| (0..8).rev().map(move |k| b >> k & 1 == 1))
.collect();
for start in 0..70u64 {
for n in 1..=32u32 {
let mut b = Bits::at(&data, start);
let mut at = start as usize;
while at + n as usize <= all.len() {
let want = all[at..at + n as usize]
.iter()
.fold(0u32, |v, &x| v << 1 | x as u32);
assert_eq!(b.bits(n), want, "start {start} n {n} at {at}");
at += n as usize;
assert_eq!(b.bit_pos(), at as u64);
}
assert!(!b.overran());
b.bits(32);
b.bits(32);
assert!(b.overran());
}
}
}
}