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

remove padded optimization for the sake of api cleanness

This commit is contained in:
Robin Appelman 2019-02-27 16:21:04 +01:00
commit eee2cf5c43
3 changed files with 36 additions and 102 deletions

View file

@ -48,37 +48,21 @@ impl IsPadded for Padded {
/// ];
/// let buffer = BitBuffer::new(bytes.to_vec(), LittleEndian);
/// ```
///
/// You can also provide a slice padded with at least `size_of::<usize>() - 1` bytes,
/// when the input slice is padded, the BitBuffer can use some optimizations which result in a ~1.5 time performance increase
///
/// ```
/// use bitstream_reader::{BitBuffer, LittleEndian};
///
/// 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_padded(bytes.to_vec(), 8, LittleEndian);
/// ```
pub struct BitBuffer<E, S>
pub struct BitBuffer<E>
where
E: Endianness,
S: IsPadded,
{
bytes: Vec<u8>,
bit_len: usize,
byte_len: usize,
endianness: PhantomData<E>,
is_padded: PhantomData<S>,
}
impl<E> BitBuffer<E, NonPadded>
impl<E> BitBuffer<E>
where
E: Endianness,
{
/// Create a new BitBuffer from a byte slice
/// Create a new BitBuffer from a byte vector
///
/// # Examples
///
@ -98,57 +82,13 @@ where
byte_len,
bit_len: byte_len * 8,
endianness: PhantomData,
is_padded: PhantomData,
}
}
}
impl<E> BitBuffer<E, Padded>
impl<E> BitBuffer<E>
where
E: Endianness,
{
/// Create a new BitBuffer from a byte slice with included padding
///
/// by including at least `size_of::<usize>() - 1` bytes of padding reading can be further optimized
///
/// # Panics
///
/// Panics if not enough bytes of padding are included
///
/// # Examples
///
/// ```
/// use bitstream_reader::{BitBuffer, LittleEndian};
///
/// 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_padded(bytes.to_vec(), 8, LittleEndian);
/// ```
pub fn from_padded(bytes: Vec<u8>, byte_len: usize, _endianness: E) -> Self {
if bytes.len() < byte_len + USIZE_SIZE - 1 {
panic!(
"not enough padding bytes, {} required, {} provided",
USIZE_SIZE - 1,
byte_len - bytes.len()
)
}
BitBuffer {
bytes,
byte_len,
bit_len: byte_len * 8,
endianness: PhantomData,
is_padded: PhantomData,
}
}
}
impl<E, S> BitBuffer<E, S>
where
E: Endianness,
S: IsPadded,
{
/// The available number of bits in the buffer
pub fn bit_len(&self) -> usize {
@ -167,11 +107,7 @@ where
bits_left: self.bit_len - position,
});
}
let byte_index = if S::is_padded() {
position / 8
} else {
min(position / 8, self.byte_len - USIZE_SIZE)
};
let byte_index = min(position / 8, self.byte_len - USIZE_SIZE);
let bit_offset = position - byte_index * 8;
let raw_container: &usize = unsafe {
// this is safe here because it's already verified that there is enough data in the slice

View file

@ -1,16 +1,16 @@
use crate::{BitStream, Endianness, IsPadded, Result};
use crate::{BitStream, Endianness, Result};
/// Trait for types that can be read from a stream without requiring the size to be configured
pub trait Read<E: Endianness, P: IsPadded>: Sized {
pub trait Read<E: Endianness>: Sized {
/// Read the type from stream
fn read(stream: &mut BitStream<E, P>) -> Result<Self>;
fn read(stream: &mut BitStream<E>) -> Result<Self>;
}
macro_rules! impl_read_int {
($type:ty, $len:expr) => {
impl<E: Endianness, P: IsPadded> Read<E, P> for $type {
impl<E: Endianness> Read<E> for $type {
#[inline(always)]
fn read(stream: &mut BitStream<E, P>) -> Result<$type> {
fn read(stream: &mut BitStream<E>) -> Result<$type> {
stream.read_int::<$type>($len)
}
}
@ -28,45 +28,45 @@ impl_read_int!(i32, 32);
impl_read_int!(i64, 64);
impl_read_int!(i128, 128);
impl<E: Endianness, P: IsPadded> Read<E, P> for f32 {
impl<E: Endianness> Read<E> for f32 {
#[inline(always)]
fn read(stream: &mut BitStream<E, P>) -> Result<f32> {
fn read(stream: &mut BitStream<E>) -> Result<f32> {
stream.read_float::<f32>()
}
}
impl<E: Endianness, P: IsPadded> Read<E, P> for f64 {
impl<E: Endianness> Read<E> for f64 {
#[inline(always)]
fn read(stream: &mut BitStream<E, P>) -> Result<f64> {
fn read(stream: &mut BitStream<E>) -> Result<f64> {
stream.read_float::<f64>()
}
}
impl<E: Endianness, P: IsPadded> Read<E, P> for bool {
impl<E: Endianness> Read<E> for bool {
#[inline(always)]
fn read(stream: &mut BitStream<E, P>) -> Result<bool> {
fn read(stream: &mut BitStream<E>) -> Result<bool> {
stream.read_bool()
}
}
impl<E: Endianness, P: IsPadded> Read<E, P> for String {
impl<E: Endianness> Read<E> for String {
#[inline(always)]
fn read(stream: &mut BitStream<E, P>) -> Result<String> {
fn read(stream: &mut BitStream<E>) -> Result<String> {
stream.read_string(None)
}
}
/// Trait for types that can be read from a stream wit requiring the size to be configured
pub trait ReadSized<E: Endianness, P: IsPadded>: Sized {
pub trait ReadSized<E: Endianness>: Sized {
/// Read the type from stream
fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<Self>;
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self>;
}
macro_rules! impl_read_int_sized {
($type:ty) => {
impl<E: Endianness, P: IsPadded> ReadSized<E, P> for $type {
impl<E: Endianness> ReadSized<E> for $type {
#[inline(always)]
fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<$type> {
fn read(stream: &mut BitStream<E>, size: usize) -> Result<$type> {
stream.read_int::<$type>(size)
}
}
@ -84,16 +84,16 @@ impl_read_int_sized!(i32);
impl_read_int_sized!(i64);
impl_read_int_sized!(i128);
impl<E: Endianness, P: IsPadded> ReadSized<E, P> for String {
impl<E: Endianness> ReadSized<E> for String {
#[inline(always)]
fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<String> {
fn read(stream: &mut BitStream<E>, size: usize) -> Result<String> {
stream.read_string(Some(size))
}
}
/// Read a boolean, if true, read the value, else return None
impl<E: Endianness, P: IsPadded, T: Read<E, P>> Read<E, P> for Option<T> {
fn read(stream: &mut BitStream<E, P>) -> Result<Self> {
impl<E: Endianness, T: Read<E>> Read<E> for Option<T> {
fn read(stream: &mut BitStream<E>) -> Result<Self> {
if stream.read()? {
Ok(Some(stream.read()?))
} else {
@ -102,8 +102,8 @@ impl<E: Endianness, P: IsPadded, T: Read<E, P>> Read<E, P> for Option<T> {
}
}
impl<E: Endianness, P: IsPadded, T: Read<E, P>> ReadSized<E, P> for Vec<T> {
fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<Self> {
impl<E: Endianness, T: Read<E>> ReadSized<E> for Vec<T> {
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
let mut vec = Vec::with_capacity(size);
for _ in 0..size {
vec.push(stream.read()?)
@ -113,9 +113,9 @@ impl<E: Endianness, P: IsPadded, T: Read<E, P>> ReadSized<E, P> for Vec<T> {
}
// Once we have something like https://github.com/rust-lang/rfcs/issues/1053 we can do this optimization
//impl<E: Endianness, P: IsPadded> ReadSized<E, P> for Vec<u8> {
//impl<E: Endianness> ReadSized<E> for Vec<u8> {
// #[inline(always)]
// fn read(stream: &mut BitStream<E, P>, size: usize) -> Result<Self> {
// fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
// stream.read_bytes(size)
// }
//}

View file

@ -24,21 +24,19 @@ use crate::{Read, ReadError, ReadSized, Result};
/// let buffer = BitBuffer::new(bytes.to_vec(), LittleEndian);
/// let mut stream = BitStream::new(buffer, None, None);
/// ```
pub struct BitStream<E, S>
pub struct BitStream<E>
where
E: Endianness,
S: IsPadded,
{
buffer: Rc<BitBuffer<E, S>>,
buffer: Rc<BitBuffer<E>>,
start_pos: usize,
pos: usize,
bit_len: usize,
}
impl<E, S> BitStream<E, S>
impl<E> BitStream<E>
where
E: Endianness,
S: IsPadded,
{
/// Create a new stream for a buffer
///
@ -59,7 +57,7 @@ where
/// let buffer = BitBuffer::new(bytes.to_vec(), LittleEndian);
/// let mut stream = BitStream::new(buffer, None, None);
/// ```
pub fn new(buffer: BitBuffer<E, S>, start_pos: Option<usize>, bit_len: Option<usize>) -> Self {
pub fn new(buffer: BitBuffer<E>, start_pos: Option<usize>, bit_len: Option<usize>) -> Self {
let buffer_len = buffer.bit_len();
let start = start_pos.unwrap_or_default();
if start > buffer_len {
@ -413,12 +411,12 @@ where
}
/// Read a value based on the provided type
pub fn read<T: Read<E, S>>(&mut self) -> Result<T> {
pub fn read<T: Read<E>>(&mut self) -> Result<T> {
T::read(self)
}
/// Read a value based on the provided type and size
pub fn read_sized<T: ReadSized<E, S>>(&mut self, size: usize) -> Result<T> {
pub fn read_sized<T: ReadSized<E>>(&mut self, size: usize) -> Result<T> {
T::read(self, size)
}
}