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

add unchecked reading to BitRead and BitReadSized

This commit is contained in:
Robin Appelman 2020-01-07 22:31:29 +01:00
commit 55eb866eb6
3 changed files with 160 additions and 3 deletions

View file

@ -92,6 +92,11 @@ pub trait BitRead<E: Endianness>: Sized {
/// Read the type from stream /// Read the type from stream
fn read(stream: &mut BitStream<E>) -> Result<Self>; fn read(stream: &mut BitStream<E>) -> Result<Self>;
#[doc(hidden)]
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<Self> {
Self::read(stream)
}
/// The number of bits that will be read or None if the number of bits will change depending /// The number of bits that will be read or None if the number of bits will change depending
/// on the bit stream /// on the bit stream
#[inline(always)] #[inline(always)]
@ -121,6 +126,11 @@ macro_rules! impl_read_int {
stream.read_int::<$type>(size_of::<$type>() * 8) stream.read_int::<$type>(size_of::<$type>() * 8)
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<$type> {
Ok(stream.read_int_unchecked::<$type>(size_of::<$type>() * 8))
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
Some(size_of::<$type>() * 8) Some(size_of::<$type>() * 8)
@ -137,6 +147,13 @@ macro_rules! impl_read_int_nonzero {
Ok(<$type>::new(stream.read()?)) Ok(<$type>::new(stream.read()?))
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<LittleEndian>) -> Result<Self> {
Ok(<$type>::new(
stream.read_int_unchecked(size_of::<$type>() * 8),
))
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
Some(size_of::<$type>() * 8) Some(size_of::<$type>() * 8)
@ -149,6 +166,13 @@ macro_rules! impl_read_int_nonzero {
Ok(<$type>::new(stream.read()?)) Ok(<$type>::new(stream.read()?))
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<BigEndian>) -> Result<Self> {
Ok(<$type>::new(
stream.read_int_unchecked(size_of::<$type>() * 8),
))
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
Some(size_of::<$type>() * 8) Some(size_of::<$type>() * 8)
@ -180,6 +204,11 @@ impl<E: Endianness> BitRead<E> for f32 {
stream.read_float::<f32>() stream.read_float::<f32>()
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<f32> {
Ok(stream.read_float_unchecked::<f32>())
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
Some(32) Some(32)
@ -192,6 +221,11 @@ impl<E: Endianness> BitRead<E> for f64 {
stream.read_float::<f64>() stream.read_float::<f64>()
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<f64> {
Ok(stream.read_float_unchecked::<f64>())
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
Some(64) Some(64)
@ -204,6 +238,11 @@ impl<E: Endianness> BitRead<E> for bool {
stream.read_bool() stream.read_bool()
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<bool> {
Ok(stream.read_bool_unchecked())
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
Some(1) Some(1)
@ -223,6 +262,11 @@ impl<E: Endianness, T: BitRead<E>> BitRead<E> for Rc<T> {
Ok(Rc::new(T::read(stream)?)) Ok(Rc::new(T::read(stream)?))
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<Self> {
Ok(Rc::new(T::read_unchecked(stream)?))
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
T::bit_size() T::bit_size()
@ -235,6 +279,11 @@ impl<E: Endianness, T: BitRead<E>> BitRead<E> for Arc<T> {
Ok(Arc::new(T::read(stream)?)) Ok(Arc::new(T::read(stream)?))
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<Self> {
Ok(Arc::new(T::read_unchecked(stream)?))
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
T::bit_size() T::bit_size()
@ -247,6 +296,11 @@ impl<E: Endianness, T: BitRead<E>> BitRead<E> for Box<T> {
Ok(Box::new(T::read(stream)?)) Ok(Box::new(T::read(stream)?))
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>) -> Result<Self> {
Ok(Box::new(T::read_unchecked(stream)?))
}
#[inline(always)] #[inline(always)]
fn bit_size() -> Option<usize> { fn bit_size() -> Option<usize> {
T::bit_size().and_then(|sum| T::bit_size().map(|size| sum + size)) T::bit_size().and_then(|sum| T::bit_size().map(|size| sum + size))
@ -341,6 +395,11 @@ pub trait BitReadSized<E: Endianness>: Sized {
/// Read the type from stream /// Read the type from stream
fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self>; fn read(stream: &mut BitStream<E>, size: usize) -> Result<Self>;
#[doc(hidden)]
unsafe fn read_unchecked(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
Self::read(stream, size)
}
/// The number of bits that will be read or None if the number of bits will change depending /// The number of bits that will be read or None if the number of bits will change depending
/// on the bit stream /// on the bit stream
#[inline(always)] #[inline(always)]
@ -357,6 +416,10 @@ macro_rules! impl_read_int_sized {
stream.read_int::<$type>(size) stream.read_int::<$type>(size)
} }
unsafe fn read_unchecked(stream: &mut BitStream<E>, size: usize) -> Result<$type> {
Ok(stream.read_int_unchecked::<$type>(size))
}
#[inline(always)] #[inline(always)]
fn bit_size_sized(size: usize) -> Option<usize> { fn bit_size_sized(size: usize) -> Option<usize> {
Some(size) Some(size)
@ -431,6 +494,15 @@ impl<E: Endianness, T: BitRead<E>> BitReadSized<E> for Vec<T> {
Ok(vec) Ok(vec)
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
let mut vec = Vec::with_capacity(size);
for _ in 0..size {
vec.push(stream.read_unchecked()?)
}
Ok(vec)
}
#[inline(always)] #[inline(always)]
fn bit_size_sized(size: usize) -> Option<usize> { fn bit_size_sized(size: usize) -> Option<usize> {
T::bit_size().map(|element_size| size * element_size) T::bit_size().map(|element_size| size * element_size)
@ -457,6 +529,17 @@ impl<E: Endianness, K: BitRead<E> + Eq + Hash, T: BitRead<E>> BitReadSized<E> fo
Ok(map) Ok(map)
} }
#[inline]
unsafe fn read_unchecked(stream: &mut BitStream<E>, size: usize) -> Result<Self> {
let mut map = HashMap::with_capacity(size);
for _ in 0..size {
let key = stream.read_unchecked()?;
let value = stream.read_unchecked()?;
map.insert(key, value);
}
Ok(map)
}
#[inline(always)] #[inline(always)]
fn bit_size_sized(size: usize) -> Option<usize> { fn bit_size_sized(size: usize) -> Option<usize> {
if let (Some(key_size), Some(value_size)) = (K::bit_size(), T::bit_size()) { if let (Some(key_size), Some(value_size)) = (K::bit_size(), T::bit_size()) {

View file

@ -99,6 +99,14 @@ where
result result
} }
#[doc(hidden)]
#[inline]
pub unsafe fn read_bool_unchecked(&mut self) -> bool {
let result = self.buffer.read_bool_unchecked(self.pos);
self.pos += 1;
result
}
/// Read a sequence of bits from the stream as integer /// Read a sequence of bits from the stream as integer
/// ///
/// # Errors /// # Errors
@ -195,9 +203,9 @@ where
T: Float + UncheckedPrimitiveFloat, T: Float + UncheckedPrimitiveFloat,
{ {
let count = size_of::<T>() * 8; let count = size_of::<T>() * 8;
let result = self.buffer.read_float_unchecked(self.pos);
self.pos += count; self.pos += count;
result
self.buffer.read_float_unchecked(self.pos)
} }
/// Read a series of bytes from the stream /// Read a series of bytes from the stream
@ -240,8 +248,9 @@ where
#[inline] #[inline]
pub unsafe fn read_bytes_unchecked(&mut self, byte_count: usize) -> Vec<u8> { pub unsafe fn read_bytes_unchecked(&mut self, byte_count: usize) -> Vec<u8> {
let count = byte_count * 8; let count = byte_count * 8;
let result = self.buffer.read_bytes_unchecked(self.pos, byte_count);
self.pos += count; self.pos += count;
self.buffer.read_bytes_unchecked(self.pos, byte_count) result
} }
/// Read a series of bytes from the stream as utf8 string /// Read a series of bytes from the stream as utf8 string
@ -547,6 +556,12 @@ where
T::read(self) T::read(self)
} }
#[doc(hidden)]
#[inline]
pub unsafe fn read_unchecked<T: BitRead<E>>(&mut self) -> Result<T> {
T::read_unchecked(self)
}
/// Read a value based on the provided type and size /// Read a value based on the provided type and size
/// ///
/// The meaning of the size parameter differs depending on the type that is being read /// The meaning of the size parameter differs depending on the type that is being read
@ -591,6 +606,12 @@ where
T::read(self, size) T::read(self, size)
} }
#[doc(hidden)]
#[inline]
pub unsafe fn read_sized_unchecked<T: BitReadSized<E>>(&mut self, size: usize) -> Result<T> {
T::read_unchecked(self, size)
}
/// Check if we can read a number of bits from the stream /// Check if we can read a number of bits from the stream
pub fn check_read(&self, count: usize) -> Result<()> { pub fn check_read(&self, count: usize) -> Result<()> {
if self.bits_left() < count { if self.bits_left() < count {

View file

@ -290,6 +290,27 @@ fn read_trait() {
assert_eq!(Some(0b011_0101_0), f); assert_eq!(Some(0b011_0101_0), f);
} }
#[test]
fn read_trait_unchecked() {
unsafe {
let buffer = BitBuffer::new(BYTES.to_vec(), BigEndian);
let mut stream = BitStream::new(buffer);
let a: u8 = stream.read_unchecked().unwrap();
assert_eq!(0b1011_0101, a);
let b: i8 = stream.read_unchecked().unwrap();
assert_eq!(0b110_1010, b);
let c: i16 = stream.read_unchecked().unwrap();
assert_eq!(-0b101_0011_0110_0111, c);
let d: bool = stream.read_unchecked().unwrap();
assert_eq!(true, d);
let e: Option<u8> = stream.read_unchecked().unwrap();
assert_eq!(None, e);
stream.set_pos(0).unwrap();
let f: Option<u8> = stream.read_unchecked().unwrap();
assert_eq!(Some(0b011_0101_0), f);
}
}
#[test] #[test]
fn read_sized_trait() { fn read_sized_trait() {
let buffer = BitBuffer::new(BYTES.to_vec(), BigEndian); let buffer = BitBuffer::new(BYTES.to_vec(), BigEndian);
@ -320,6 +341,38 @@ fn read_sized_trait() {
assert_eq!(0b10u8, result.read_int(2).unwrap()); assert_eq!(0b10u8, result.read_int(2).unwrap());
} }
#[test]
fn read_sized_trait_unchecked() {
unsafe {
let buffer = BitBuffer::new(BYTES.to_vec(), BigEndian);
let mut stream = BitStream::new(buffer);
let a: u8 = stream.read_sized_unchecked(4).unwrap();
assert_eq!(0b1011, a);
stream.set_pos(0).unwrap();
let vec: Vec<u16> = stream.read_sized_unchecked(3).unwrap();
assert_eq!(
vec![
0b1011_0101_0110_1010,
0b1010_1100_1001_1001,
0b1001_1001_1001_1001
],
vec
);
stream.set_pos(0).unwrap();
let vec: Vec<u8> = stream.read_sized_unchecked(3).unwrap();
assert_eq!(vec![0b1011_0101, 0b0110_1010, 0b1010_1100], vec);
stream.set_pos(0).unwrap();
let result: HashMap<u8, u8> = stream.read_sized_unchecked(2).unwrap();
assert_eq!(
hashmap!(0b1011_0101 => 0b0110_1010, 0b1010_1100 => 0b1001_1001),
result
);
stream.set_pos(0).unwrap();
let mut result: BitStream<BigEndian> = stream.read_sized_unchecked(4).unwrap();
assert_eq!(0b10u8, result.read_int(2).unwrap());
}
}
#[derive(BitRead, PartialEq, Debug)] #[derive(BitRead, PartialEq, Debug)]
struct TestStruct { struct TestStruct {
foo: u8, foo: u8,