pub struct BitWriter {
buf: Vec<u8>,
bit_pos: u32,
current: u8,
}
impl Default for BitWriter {
fn default() -> Self {
Self::new()
}
}
impl BitWriter {
pub fn new() -> Self {
Self {
buf: Vec::with_capacity(256),
bit_pos: 0,
current: 0,
}
}
pub fn write_bits(&mut self, value: u64, nbits: u32) {
let mut val = value;
let mut bits = nbits;
while bits > 0 {
let space = 8 - self.bit_pos;
let take = std::cmp::min(space, bits);
let mask = (1u64 << take) - 1;
self.current |= ((val & mask) as u8) << self.bit_pos;
val >>= take;
bits -= take;
self.bit_pos += take;
if self.bit_pos == 8 {
self.buf.push(self.current);
self.current = 0;
self.bit_pos = 0;
}
}
}
pub fn finish(mut self) -> Vec<u8> {
if self.bit_pos > 0 {
self.buf.push(self.current);
}
self.buf
}
pub fn len(&self) -> usize {
self.buf.len() * 8 + self.bit_pos as usize
}
}
pub struct BackwardBitWriter {
container: u64,
bit_pos: u32,
buf: Vec<u8>,
}
impl Default for BackwardBitWriter {
fn default() -> Self {
Self::new()
}
}
impl BackwardBitWriter {
pub fn new() -> Self {
Self {
container: 0,
bit_pos: 0,
buf: Vec::with_capacity(256),
}
}
#[inline]
pub fn add_bits(&mut self, value: u64, nbits: u32) {
if nbits == 0 {
return;
}
debug_assert!(nbits <= 57);
debug_assert!(self.bit_pos + nbits <= 64);
let mask = if nbits >= 64 {
u64::MAX
} else {
(1u64 << nbits) - 1
};
self.container |= (value & mask) << self.bit_pos;
self.bit_pos += nbits;
}
#[inline]
pub fn flush_bits(&mut self) {
let nb_bytes = (self.bit_pos / 8) as usize;
for i in 0..nb_bytes {
self.buf.push((self.container >> (i * 8)) as u8);
}
self.container >>= nb_bytes * 8;
self.bit_pos &= 7;
}
pub fn finish(mut self) -> Vec<u8> {
self.add_bits(1, 1);
self.flush_bits();
if self.bit_pos > 0 {
self.buf.push(self.container as u8);
}
self.buf
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bit_writer_basic() {
let mut w = BitWriter::new();
w.write_bits(0b101, 3);
w.write_bits(0b1100, 4);
w.write_bits(0b1, 1);
let bytes = w.finish();
assert_eq!(bytes, vec![0xE5]);
}
#[test]
fn backward_writer_sentinel_only() {
let w = BackwardBitWriter::new();
let result = w.finish();
assert_eq!(result, vec![0x01]);
}
#[test]
fn backward_writer_c_layout() {
let mut w = BackwardBitWriter::new();
w.add_bits(0xFF, 8);
w.flush_bits();
w.add_bits(0xAB, 8);
let result = w.finish();
assert_eq!(result, vec![0xFF, 0xAB, 0x01]);
}
}