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

@ -13,7 +13,6 @@ travis-ci = { repository = "icewind1991/bitstream_reader" }
[dependencies] [dependencies]
num-traits = "0.2" num-traits = "0.2"
bitstream_reader_derive = { version = "0.4", path = "bitstream_reader_derive" } bitstream_reader_derive = { version = "0.4", path = "bitstream_reader_derive" }
bitstream_reader_skip = { version = "0.4", path = "bitstream_reader_skip", optional = true }
packed_simd = { version = "0.3", features = ["into_bits"], optional = true } packed_simd = { version = "0.3", features = ["into_bits"], optional = true }
[dev-dependencies] [dev-dependencies]
@ -22,6 +21,5 @@ maplit = "1.0.1"
[features] [features]
unchecked_utf8 = [] unchecked_utf8 = []
simd = ["packed_simd"] simd = ["packed_simd"]
skip = ["bitstream_reader_skip"]
[workspace] [workspace]

View file

@ -114,7 +114,13 @@ fn verify_buffer(buffer: &BitBuffer<BigEndian>, inputs: &Vec<&str>) {
#[bench] #[bench]
fn perf_string_be(b: &mut Bencher) { fn perf_string_be(b: &mut Bencher) {
let inputs = vec!["foo", "bar", "something a little bit longer for extra testing", "a", ""]; let inputs = vec![
"foo",
"bar",
"something a little bit longer for extra testing",
"a",
"",
];
let data = build_string_data(10 * 1024 * 1024, &inputs); let data = build_string_data(10 * 1024 * 1024, &inputs);
let buffer = BitBuffer::new(data, BigEndian); let buffer = BitBuffer::new(data, BigEndian);
@ -137,7 +143,13 @@ fn perf_string_be(b: &mut Bencher) {
#[bench] #[bench]
fn perf_string_le(b: &mut Bencher) { fn perf_string_le(b: &mut Bencher) {
let inputs = vec!["foo", "bar", "something a little bit longer for extra testing", "a", ""]; let inputs = vec![
"foo",
"bar",
"something a little bit longer for extra testing",
"a",
"",
];
let data = build_string_data(10 * 1024 * 1024, &inputs); let data = build_string_data(10 * 1024 * 1024, &inputs);
let buffer = BitBuffer::new(data, LittleEndian); let buffer = BitBuffer::new(data, LittleEndian);

View file

@ -8,10 +8,10 @@ use std::rc::Rc;
use num_traits::{Float, PrimInt}; use num_traits::{Float, PrimInt};
use crate::{ReadError, Result};
use crate::endianness::Endianness; use crate::endianness::Endianness;
use crate::is_signed::IsSigned; use crate::is_signed::IsSigned;
use crate::unchecked_primitive::{UncheckedPrimitiveFloat, UncheckedPrimitiveInt}; use crate::unchecked_primitive::{UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
use crate::{ReadError, Result};
const USIZE_SIZE: usize = size_of::<usize>(); const USIZE_SIZE: usize = size_of::<usize>();
@ -35,7 +35,7 @@ const USIZE_SIZE: usize = size_of::<usize>();
/// # } /// # }
/// ``` /// ```
pub struct BitBuffer<E> pub struct BitBuffer<E>
where where
E: Endianness, E: Endianness,
{ {
bytes: Rc<Vec<u8>>, bytes: Rc<Vec<u8>>,
@ -46,7 +46,7 @@ pub struct BitBuffer<E>
} }
impl<E> BitBuffer<E> impl<E> BitBuffer<E>
where where
E: Endianness, E: Endianness,
{ {
/// Create a new BitBuffer from a byte vector /// Create a new BitBuffer from a byte vector
@ -75,7 +75,7 @@ impl<E> BitBuffer<E>
} }
impl<E> BitBuffer<E> impl<E> BitBuffer<E>
where where
E: Endianness, E: Endianness,
{ {
/// The available number of bits in the buffer /// The available number of bits in the buffer
@ -147,9 +147,7 @@ impl<E> BitBuffer<E>
}); });
} }
let byte = unsafe { let byte = unsafe { self.bytes.get_unchecked(byte_index) };
self.bytes.get_unchecked(byte_index)
};
let shifted = byte >> bit_offset; let shifted = byte >> bit_offset;
Ok(shifted & 1u8 == 1) Ok(shifted & 1u8 == 1)
} }
@ -400,9 +398,7 @@ impl<E> BitBuffer<E>
Some(byte_len) => { Some(byte_len) => {
let bytes = self.read_bytes(position, byte_len)?; let bytes = self.read_bytes(position, byte_len)?;
let raw_string = if cfg!(feature = "unchecked_utf8") { let raw_string = if cfg!(feature = "unchecked_utf8") {
unsafe { unsafe { String::from_utf8_unchecked(bytes) }
String::from_utf8_unchecked(bytes)
}
} else { } else {
String::from_utf8(bytes)? String::from_utf8(bytes)?
}; };
@ -411,9 +407,7 @@ impl<E> BitBuffer<E>
None => { None => {
let bytes = self.read_string_bytes(position); let bytes = self.read_string_bytes(position);
if cfg!(feature = "unchecked_utf8") { if cfg!(feature = "unchecked_utf8") {
unsafe { unsafe { Ok(String::from_utf8_unchecked(bytes)) }
Ok(String::from_utf8_unchecked(bytes))
}
} else { } else {
String::from_utf8(bytes).map_err(ReadError::from) String::from_utf8(bytes).map_err(ReadError::from)
} }
@ -454,8 +448,8 @@ impl<E> BitBuffer<E>
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
fn read_string_bytes(&self, position: usize) -> Vec<u8> { fn read_string_bytes(&self, position: usize) -> Vec<u8> {
use packed_simd::u8x16;
use packed_simd::u128x1; use packed_simd::u128x1;
use packed_simd::u8x16;
use packed_simd::IntoBits; use packed_simd::IntoBits;
let bit_index = position & 7; let bit_index = position & 7;
@ -465,7 +459,8 @@ impl<E> BitBuffer<E>
let bit_index_simd = u128x1::new(bit_index as u128); let bit_index_simd = u128x1::new(bit_index as u128);
loop { 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 shifted = raw_value.rotate_right(bit_index_simd);
let input_bytes: u8x16 = shifted.into_bits(); let input_bytes: u8x16 = shifted.into_bits();
let has_zero = ZEROS.eq(input_bytes).any(); let has_zero = ZEROS.eq(input_bytes).any();

View file

@ -62,7 +62,9 @@ pub use std::string::FromUtf8Error;
pub use bitstream_reader_derive::{BitRead, BitReadSized, BitSize, BitSizeSized}; pub use bitstream_reader_derive::{BitRead, BitReadSized, BitSize, BitSizeSized};
pub use buffer::BitBuffer; pub use buffer::BitBuffer;
pub use endianness::*; 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; pub use stream::BitStream;
mod buffer; mod buffer;

View file

@ -1,8 +1,10 @@
use crate::endianness::{BigEndian, LittleEndian};
use crate::{BitStream, Endianness, Result}; use crate::{BitStream, Endianness, Result};
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; 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 /// 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 { macro_rules! impl_read_int {
($type:ty, $len:expr) => { ($type:ty) => {
impl<E: Endianness> BitRead<E> for $type { impl<E: Endianness> BitRead<E> for $type {
#[inline] #[inline]
fn read(stream: &mut BitStream<E>) -> Result<$type> { 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 { impl BitSize for $type {
#[inline] #[inline]
fn bit_size() -> usize { fn bit_size() -> usize {
$len size_of::<$type>() * 8
} }
} }
}; };
} }
impl_read_int!(u8, 8); macro_rules! impl_read_int_nonzero {
impl_read_int!(u16, 16); ($type:ty) => {
impl_read_int!(u32, 32); impl BitRead<LittleEndian> for Option<$type> {
impl_read_int!(u64, 64); #[inline]
impl_read_int!(u128, 128); fn read(stream: &mut BitStream<LittleEndian>) -> Result<Self> {
impl_read_int!(i8, 8); Ok(<$type>::new(stream.read()?))
impl_read_int!(i16, 16); }
impl_read_int!(i32, 32); }
impl_read_int!(i64, 64);
impl_read_int!(i128, 128); 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 { impl<E: Endianness> BitRead<E> for f32 {
#[inline] #[inline]

View file

@ -1,4 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::num::NonZeroU16;
use maplit::hashmap; use maplit::hashmap;
@ -255,28 +256,11 @@ fn test_read_str_be() {
#[test] #[test]
fn test_read_str_le() { fn test_read_str_le() {
let bytes = vec![ let bytes = vec![
'h' as u8, 'h' as u8, 'e' as u8, 'l' as u8, 'l' as u8, 'o' as u8, ' ' as u8, 'w' as u8, 'o' as u8,
'e' as u8, 'r' as u8, 'l' as u8, 'd' as u8, 0, 'f' as u8, 'o' as u8, 'o' as u8, 0, 0, 0, 0, 0,
'l' as u8,
'l' as u8,
'o' as u8,
' ' as u8,
'w' as u8,
'o' as u8,
'r' as u8,
'l' as u8,
'd' as u8,
0,
'f' as u8,
'o' as u8,
'o' as u8,
0, 0, 0, 0, 0,
]; ];
let buffer = BitBuffer::new(bytes, LittleEndian); let buffer = BitBuffer::new(bytes, LittleEndian);
assert_eq!( assert_eq!(buffer.read_string(0, Some(3)).unwrap(), "hel".to_owned());
buffer.read_string(0, Some(3)).unwrap(),
"hel".to_owned()
);
assert_eq!( assert_eq!(
buffer.read_string(0, Some(11)).unwrap(), buffer.read_string(0, Some(11)).unwrap(),
"hello world".to_owned() "hello world".to_owned()
@ -390,3 +374,12 @@ fn test_read_struct() {
stream.read().unwrap() stream.read().unwrap()
); );
} }
#[test]
fn test_read_nonzero() {
let bytes = vec![12, 0, 0, 0];
let buffer = BitBuffer::new(bytes, LittleEndian);
let mut stream = BitStream::from(buffer);
assert_eq!(NonZeroU16::new(12), stream.read().unwrap());
assert_eq!(None, stream.read::<Option<NonZeroU16>>().unwrap());
}