mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-04 00:54:07 +02:00
usize reading
This commit is contained in:
parent
741f987833
commit
f5aff2cd80
2 changed files with 50 additions and 80 deletions
108
src/lib.rs
108
src/lib.rs
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
22
src/tests.rs
22
src/tests.rs
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue