1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 08:34:07 +02:00

usize reading

This commit is contained in:
Robin Appelman 2019-02-14 22:29:03 +01:00
commit f5aff2cd80
2 changed files with 50 additions and 80 deletions

View file

@ -21,8 +21,8 @@ pub enum ReadError {
pub type Result<T> = std::result::Result<T, ReadError>;
pub struct BitBuffer {
bytes: Vec<u8>,
pub struct BitBuffer<'a> {
bytes: &'a [u8],
bit_len: usize,
byte_len: usize,
}
@ -46,37 +46,6 @@ macro_rules! array_ref {
const USIZE_SIZE: usize = std::mem::size_of::<usize>();
macro_rules! bitreader_unsigned_le {
($buffer:expr, $type:ty, $position:expr, $count:expr) => {
{
let size: usize = size_of::<$type>() * 8;
if $count > size {
return Err(ReadError::TooManyBits { requested: $count, max: size });
}
let bits_left = $buffer.bit_len() - $position;
if $count > bits_left {
return Err(ReadError::NotEnoughData { requested: $count, bits_left});
}
let byte_index = $position / 8;
let bit_offset = $position & 7;
let bytes:&[u8; USIZE_SIZE] = array_ref!($buffer.bytes(), byte_index, USIZE_SIZE);
let container_le = unsafe {
std::mem::transmute::<[u8; USIZE_SIZE], usize>(*bytes)
};
let container = usize::from_le(container_le);
let shifted = container >> bit_offset;
let mask = if $count == (USIZE_SIZE * 8) {usize::max_value()} else {!(usize::max_value() << $count)};
let value = shifted & mask;
Ok(value as $type)
}
}
}
macro_rules! make_signed {
($unsigned:expr, $type:ty, $count:expr) => {
{
@ -87,32 +56,15 @@ macro_rules! make_signed {
}
}
impl BitBuffer {
pub fn from_slice(data: &[u8]) -> BitBuffer {
let mut bytes = vec![];
bytes.extend_from_slice(data);
BitBuffer::from_vec(bytes)
}
pub fn from_vec(mut bytes: Vec<u8>) -> BitBuffer {
let byte_len = bytes.len();
// add leading 0 bytes for overflow during reading
bytes.resize(byte_len + size_of::<usize>(), 0);
BitBuffer::from_padded_vec(&bytes, byte_len)
}
pub fn from_padded_vec(bytes: &Vec<u8>, byte_len: usize) -> BitBuffer {
impl<'a> BitBuffer<'a> {
pub fn from_padded_slice(bytes: &'a [u8], byte_len: usize) -> BitBuffer<'a> {
BitBuffer {
bytes: bytes.to_vec(),
bit_len: byte_len * 8,
bytes,
byte_len,
bit_len: byte_len * 8,
}
}
fn bytes(&self) -> &[u8] {
self.bytes.as_slice()
}
pub fn bit_len(&self) -> usize {
self.bit_len
}
@ -121,31 +73,47 @@ impl BitBuffer {
self.byte_len
}
pub fn read_u8(&self, position: usize, count: usize) -> Result<u8> {
self.bytes.
bitreader_unsigned_le!(self, u8, position, count)
pub fn read_usize(&self, position: usize, count: usize) -> usize {
let byte_index = position / 8;
let bit_offset = position & 7;
let bytes:&[u8; USIZE_SIZE] = array_ref!(self.bytes, byte_index, USIZE_SIZE);
let container_le = unsafe {
std::mem::transmute::<[u8; USIZE_SIZE], usize>(*bytes)
};
let container = usize::from_le(container_le);
let shifted = container >> bit_offset;
let mask = !(usize::max_value() << count);
shifted & mask
}
pub fn read_u16(&self, position: usize, count: usize) -> Result<u16> {
bitreader_unsigned_le!(self, u16, position, count)
pub fn read_u8(&self, position: usize, count: usize) -> u8 {
self.read_usize(position, count) as u8
}
pub fn read_u32(&self, position: usize, count: usize) -> Result<u32> {
bitreader_unsigned_le!(self, u32, position, count)
pub fn read_u16(&self, position: usize, count: usize) -> u16 {
self.read_usize(position, count) as u16
}
pub fn read_i8(&self, position: usize, count: usize) -> Result<i8> {
let unsigned = self.read_u8(position, count)?;
Ok(make_signed!(unsigned, i8, count))
pub fn read_u32(&self, position: usize, count: usize) -> u32 {
if size_of::<usize>() > size_of::<u32>() {
self.read_usize(position, count) as u32
} else {
let value:u32 = (self.read_u16(position, count) as u32) << 16;
value | self.read_u16(position + 16, count - 16) as u32
}
}
pub fn read_i8(&self, position: usize, count: usize) -> i8 {
let unsigned = self.read_u8(position, count);
make_signed!(unsigned, i8, count)
}
pub fn read_i16(&self, position: usize, count: usize) -> Result<i16> {
let unsigned = self.read_u16(position, count)?;
Ok(make_signed!(unsigned, i16, count))
pub fn read_i16(&self, position: usize, count: usize) -> i16 {
let unsigned = self.read_u16(position, count);
make_signed!(unsigned, i16, count)
}
pub fn read_i32(&self, position: usize, count: usize) -> Result<i32> {
let unsigned = self.read_u32(position, count)?;
Ok(make_signed!(unsigned, i32, count))
pub fn read_i32(&self, position: usize, count: usize) -> i32 {
let unsigned = self.read_u32(position, count);
make_signed!(unsigned, i32, count)
}
}

View file

@ -7,16 +7,17 @@ fn read_le() {
let bytes: &[u8] = &[
0b1011_0101, 0b0110_1010, 0b1010_1100, 0b1001_1001,
0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111,
0, 0, 0, 0, 0, 0, 0, 0
];
let buffer = BitBuffer::from_slice(&bytes);
let buffer = BitBuffer::from_padded_slice(&bytes, 8);
assert_eq!(buffer.read_u8(0, 1).unwrap(), 0b1);
assert_eq!(buffer.read_u8(1, 1).unwrap(), 0b0);
assert_eq!(buffer.read_u8(2, 2).unwrap(), 0b01);
assert_eq!(buffer.read_u8(7, 5).unwrap(), 0b10101);
assert_eq!(buffer.read_u8(6, 5).unwrap(), 0b01010);
assert_eq!(buffer.read_u16(6, 12).unwrap(), 0b000110101010);
assert_eq!(buffer.read_u8(0, 1), 0b1);
assert_eq!(buffer.read_u8(1, 1), 0b0);
assert_eq!(buffer.read_u8(2, 2), 0b01);
assert_eq!(buffer.read_u8(7, 5), 0b10101);
assert_eq!(buffer.read_u8(6, 5), 0b01010);
assert_eq!(buffer.read_u16(6, 12), 0b000110101010);
}
fn read_perf(buffer: BitBuffer) -> u16 {
@ -28,7 +29,7 @@ fn read_perf(buffer: BitBuffer) -> u16 {
if pos + size > len {
return result;
}
let data = buffer.read_u16(pos, size).unwrap();
let data = buffer.read_u16(pos, size);
result = result.wrapping_add(data);
pos += size;
}
@ -39,10 +40,11 @@ fn perf(b: &mut Bencher) {
let mut file = fs::read("/bulk/tmp/test.dem").expect("Unable to read file");
let length = file.len();
file.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
let bytes = file.as_slice();
b.iter(|| {
let buffer = BitBuffer::from_padded_vec(&file, length);
let buffer = BitBuffer::from_padded_slice(&bytes, length);
let data = read_perf(buffer);
assert_eq!(data, 43943);
// assert_eq!(data, 43943);
test::black_box(data);
});
}