Skip to content

Commit

Permalink
Merge pull request #57 from nickbabcock/be-fast
Browse files Browse the repository at this point in the history
Faster unaligned big endian buffer reads
  • Loading branch information
nickbabcock authored Dec 19, 2024
2 parents 0da3e85 + f52c5db commit 6d6da7c
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 13 deletions.
12 changes: 12 additions & 0 deletions fuzz/fuzz_targets/fuzz_simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,16 @@ fuzz_target!(|data: &[u8]| {
while bitter.has_bits_remaining(bits as usize) {
assert_eq!(io.read(bits).ok(), bitter.read_bits(bits))
}

let mut io = bitstream_io::BitReader::endian(data, bitstream_io::BigEndian);
let mut bitter = BigEndianReader::new(&data);
assert_eq!(io.read(bits).ok(), bitter.read_bits(bits));
let mut out1 = vec![0; 12];
let mut out2 = vec![0; 12];
let result1 = io.read_bytes(&mut out1);
let result2 = bitter.read_bytes(&mut out2);
assert_eq!(result1.is_ok(), result2);
if result2 {
assert_eq!(out1, out2);
}
});
34 changes: 21 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -798,33 +798,30 @@ impl<'a, const LE: bool> BitReader for BitterState<'a, LE> {
self.data = tail;
self.bit_buf = 0;
self.refill_lookahead();
} else if !LE {
self.refill_lookahead();
for dst in buf.iter_mut() {
if self.lookahead_bits() < 8 {
self.refill_lookahead();
debug_assert!(self.lookahead_bits() >= 8);
}

*dst = self.peek(8) as u8;
self.consume(8);
}
} else if let Some((first, buf)) = buf.split_first_mut() {
// Consume the rest of the lookahead
let lookahead_remainder = self.bit_count;
let lookahead_tail = self.peek(lookahead_remainder) as u8;
self.consume(lookahead_remainder);

// lookahead now empty, but adjust overlapping data byte
*first = (head[0] << lookahead_remainder) + lookahead_tail;
*first = if LE {
(head[0] << lookahead_remainder) + lookahead_tail
} else {
(head[0] >> lookahead_remainder) + (lookahead_tail << (8 - lookahead_remainder))
};

// Then attempt to process multiple 16 bytes at once
let chunk_size = 16;
let buf_chunks = buf.len() / chunk_size;
let chunk_bytes = buf_chunks * chunk_size;

let (buf_body, buf) = buf.split_at_mut(chunk_bytes);
read_n_bytes(lookahead_remainder, head, buf_body);
if LE {
read_n_bytes(lookahead_remainder, head, buf_body);
} else {
read_n_bytes_be(lookahead_remainder, head, buf_body);
}

// Process trailing bytes that don't fit into chunk
//
Expand Down Expand Up @@ -1248,6 +1245,17 @@ fn read_n_bytes(rem: u32, input: &[u8], out: &mut [u8]) {
}
}

#[inline]
fn read_n_bytes_be(rem: u32, input: &[u8], out: &mut [u8]) {
let mask = (1 << rem) - 1;

for (i, o) in input.windows(2).zip(out.iter_mut()) {
let left_part = (i[0] & mask) << (8 - rem);
let right_part = i[1] >> rem;
*o = left_part | right_part;
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down

0 comments on commit 6d6da7c

Please sign in to comment.