#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct BitAccumulator {
acc: u64,
bits: usize,
}
impl BitAccumulator {
#[inline]
pub const fn new() -> Self {
Self { acc: 0, bits: 0 }
}
#[inline]
pub const fn push_bits(&mut self, v: u64, n: usize) {
debug_assert!(n <= 56, "push_bits: too many bits");
let mask = (1u64 << n) - 1;
self.acc = (self.acc << n) | (v & mask);
self.bits += n;
}
#[inline]
pub const fn take_bits(&mut self, n: usize) -> u64 {
debug_assert!(n <= self.bits, "take_bits: not enough bits");
let shift = self.bits - n;
let v = (self.acc >> shift) & ((1u64 << n) - 1);
self.acc &= (1u64 << shift) - 1;
self.bits = shift;
v
}
#[inline]
pub const fn can_take(&self, n: usize) -> bool {
self.bits >= n
}
#[inline]
pub const fn bits(&self) -> usize {
self.bits
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bitacc_msb_first_roundtrip_bytes() {
let mut acc = BitAccumulator::new();
acc.push_bits(0b1111_0111, 8);
assert_eq!(acc.take_bits(1), 1);
assert_eq!(acc.take_bits(1), 1);
assert_eq!(acc.take_bits(1), 1);
assert_eq!(acc.take_bits(1), 1);
assert_eq!(acc.take_bits(1), 0);
assert_eq!(acc.take_bits(3), 0b111);
assert_eq!(acc.bits(), 0);
}
}