1
0
Fork 0
mirror of https://codeberg.org/icewind/bitbuffer.git synced 2026-06-03 16:44:06 +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 type Result<T> = std::result::Result<T, ReadError>;
pub struct BitBuffer { pub struct BitBuffer<'a> {
bytes: Vec<u8>, bytes: &'a [u8],
bit_len: usize, bit_len: usize,
byte_len: usize, byte_len: usize,
} }
@ -46,37 +46,6 @@ macro_rules! array_ref {
const USIZE_SIZE: usize = std::mem::size_of::<usize>(); 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 { macro_rules! make_signed {
($unsigned:expr, $type:ty, $count:expr) => { ($unsigned:expr, $type:ty, $count:expr) => {
{ {
@ -87,32 +56,15 @@ macro_rules! make_signed {
} }
} }
impl BitBuffer { impl<'a> BitBuffer<'a> {
pub fn from_slice(data: &[u8]) -> BitBuffer { pub fn from_padded_slice(bytes: &'a [u8], byte_len: usize) -> BitBuffer<'a> {
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 {
BitBuffer { BitBuffer {
bytes: bytes.to_vec(), bytes,
bit_len: byte_len * 8,
byte_len, byte_len,
bit_len: byte_len * 8,
} }
} }
fn bytes(&self) -> &[u8] {
self.bytes.as_slice()
}
pub fn bit_len(&self) -> usize { pub fn bit_len(&self) -> usize {
self.bit_len self.bit_len
} }
@ -121,31 +73,47 @@ impl BitBuffer {
self.byte_len self.byte_len
} }
pub fn read_u8(&self, position: usize, count: usize) -> Result<u8> { pub fn read_usize(&self, position: usize, count: usize) -> usize {
self.bytes. let byte_index = position / 8;
bitreader_unsigned_le!(self, u8, position, count) 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> { pub fn read_u8(&self, position: usize, count: usize) -> u8 {
bitreader_unsigned_le!(self, u16, position, count) self.read_usize(position, count) as u8
} }
pub fn read_u32(&self, position: usize, count: usize) -> Result<u32> { pub fn read_u16(&self, position: usize, count: usize) -> u16 {
bitreader_unsigned_le!(self, u32, position, count) self.read_usize(position, count) as u16
} }
pub fn read_i8(&self, position: usize, count: usize) -> Result<i8> { pub fn read_u32(&self, position: usize, count: usize) -> u32 {
let unsigned = self.read_u8(position, count)?; if size_of::<usize>() > size_of::<u32>() {
Ok(make_signed!(unsigned, i8, count)) 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> { pub fn read_i16(&self, position: usize, count: usize) -> i16 {
let unsigned = self.read_u16(position, count)?; let unsigned = self.read_u16(position, count);
Ok(make_signed!(unsigned, i16, count)) make_signed!(unsigned, i16, count)
} }
pub fn read_i32(&self, position: usize, count: usize) -> Result<i32> { pub fn read_i32(&self, position: usize, count: usize) -> i32 {
let unsigned = self.read_u32(position, count)?; let unsigned = self.read_u32(position, count);
Ok(make_signed!(unsigned, i32, count)) make_signed!(unsigned, i32, count)
} }
} }

View file

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