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

some 32bit optimizations

This commit is contained in:
Robin Appelman 2021-07-27 15:52:47 +02:00
commit f09b56b36a
3 changed files with 62 additions and 28 deletions

View file

@ -256,19 +256,50 @@ macro_rules! impl_is_signed {
} }
pub trait IntoBytes: Sized { pub trait IntoBytes: Sized {
type Iter: DoubleEndedIterator<Item = u8> + ExactSizeIterator; type BytesIter: DoubleEndedIterator<Item = u8> + ExactSizeIterator;
type U16Iter: DoubleEndedIterator<Item = u16> + ExactSizeIterator;
fn into_bytes(self) -> Self::Iter; fn into_bytes(self) -> Self::BytesIter;
fn into_u16(self) -> Self::U16Iter;
} }
macro_rules! impl_into_bytes { macro_rules! impl_into_bytes {
($type:ty, $bytes:expr) => { ($type:ty, $bytes:expr, 1 ) => {
impl IntoBytes for $type { impl IntoBytes for $type {
type Iter = std::array::IntoIter<u8, $bytes>; type BytesIter = std::array::IntoIter<u8, $bytes>;
type U16Iter = std::array::IntoIter<u16, 1>;
#[inline(always)] #[inline(always)]
fn into_bytes(self) -> Self::Iter { fn into_bytes(self) -> Self::BytesIter {
Self::Iter::new(self.to_le_bytes()) Self::BytesIter::new(self.to_le_bytes())
}
#[inline(always)]
fn into_u16(self) -> Self::U16Iter {
Self::U16Iter::new([self as u16])
}
}
};
($type:ty, $bytes:expr, $shorts:expr ) => {
impl IntoBytes for $type {
type BytesIter = std::array::IntoIter<u8, $bytes>;
type U16Iter = std::array::IntoIter<u16, { $shorts }>;
#[inline(always)]
fn into_bytes(self) -> Self::BytesIter {
Self::BytesIter::new(self.to_le_bytes())
}
#[inline(always)]
fn into_u16(self) -> Self::U16Iter {
use std::convert::TryInto;
let bytes = self.to_le_bytes();
let (head, aligned, tail) = unsafe { bytes[..].align_to::<u16>() };
debug_assert_eq!(0, head.len());
debug_assert_eq!(0, tail.len());
Self::U16Iter::new(aligned.try_into().unwrap())
} }
} }
}; };
@ -287,24 +318,24 @@ impl_is_signed!(i64, true);
impl_is_signed!(i128, true); impl_is_signed!(i128, true);
impl_is_signed!(isize, true); impl_is_signed!(isize, true);
impl_into_bytes!(u8, 1); impl_into_bytes!(u8, 1, 1);
impl_into_bytes!(u16, 2); impl_into_bytes!(u16, 2, 1);
impl_into_bytes!(u32, 4); impl_into_bytes!(u32, 4, 2);
impl_into_bytes!(u64, 8); impl_into_bytes!(u64, 8, 4);
impl_into_bytes!(u128, 16); impl_into_bytes!(u128, 16, 8);
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
impl_into_bytes!(usize, 8); impl_into_bytes!(usize, 8, 4);
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
impl_into_bytes!(usize, 4); impl_into_bytes!(usize, 4, 2);
impl_into_bytes!(i8, 1); impl_into_bytes!(i8, 1, 1);
impl_into_bytes!(i16, 2); impl_into_bytes!(i16, 2, 1);
impl_into_bytes!(i32, 4); impl_into_bytes!(i32, 4, 2);
impl_into_bytes!(i64, 8); impl_into_bytes!(i64, 8, 4);
impl_into_bytes!(i128, 16); impl_into_bytes!(i128, 16, 8);
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
impl_into_bytes!(isize, 8); impl_into_bytes!(isize, 8, 4);
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
impl_into_bytes!(isize, 4); impl_into_bytes!(isize, 4, 2);

View file

@ -29,13 +29,14 @@ impl<'a, E: Endianness> WriteBuffer<'a, E> {
pub fn push_non_fit_bits<I>(&mut self, bits: I, count: usize) pub fn push_non_fit_bits<I>(&mut self, bits: I, count: usize)
where where
I: ExactSizeIterator, I: ExactSizeIterator,
I: DoubleEndedIterator<Item = u8>, I: DoubleEndedIterator<Item = u16>,
{ {
let full_bytes = min(bits.len() - 1, count / 8); let chunk_bits = u16::BITS as usize;
let full_bytes = min(bits.len() - 1, count / chunk_bits);
let counts = repeat(8) let counts = repeat(chunk_bits)
.take(full_bytes) .take(full_bytes)
.chain(once(count - full_bytes * 8)); .chain(once(count - full_bytes * chunk_bits));
if E::is_le() { if E::is_le() {
bits.zip(counts) bits.zip(counts)
.for_each(|(chunk, count)| self.push_bits(chunk as usize, count)) .for_each(|(chunk, count)| self.push_bits(chunk as usize, count))
@ -52,12 +53,14 @@ impl<'a, E: Endianness> WriteBuffer<'a, E> {
if count == 0 { if count == 0 {
return; return;
} }
debug_assert!(count < USIZE_BITS - 8);
// ensure there are no stray bits // ensure there are no stray bits
let bits = bits & (usize::MAX >> (USIZE_BITS - count)); let bits = bits & (usize::MAX >> (USIZE_BITS - count));
let bit_offset = self.bit_len & 7; let bit_offset = self.bit_len & 7;
debug_assert!(count <= USIZE_BITS - bit_offset);
let last_written_byte = if bit_offset > 0 { let last_written_byte = if bit_offset > 0 {
self.bytes.pop().unwrap_or(0) self.bytes.pop().unwrap_or(0)
} else { } else {

View file

@ -76,7 +76,7 @@ where
fn push_non_fit_bits<I>(&mut self, bits: I, count: usize) fn push_non_fit_bits<I>(&mut self, bits: I, count: usize)
where where
I: ExactSizeIterator, I: ExactSizeIterator,
I: DoubleEndedIterator<Item = u8>, I: DoubleEndedIterator<Item = u16>,
{ {
self.buffer.push_non_fit_bits(bits, count) self.buffer.push_non_fit_bits(bits, count)
} }
@ -142,10 +142,10 @@ where
}); });
} }
if type_bit_size < USIZE_BITS || count < USIZE_BITS { if type_bit_size < USIZE_BITS || count <= (USIZE_BITS - (self.bit_len() % 8)) {
self.push_bits(value.into_usize_unchecked(), count); self.push_bits(value.into_usize_unchecked(), count);
} else { } else {
self.push_non_fit_bits(value.into_bytes(), count) self.push_non_fit_bits(value.into_u16(), count)
} }
Ok(()) Ok(())