1
0
Fork 0
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:
Robin Appelman 2019-02-20 20:29:23 +01:00
commit 6d999f7471
2 changed files with 42 additions and 66 deletions

View file

@ -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>

View file

@ -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);