mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 08:34:07 +02:00
some 32bit optimizations
This commit is contained in:
parent
0fe7c04ece
commit
f09b56b36a
3 changed files with 62 additions and 28 deletions
|
|
@ -256,19 +256,50 @@ macro_rules! impl_is_signed {
|
|||
}
|
||||
|
||||
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 {
|
||||
($type:ty, $bytes:expr) => {
|
||||
($type:ty, $bytes:expr, 1 ) => {
|
||||
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)]
|
||||
fn into_bytes(self) -> Self::Iter {
|
||||
Self::Iter::new(self.to_le_bytes())
|
||||
fn into_bytes(self) -> Self::BytesIter {
|
||||
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!(isize, true);
|
||||
|
||||
impl_into_bytes!(u8, 1);
|
||||
impl_into_bytes!(u16, 2);
|
||||
impl_into_bytes!(u32, 4);
|
||||
impl_into_bytes!(u64, 8);
|
||||
impl_into_bytes!(u128, 16);
|
||||
impl_into_bytes!(u8, 1, 1);
|
||||
impl_into_bytes!(u16, 2, 1);
|
||||
impl_into_bytes!(u32, 4, 2);
|
||||
impl_into_bytes!(u64, 8, 4);
|
||||
impl_into_bytes!(u128, 16, 8);
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl_into_bytes!(usize, 8);
|
||||
impl_into_bytes!(usize, 8, 4);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
impl_into_bytes!(usize, 4);
|
||||
impl_into_bytes!(usize, 4, 2);
|
||||
|
||||
impl_into_bytes!(i8, 1);
|
||||
impl_into_bytes!(i16, 2);
|
||||
impl_into_bytes!(i32, 4);
|
||||
impl_into_bytes!(i64, 8);
|
||||
impl_into_bytes!(i128, 16);
|
||||
impl_into_bytes!(i8, 1, 1);
|
||||
impl_into_bytes!(i16, 2, 1);
|
||||
impl_into_bytes!(i32, 4, 2);
|
||||
impl_into_bytes!(i64, 8, 4);
|
||||
impl_into_bytes!(i128, 16, 8);
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
impl_into_bytes!(isize, 8);
|
||||
impl_into_bytes!(isize, 8, 4);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
impl_into_bytes!(isize, 4);
|
||||
impl_into_bytes!(isize, 4, 2);
|
||||
|
|
|
|||
|
|
@ -29,13 +29,14 @@ impl<'a, E: Endianness> WriteBuffer<'a, E> {
|
|||
pub fn push_non_fit_bits<I>(&mut self, bits: I, count: usize)
|
||||
where
|
||||
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)
|
||||
.chain(once(count - full_bytes * 8));
|
||||
.chain(once(count - full_bytes * chunk_bits));
|
||||
if E::is_le() {
|
||||
bits.zip(counts)
|
||||
.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 {
|
||||
return;
|
||||
}
|
||||
debug_assert!(count < USIZE_BITS - 8);
|
||||
|
||||
// ensure there are no stray bits
|
||||
let bits = bits & (usize::MAX >> (USIZE_BITS - count));
|
||||
|
||||
let bit_offset = self.bit_len & 7;
|
||||
|
||||
debug_assert!(count <= USIZE_BITS - bit_offset);
|
||||
|
||||
let last_written_byte = if bit_offset > 0 {
|
||||
self.bytes.pop().unwrap_or(0)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ where
|
|||
fn push_non_fit_bits<I>(&mut self, bits: I, count: usize)
|
||||
where
|
||||
I: ExactSizeIterator,
|
||||
I: DoubleEndedIterator<Item = u8>,
|
||||
I: DoubleEndedIterator<Item = u16>,
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
self.push_non_fit_bits(value.into_bytes(), count)
|
||||
self.push_non_fit_bits(value.into_u16(), count)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue