mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-04 00:54:07 +02:00
remove need for padding from input slice
this makes reading slower but the api a lot nicer
This commit is contained in:
parent
c33a9a711b
commit
6d999f7471
2 changed files with 42 additions and 66 deletions
63
src/lib.rs
63
src/lib.rs
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
extern crate test;
|
||||
|
||||
pub use endianness::{BigEndian, LittleEndian};
|
||||
use endianness::Endianness;
|
||||
use is_signed::IsSigned;
|
||||
use num_traits::{Float, PrimInt};
|
||||
|
|
@ -13,8 +14,6 @@ use std::marker::PhantomData;
|
|||
use std::mem::size_of;
|
||||
use std::ops::BitOrAssign;
|
||||
|
||||
pub use endianness::{LittleEndian, BigEndian};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod is_signed;
|
||||
|
|
@ -56,33 +55,21 @@ pub struct BitBuffer<'a, E>
|
|||
}
|
||||
|
||||
impl<'a, E> BitBuffer<'a, E> where E: Endianness {
|
||||
/// Create a new BitBuffer from a byte slice with included padding
|
||||
///
|
||||
/// The padding is required because the optimized method for reading bits can overshoot the last requested bit
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// When not enough padding is provided (3 bytes on 32bit systems, 7 bytes on 64 bit systems)
|
||||
/// this method will panic
|
||||
/// Create a new BitBuffer from a byte slice
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bitbuffer::{BitBuffer, LittleEndian};
|
||||
///
|
||||
/// let bytes:&[u8] =&[
|
||||
/// 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
|
||||
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
||||
/// ];
|
||||
/// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
|
||||
/// let buffer: BitBuffer<LittleEndian> = BitBuffer::new(bytes);
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
pub fn from_padded_slice(bytes: &'a [u8], byte_len: usize) -> Self {
|
||||
if byte_len > bytes.len() - (USIZE_SIZE - 1) {
|
||||
panic!("Not enough padding on slice, at least {} bytes of padding are required", USIZE_SIZE - 1);
|
||||
}
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
let byte_len = bytes.len();
|
||||
BitBuffer {
|
||||
bytes,
|
||||
byte_len,
|
||||
|
|
@ -92,15 +79,11 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
|
|||
}
|
||||
|
||||
/// The available number of bits in the buffer
|
||||
///
|
||||
/// Note that this does not included any padding from the source slice
|
||||
pub fn bit_len(&self) -> usize {
|
||||
self.bit_len
|
||||
}
|
||||
|
||||
/// The available number of bytes in the buffer
|
||||
///
|
||||
/// Note that this does not included any padding from the source slice
|
||||
pub fn byte_len(&self) -> usize {
|
||||
self.byte_len
|
||||
}
|
||||
|
|
@ -112,8 +95,8 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
|
|||
bits_left: self.bit_len - position,
|
||||
});
|
||||
}
|
||||
let byte_index = position / 8;
|
||||
let bit_offset = position & 7;
|
||||
let byte_index = min(position / 8, self.byte_len - USIZE_SIZE);
|
||||
let bit_offset = position - byte_index * 8;
|
||||
let slice = &self.bytes[byte_index..byte_index + USIZE_SIZE];
|
||||
let bytes: [u8; USIZE_SIZE] = unsafe {
|
||||
*(slice.as_ptr() as *const [u8; USIZE_SIZE])
|
||||
|
|
@ -143,12 +126,11 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
|
|||
/// ```
|
||||
/// use bitbuffer::{BitBuffer, LittleEndian};
|
||||
///
|
||||
/// let bytes:&[u8] =&[
|
||||
/// 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
|
||||
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
||||
/// ];
|
||||
/// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
|
||||
/// let buffer: BitBuffer<LittleEndian> = BitBuffer::new(bytes);
|
||||
/// let result = buffer.read_bool(6);
|
||||
/// ```
|
||||
pub fn read_bool(&self, position: usize) -> Result<bool> {
|
||||
|
|
@ -180,12 +162,11 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
|
|||
/// ```
|
||||
/// use bitbuffer::{BitBuffer, LittleEndian};
|
||||
///
|
||||
/// let bytes:&[u8] =&[
|
||||
/// 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
|
||||
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
||||
/// ];
|
||||
/// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
|
||||
/// let buffer: BitBuffer<LittleEndian> = BitBuffer::new(bytes);
|
||||
/// let result = buffer.read::<u16>(10, 9);
|
||||
/// ```
|
||||
pub fn read<T>(&self, position: usize, count: usize) -> Result<T>
|
||||
|
|
@ -256,12 +237,11 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
|
|||
/// ```
|
||||
/// use bitbuffer::{BitBuffer, LittleEndian};
|
||||
///
|
||||
/// let bytes:&[u8] =&[
|
||||
/// 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
|
||||
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
||||
/// ];
|
||||
/// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
|
||||
/// let buffer: BitBuffer<LittleEndian> = BitBuffer::new(bytes);
|
||||
/// let bytes = buffer.read_bytes(5, 3);
|
||||
/// ```
|
||||
pub fn read_bytes(&self, position: usize, byte_count: usize) -> Result<Vec<u8>> {
|
||||
|
|
@ -293,12 +273,11 @@ impl<'a, E> BitBuffer<'a, E> where E: Endianness {
|
|||
/// ```
|
||||
/// use bitbuffer::{BitBuffer, LittleEndian};
|
||||
///
|
||||
/// let bytes:&[u8] =&[
|
||||
/// 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
|
||||
/// 0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
||||
/// ];
|
||||
/// let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(bytes, 8);
|
||||
/// let buffer: BitBuffer<LittleEndian> = BitBuffer::new(bytes);
|
||||
/// let result = buffer.read_float::<f32>(10);
|
||||
/// ```
|
||||
pub fn read_float<T>(&self, position: usize) -> Result<T>
|
||||
|
|
|
|||
45
src/tests.rs
45
src/tests.rs
|
|
@ -5,13 +5,12 @@ use test::Bencher;
|
|||
const BYTES: &'static [u8] = &[
|
||||
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, 0
|
||||
0b1001_1001, 0b1001_1001, 0b1001_1001, 0b1110_0111
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn read_u8_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<u8>(0, 1).unwrap(), 0b1);
|
||||
assert_eq!(buffer.read::<u8>(1, 1).unwrap(), 0b0);
|
||||
|
|
@ -23,7 +22,7 @@ fn read_u8_le() {
|
|||
|
||||
#[test]
|
||||
fn read_u8_be() {
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<u8>(0, 1).unwrap(), 0b1);
|
||||
assert_eq!(buffer.read::<u8>(1, 1).unwrap(), 0b0);
|
||||
|
|
@ -35,35 +34,35 @@ fn read_u8_be() {
|
|||
|
||||
#[test]
|
||||
fn read_u16_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<u16>(6, 12).unwrap(), 0b00_0110_1010_10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_u16_be() {
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<u16>(6, 12).unwrap(), 0b01_0110_1010_10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_u32_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<u32>(6, 24).unwrap(), 0b01_1001_1010_1100_0110_1010_10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_u32_be() {
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<u32>(6, 24).unwrap(), 0b01_0110_1010_1010_1100_1001_10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_u64_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<u64>(6, 34).unwrap(), 0b1001_1001_1001_1001_1010_1100_0110_1010_10);
|
||||
assert_eq!(buffer.read::<u64>(6, 60).unwrap(), 0b01_1110_0111_1001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_10);
|
||||
|
|
@ -72,7 +71,7 @@ fn read_u64_le() {
|
|||
|
||||
#[test]
|
||||
fn read_u64_be() {
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<u64>(6, 34).unwrap(), 0b01_0110_1010_1010_1100_1001_1001_1001_1001);
|
||||
assert_eq!(buffer.read::<u64>(6, 60).unwrap(), 0b01_0110_1010_1010_1100_1001_1001_1001_1001_1001_1001_1001_1001_1110_0111_10);
|
||||
|
|
@ -81,7 +80,7 @@ fn read_u64_be() {
|
|||
|
||||
#[test]
|
||||
fn read_i8_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<i8>(0, 3).unwrap(), -0b01);
|
||||
assert_eq!(buffer.read::<i8>(0, 8).unwrap(), -0b011_0101);
|
||||
|
|
@ -89,7 +88,7 @@ fn read_i8_le() {
|
|||
|
||||
#[test]
|
||||
fn read_i8_be() {
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<i8>(1, 2).unwrap(), 0b1);
|
||||
assert_eq!(buffer.read::<i8>(0, 3).unwrap(), -0b01);
|
||||
|
|
@ -98,7 +97,7 @@ fn read_i8_be() {
|
|||
|
||||
#[test]
|
||||
fn read_i16_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<i16>(6, 12).unwrap(), 0b0_0110_1010_10);
|
||||
assert_eq!(buffer.read::<i16>(6, 13).unwrap(), -0b00_0110_1010_10);
|
||||
|
|
@ -106,7 +105,7 @@ fn read_i16_le() {
|
|||
|
||||
#[test]
|
||||
fn read_i16_be() {
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<i16>(6, 12).unwrap(), 0b1_0110_1010_10);
|
||||
assert_eq!(buffer.read::<i16>(7, 12).unwrap(), -0b0110_1010_101);
|
||||
|
|
@ -114,7 +113,7 @@ fn read_i16_be() {
|
|||
|
||||
#[test]
|
||||
fn read_i32_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<i32>(6, 24).unwrap(), 0b1_1001_1010_1100_0110_1010_10);
|
||||
assert_eq!(buffer.read::<i32>(6, 26).unwrap(), -0b001_1001_1010_1100_0110_1010_10);
|
||||
|
|
@ -122,14 +121,14 @@ fn read_i32_le() {
|
|||
|
||||
#[test]
|
||||
fn read_i32_be() {
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<i32>(7, 24).unwrap(), -0b0110_1010_1010_1100_1001_100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_i64_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<i64>(6, 34).unwrap(), -0b001_1001_1001_1001_1010_1100_0110_1010_10);
|
||||
assert_eq!(buffer.read::<i64>(6, 59).unwrap(), -0b1110_01111001_1001_1001_1001_1001_1001_1001_1001_1010_1100_0110_1010_10);
|
||||
|
|
@ -138,7 +137,7 @@ fn read_i64_le() {
|
|||
|
||||
#[test]
|
||||
fn read_i64_be() {
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<BigEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read::<i64>(7, 34).unwrap(), -0b0110_1010_1010_1100_1001_1001_1001_1001_1);
|
||||
assert_eq!(buffer.read::<i64>(7, 60).unwrap(), -0b0110_1010_1010_1100_1001_1001_1001_1001_1001_1001_1001_1001_1110_0111_100);
|
||||
|
|
@ -147,14 +146,14 @@ fn read_i64_be() {
|
|||
|
||||
#[test]
|
||||
fn read_f32_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read_float::<f64>(6).unwrap(), 135447455835963910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_f64_le() {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(BYTES, 12);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(BYTES);
|
||||
|
||||
assert_eq!(buffer.read_float::<f64>(6).unwrap(), 135447455835963910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0);
|
||||
}
|
||||
|
|
@ -176,12 +175,10 @@ fn read_perf<E: Endianness>(buffer: BitBuffer<E>) -> u16 {
|
|||
|
||||
#[bench]
|
||||
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 file = fs::read("/bulk/tmp/test.dem").expect("Unable to read file");
|
||||
let bytes = file.as_slice();
|
||||
b.iter(|| {
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::from_padded_slice(&bytes, length);
|
||||
let buffer:BitBuffer<LittleEndian> = BitBuffer::new(&bytes);
|
||||
let data = read_perf(buffer);
|
||||
assert_eq!(data, 43943);
|
||||
test::black_box(data);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue