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]
num-traits = "0.2"
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 }
[dev-dependencies]
@ -22,6 +21,5 @@ maplit = "1.0.1"
[features]
unchecked_utf8 = []
simd = ["packed_simd"]
skip = ["bitstream_reader_skip"]
[workspace]

View file

@ -114,7 +114,13 @@ fn verify_buffer(buffer: &BitBuffer<BigEndian>, inputs: &Vec<&str>) {
#[bench]
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 buffer = BitBuffer::new(data, BigEndian);
@ -137,7 +143,13 @@ fn perf_string_be(b: &mut Bencher) {
#[bench]
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 buffer = BitBuffer::new(data, LittleEndian);

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

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]

View file

@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::num::NonZeroU16;
use maplit::hashmap;
@ -255,28 +256,11 @@ fn test_read_str_be() {
#[test]
fn test_read_str_le() {
let bytes = vec![
'h' as u8,
'e' as u8,
'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,
'h' as u8, 'e' as u8, '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);
assert_eq!(
buffer.read_string(0, Some(3)).unwrap(),
"hel".to_owned()
);
assert_eq!(buffer.read_string(0, Some(3)).unwrap(), "hel".to_owned());
assert_eq!(
buffer.read_string(0, Some(11)).unwrap(),
"hello world".to_owned()
@ -390,3 +374,12 @@ fn test_read_struct() {
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());
}