const LO: u64 = 0x0101_0101_0101_0101;
const HI: u64 = 0x8080_8080_8080_8080;
#[inline(always)]
fn any_byte_ff(w: u64) -> bool {
let x = !w;
(x.wrapping_sub(LO)) & !x & HI != 0
}
pub struct BitStream<'a> {
data: &'a [u8],
pos: usize,
bits: u64,
avail: i32,
prefetch: usize,
overran: bool,
}
pub struct BitCursor<'a> {
data: &'a [u8],
pos: usize,
bits: u64,
avail: i32,
prefetch: usize,
overran: bool,
}
impl<'a> BitStream<'a> {
#[cfg(test)]
pub fn new(data: &'a [u8], offset: usize) -> Self {
Self::with_prefetch(data, offset, 192)
}
pub fn with_prefetch(data: &'a [u8], offset: usize, prefetch: usize) -> Self {
let mut bs = Self {
data,
pos: offset,
bits: 0,
avail: 0,
prefetch,
overran: false,
};
bs.refill();
bs
}
#[allow(dead_code)]
pub fn position(&self) -> usize {
self.pos
}
#[inline(always)]
pub fn cursor(&self) -> BitCursor<'a> {
BitCursor {
data: self.data,
pos: self.pos,
bits: self.bits,
avail: self.avail,
prefetch: self.prefetch,
overran: self.overran,
}
}
#[inline(always)]
pub fn commit(&mut self, cur: BitCursor<'a>) {
self.pos = cur.pos;
self.bits = cur.bits;
self.avail = cur.avail;
self.overran = cur.overran;
}
}
impl<'a> BitCursor<'a> {
#[inline(always)]
fn prefetch_ahead(&self) {
if self.prefetch == 0 {
return;
}
let idx = self.pos + self.prefetch;
if idx < self.data.len() {
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!(
"prfm pldl1keep, [{ptr}]",
ptr = in(reg) self.data.as_ptr().add(idx),
options(nostack, preserves_flags, readonly)
);
}
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::x86_64::_mm_prefetch(
self.data.as_ptr().add(idx) as *const i8,
core::arch::x86_64::_MM_HINT_T0,
);
}
}
}
#[inline(always)]
pub fn refill(&mut self) {
if self.avail >= 32 {
return;
}
if self.pos + 8 <= self.data.len() {
let w = u64::from_be(unsafe {
(self.data.as_ptr().add(self.pos) as *const u64).read_unaligned()
});
if !any_byte_ff(w) {
let avail = self.avail; let take = (64 - avail) & !7; self.bits |= (w >> (64 - take)) << (64 - avail - take);
self.pos += (take >> 3) as usize;
self.avail = avail + take;
self.prefetch_ahead();
return;
}
}
self.refill_slow();
}
#[inline(always)]
fn refill_slow(&mut self) {
if self.avail < 0 {
self.overran = true;
self.avail = 0;
}
while self.avail <= 56 {
if self.pos >= self.data.len() {
break;
}
let b = self.data[self.pos];
if b == 0xFF {
if self.pos + 1 < self.data.len() && self.data[self.pos + 1] == 0x00 {
self.pos += 2; } else {
break; }
} else {
self.pos += 1;
}
self.bits |= (b as u64) << (56 - self.avail);
self.avail += 8;
}
}
#[inline(always)]
pub fn peek(&self, n: u8) -> u32 {
debug_assert!((1..=56).contains(&n));
(self.bits >> (64 - n as u32)) as u32
}
#[inline(always)]
pub fn consume(&mut self, n: u8) {
self.bits <<= n;
self.avail -= n as i32;
}
#[inline(always)]
pub fn get_bits(&mut self, n: u8) -> u32 {
let val = self.peek(n);
self.consume(n);
val
}
}
impl<'a> BitStream<'a> {
#[inline]
fn refill(&mut self) {
let mut cur = self.cursor();
cur.refill();
self.commit(cur);
}
#[inline]
pub fn overran(&self) -> bool {
self.overran
}
#[cfg(test)]
pub fn read_bits(&mut self, n: u8) -> u32 {
let mut cur = self.cursor();
cur.refill();
let val = cur.get_bits(n);
self.commit(cur);
val
}
#[inline(always)]
pub fn extend(val: u32, nbits: u8) -> i32 {
debug_assert!((1..=15).contains(&nbits));
let vt = val as i32;
let m = 1i32 << (nbits - 1);
vt + (((vt - m) >> 31) & (((-1i32) << nbits) + 1))
}
pub fn align_to_byte(&mut self) {
self.bits = 0;
self.avail = 0;
}
pub fn skip_restart_marker(&mut self) -> bool {
self.align_to_byte();
while self.pos + 1 < self.data.len() {
if self.data[self.pos] == 0xFF {
let m = self.data[self.pos + 1];
if (0xD0..=0xD7).contains(&m) {
self.pos += 2;
self.refill();
return true;
} else if m == 0x00 {
self.pos += 2;
continue;
} else {
break;
}
}
self.pos += 1;
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn read_bits_basic() {
let data = [0b1010_1100, 0b0011_0000];
let mut bs = BitStream::new(&data, 0);
assert_eq!(bs.read_bits(4), 0b1010);
assert_eq!(bs.read_bits(4), 0b1100);
assert_eq!(bs.read_bits(4), 0b0011);
}
#[test]
fn byte_stuffing() {
let data = [0xFF, 0x00, 0xAB];
let mut bs = BitStream::new(&data, 0);
assert_eq!(bs.read_bits(8), 0xFF);
assert_eq!(bs.read_bits(8), 0xAB);
}
#[test]
fn extend_positive() {
assert_eq!(BitStream::extend(5, 3), 5);
assert_eq!(BitStream::extend(7, 3), 7);
}
#[test]
fn extend_negative() {
assert_eq!(BitStream::extend(0, 3), -7);
assert_eq!(BitStream::extend(1, 3), -6);
assert_eq!(BitStream::extend(3, 3), -4);
}
#[test]
fn extend_one_bit() {
assert_eq!(BitStream::extend(0, 1), -1);
assert_eq!(BitStream::extend(1, 1), 1);
}
#[test]
fn bulk_refill_allows_high_bit_non_ff() {
let data = [0x80, 0x81, 0x7E, 0x7F, 0x01, 0x02, 0x03, 0x04];
let mut bs = BitStream::new(&data, 0);
assert!(bs.avail >= 32, "expected bulk refill, avail={}", bs.avail);
assert_eq!(bs.read_bits(8), 0x80);
assert_eq!(bs.read_bits(8), 0x81);
assert_eq!(bs.read_bits(8), 0x7E);
assert_eq!(bs.read_bits(8), 0x7F);
}
#[test]
fn bulk_refill_aborts_on_ff_stuffing() {
let data = [0x11, 0xFF, 0x00, 0x22, 0x33, 0x44, 0x55, 0x66];
let mut bs = BitStream::new(&data, 0);
assert_eq!(bs.read_bits(8), 0x11);
assert_eq!(bs.read_bits(8), 0xFF);
assert_eq!(bs.read_bits(8), 0x22);
}
#[test]
fn swar_ff_detector() {
assert!(!any_byte_ff(0x1122_3344_5566_7788));
assert!(!any_byte_ff(0x0000_0000_0000_0000));
assert!(!any_byte_ff(0x80FE_7F01_ECAB_1002));
for lane in 0..8 {
let w = 0x1122_3344_5566_7788u64 & !(0xFFu64 << (lane * 8)) | (0xFFu64 << (lane * 8));
assert!(any_byte_ff(w), "lane {lane}");
}
}
#[test]
fn refill_parity_random_reads() {
let mut state = 0x1234_5678u32;
let mut next = move || {
state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
state
};
let data: Vec<u8> = (0..4096).map(|_| (next() % 0xFF) as u8).collect();
let mut bs = BitStream::new(&data, 0);
let mut bitpos = 0usize; for _ in 0..2000 {
let n = (next() % 16 + 1) as u8; if bitpos + n as usize > data.len() * 8 {
break;
}
let mut expect = 0u32;
for _ in 0..n {
let byte = data[bitpos / 8];
let bit = (byte >> (7 - (bitpos % 8))) & 1;
expect = (expect << 1) | bit as u32;
bitpos += 1;
}
assert_eq!(bs.read_bits(n), expect, "at bitpos {bitpos} n={n}");
}
}
#[test]
fn refill_parity_with_stuffing() {
let mut raw = Vec::new(); let mut data = Vec::new(); let mut state = 0x9E37_79B9u32;
let mut next = move || {
state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
state
};
for i in 0..2048 {
let b = if i % 37 == 0 {
0xFF
} else {
(next() % 0xFF) as u8
};
raw.push(b);
data.push(b);
if b == 0xFF {
data.push(0x00);
}
}
let mut bs = BitStream::new(&data, 0);
let mut bitpos = 0usize;
loop {
let n = (next() % 12 + 1) as u8;
if bitpos + n as usize > raw.len() * 8 - 64 {
break;
}
let mut expect = 0u32;
for _ in 0..n {
let byte = raw[bitpos / 8];
let bit = (byte >> (7 - (bitpos % 8))) & 1;
expect = (expect << 1) | bit as u32;
bitpos += 1;
}
assert_eq!(bs.read_bits(n), expect, "at bitpos {bitpos} n={n}");
}
}
}