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

read for NoZero ints

This commit is contained in:
Robin Appelman 2019-04-09 19:59:38 +02:00
commit 71823f22ec
6 changed files with 100 additions and 67 deletions

View file

@ -8,10 +8,10 @@ use std::rc::Rc;
use num_traits::{Float, PrimInt};
use crate::{ReadError, Result};
use crate::endianness::Endianness;
use crate::is_signed::IsSigned;
use crate::unchecked_primitive::{UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
use crate::{ReadError, Result};
const USIZE_SIZE: usize = size_of::<usize>();
@ -35,8 +35,8 @@ const USIZE_SIZE: usize = size_of::<usize>();
/// # }
/// ```
pub struct BitBuffer<E>
where
E: Endianness,
where
E: Endianness,
{
bytes: Rc<Vec<u8>>,
bit_len: usize,
@ -46,8 +46,8 @@ pub struct BitBuffer<E>
}
impl<E> BitBuffer<E>
where
E: Endianness,
where
E: Endianness,
{
/// Create a new BitBuffer from a byte vector
///
@ -75,8 +75,8 @@ impl<E> BitBuffer<E>
}
impl<E> BitBuffer<E>
where
E: Endianness,
where
E: Endianness,
{
/// The available number of bits in the buffer
pub fn bit_len(&self) -> usize {
@ -147,9 +147,7 @@ impl<E> BitBuffer<E>
});
}
let byte = unsafe {
self.bytes.get_unchecked(byte_index)
};
let byte = unsafe { self.bytes.get_unchecked(byte_index) };
let shifted = byte >> bit_offset;
Ok(shifted & 1u8 == 1)
}
@ -183,8 +181,8 @@ impl<E> BitBuffer<E>
/// [`ReadError::TooManyBits`]: enum.ReadError.html#variant.TooManyBits
#[inline]
pub fn read_int<T>(&self, position: usize, count: usize) -> Result<T>
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
let type_bit_size = size_of::<T>() * 8;
let usize_bit_size = size_of::<usize>() * 8;
@ -228,8 +226,8 @@ impl<E> BitBuffer<E>
#[inline]
fn read_fit_usize<T>(&self, position: usize, count: usize) -> T
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
let type_bit_size = size_of::<T>() * 8;
let raw = self.read_usize(position, count);
@ -242,8 +240,8 @@ impl<E> BitBuffer<E>
}
fn read_no_fit_usize<T>(&self, position: usize, count: usize) -> T
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
let mut left_to_read = count;
let mut acc = T::zero();
@ -269,8 +267,8 @@ impl<E> BitBuffer<E>
}
fn make_signed<T>(&self, value: T, count: usize) -> T
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
where
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
{
if T::is_signed() {
let sign_bit = value >> (count - 1) & T::one();
@ -400,9 +398,7 @@ impl<E> BitBuffer<E>
Some(byte_len) => {
let bytes = self.read_bytes(position, byte_len)?;
let raw_string = if cfg!(feature = "unchecked_utf8") {
unsafe {
String::from_utf8_unchecked(bytes)
}
unsafe { String::from_utf8_unchecked(bytes) }
} else {
String::from_utf8(bytes)?
};
@ -411,9 +407,7 @@ impl<E> BitBuffer<E>
None => {
let bytes = self.read_string_bytes(position);
if cfg!(feature = "unchecked_utf8") {
unsafe {
Ok(String::from_utf8_unchecked(bytes))
}
unsafe { Ok(String::from_utf8_unchecked(bytes)) }
} else {
String::from_utf8(bytes).map_err(ReadError::from)
}
@ -454,8 +448,8 @@ impl<E> BitBuffer<E>
#[cfg(feature = "simd")]
fn read_string_bytes(&self, position: usize) -> Vec<u8> {
use packed_simd::u8x16;
use packed_simd::u128x1;
use packed_simd::u8x16;
use packed_simd::IntoBits;
let bit_index = position & 7;
@ -465,7 +459,8 @@ impl<E> BitBuffer<E>
let bit_index_simd = u128x1::new(bit_index as u128);
loop {
let raw_value: u128x1 = u8x16::from_slice_unaligned(&self.bytes[byte_index..byte_index + 16]).into_bits();
let raw_value: u128x1 =
u8x16::from_slice_unaligned(&self.bytes[byte_index..byte_index + 16]).into_bits();
let shifted = raw_value.rotate_right(bit_index_simd);
let input_bytes: u8x16 = shifted.into_bits();
let has_zero = ZEROS.eq(input_bytes).any();
@ -513,8 +508,8 @@ impl<E> BitBuffer<E>
///
/// [`ReadError::NotEnoughData`]: enum.ReadError.html#variant.NotEnoughData
pub fn read_float<T>(&self, position: usize) -> Result<T>
where
T: Float + UncheckedPrimitiveFloat,
where
T: Float + UncheckedPrimitiveFloat,
{
let type_bit_size = size_of::<T>() * 8;
if position + type_bit_size > self.bit_len {

View file

@ -62,7 +62,9 @@ pub use std::string::FromUtf8Error;
pub use bitstream_reader_derive::{BitRead, BitReadSized, BitSize, BitSizeSized};
pub use buffer::BitBuffer;
pub use endianness::*;
pub use read::{BitRead, BitReadSized, BitSize, BitSizeSized, LazyBitRead, LazyBitReadSized, BitSkip};
pub use read::{
BitRead, BitReadSized, BitSize, BitSizeSized, BitSkip, LazyBitRead, LazyBitReadSized,
};
pub use stream::BitStream;
mod buffer;

View file

@ -1,8 +1,10 @@
use crate::endianness::{BigEndian, LittleEndian};
use crate::{BitStream, Endianness, Result};
use std::cell::RefCell;
use std::collections::HashMap;
use std::hash::Hash;
use std::marker::PhantomData;
use std::mem::size_of;
/// Trait for types that can be read from a stream without requiring the size to be configured
///
@ -112,33 +114,64 @@ impl<T: BitRead<E> + BitSize, E: Endianness> BitSkip<E> for T {
}
macro_rules! impl_read_int {
($type:ty, $len:expr) => {
($type:ty) => {
impl<E: Endianness> BitRead<E> for $type {
#[inline]
fn read(stream: &mut BitStream<E>) -> Result<$type> {
stream.read_int::<$type>($len)
stream.read_int::<$type>(size_of::<$type>() * 8)
}
}
impl BitSize for $type {
#[inline]
fn bit_size() -> usize {
$len
size_of::<$type>() * 8
}
}
};
}
impl_read_int!(u8, 8);
impl_read_int!(u16, 16);
impl_read_int!(u32, 32);
impl_read_int!(u64, 64);
impl_read_int!(u128, 128);
impl_read_int!(i8, 8);
impl_read_int!(i16, 16);
impl_read_int!(i32, 32);
impl_read_int!(i64, 64);
impl_read_int!(i128, 128);
macro_rules! impl_read_int_nonzero {
($type:ty) => {
impl BitRead<LittleEndian> for Option<$type> {
#[inline]
fn read(stream: &mut BitStream<LittleEndian>) -> Result<Self> {
Ok(<$type>::new(stream.read()?))
}
}
impl BitRead<BigEndian> for Option<$type> {
#[inline]
fn read(stream: &mut BitStream<BigEndian>) -> Result<Self> {
Ok(<$type>::new(stream.read()?))
}
}
impl BitSize for $type {
#[inline]
fn bit_size() -> usize {
size_of::<$type>() * 8
}
}
};
}
impl_read_int!(u8);
impl_read_int!(u16);
impl_read_int!(u32);
impl_read_int!(u64);
impl_read_int!(u128);
impl_read_int!(i8);
impl_read_int!(i16);
impl_read_int!(i32);
impl_read_int!(i64);
impl_read_int!(i128);
impl_read_int_nonzero!(std::num::NonZeroU8);
impl_read_int_nonzero!(std::num::NonZeroU16);
impl_read_int_nonzero!(std::num::NonZeroU32);
impl_read_int_nonzero!(std::num::NonZeroU64);
impl_read_int_nonzero!(std::num::NonZeroU128);
impl<E: Endianness> BitRead<E> for f32 {
#[inline]