mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
optimize aligned floats
This commit is contained in:
parent
eb4bafc310
commit
9aba4351ac
5 changed files with 82 additions and 20 deletions
|
|
@ -1,12 +1,21 @@
|
||||||
|
use crate::Endianness;
|
||||||
|
use std::array::TryFromSliceError;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
/// some extra number traits
|
/// some extra number traits
|
||||||
|
|
||||||
/// Allow casting floats unchecked
|
/// Allow casting floats unchecked
|
||||||
pub trait UncheckedPrimitiveFloat: Sized {
|
pub trait UncheckedPrimitiveFloat: Sized {
|
||||||
|
type BYTES: AsRef<[u8]> + for<'a> TryFrom<&'a [u8], Error = TryFromSliceError>;
|
||||||
|
|
||||||
fn from_f32_unchecked(n: f32) -> Self;
|
fn from_f32_unchecked(n: f32) -> Self;
|
||||||
fn from_f64_unchecked(n: f64) -> Self;
|
fn from_f64_unchecked(n: f64) -> Self;
|
||||||
|
fn to_bytes<E: Endianness>(self) -> Self::BYTES;
|
||||||
|
fn from_bytes<E: Endianness>(bytes: Self::BYTES) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UncheckedPrimitiveFloat for f32 {
|
impl UncheckedPrimitiveFloat for f32 {
|
||||||
|
type BYTES = [u8; 4];
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from_f32_unchecked(n: f32) -> Self {
|
fn from_f32_unchecked(n: f32) -> Self {
|
||||||
n
|
n
|
||||||
|
|
@ -15,9 +24,24 @@ impl UncheckedPrimitiveFloat for f32 {
|
||||||
fn from_f64_unchecked(n: f64) -> Self {
|
fn from_f64_unchecked(n: f64) -> Self {
|
||||||
n as f32
|
n as f32
|
||||||
}
|
}
|
||||||
|
fn to_bytes<E: Endianness>(self) -> Self::BYTES {
|
||||||
|
if E::is_le() {
|
||||||
|
self.to_le_bytes()
|
||||||
|
} else {
|
||||||
|
self.to_be_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn from_bytes<E: Endianness>(bytes: Self::BYTES) -> Self {
|
||||||
|
if E::is_le() {
|
||||||
|
Self::from_le_bytes(bytes)
|
||||||
|
} else {
|
||||||
|
Self::from_be_bytes(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UncheckedPrimitiveFloat for f64 {
|
impl UncheckedPrimitiveFloat for f64 {
|
||||||
|
type BYTES = [u8; 8];
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from_f32_unchecked(n: f32) -> Self {
|
fn from_f32_unchecked(n: f32) -> Self {
|
||||||
n as f64
|
n as f64
|
||||||
|
|
@ -26,6 +50,20 @@ impl UncheckedPrimitiveFloat for f64 {
|
||||||
fn from_f64_unchecked(n: f64) -> Self {
|
fn from_f64_unchecked(n: f64) -> Self {
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
fn to_bytes<E: Endianness>(self) -> Self::BYTES {
|
||||||
|
if E::is_le() {
|
||||||
|
self.to_le_bytes()
|
||||||
|
} else {
|
||||||
|
self.to_be_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn from_bytes<E: Endianness>(bytes: Self::BYTES) -> Self {
|
||||||
|
if E::is_le() {
|
||||||
|
Self::from_le_bytes(bytes)
|
||||||
|
} else {
|
||||||
|
Self::from_be_bytes(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allow casting integers unchecked
|
/// Allow casting integers unchecked
|
||||||
|
|
|
||||||
|
|
@ -737,16 +737,24 @@ where
|
||||||
where
|
where
|
||||||
T: Float + UncheckedPrimitiveFloat,
|
T: Float + UncheckedPrimitiveFloat,
|
||||||
{
|
{
|
||||||
if size_of::<T>() == 4 {
|
if position & 7 == 0 {
|
||||||
let int = if size_of::<T>() < USIZE_SIZE {
|
let byte_pos = position / 8;
|
||||||
self.read_fit_usize::<u32>(position, 32, end)
|
let bytes = self.slice[byte_pos..byte_pos + size_of::<T>()]
|
||||||
} else {
|
.try_into()
|
||||||
self.read_no_fit_usize::<u32>(position, 32, end)
|
.unwrap();
|
||||||
};
|
T::from_bytes::<E>(bytes)
|
||||||
T::from_f32_unchecked(f32::from_bits(int))
|
|
||||||
} else {
|
} else {
|
||||||
let int = self.read_no_fit_usize::<u64>(position, 64, end);
|
if size_of::<T>() == 4 {
|
||||||
T::from_f64_unchecked(f64::from_bits(int))
|
let int = if size_of::<T>() < USIZE_SIZE {
|
||||||
|
self.read_fit_usize::<u32>(position, 32, end)
|
||||||
|
} else {
|
||||||
|
self.read_no_fit_usize::<u32>(position, 32, end)
|
||||||
|
};
|
||||||
|
T::from_f32_unchecked(f32::from_bits(int))
|
||||||
|
} else {
|
||||||
|
let int = self.read_no_fit_usize::<u64>(position, 64, end);
|
||||||
|
T::from_f64_unchecked(f64::from_bits(int))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,4 +93,10 @@ impl<'a, E: Endianness> WriteBuffer<'a, E> {
|
||||||
let merged = merged.to_le_bytes();
|
let merged = merged.to_le_bytes();
|
||||||
self.bytes[byte_pos..byte_pos + byte_count].copy_from_slice(&merged[0..byte_count]);
|
self.bytes[byte_pos..byte_pos + byte_count].copy_from_slice(&merged[0..byte_count]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn extends_from_slice(&mut self, slice: &[u8]) {
|
||||||
|
debug_assert_eq!(0, self.bit_len & 7);
|
||||||
|
self.bytes.extend_from_slice(slice);
|
||||||
|
self.bit_len += slice.len() * 8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,14 +173,19 @@ where
|
||||||
where
|
where
|
||||||
T: Float + UncheckedPrimitiveFloat,
|
T: Float + UncheckedPrimitiveFloat,
|
||||||
{
|
{
|
||||||
if size_of::<T>() == 4 {
|
if self.buffer.bit_len() & 7 == 0 {
|
||||||
if size_of::<T>() < USIZE_SIZE {
|
let bytes = value.to_bytes::<E>();
|
||||||
self.push_bits(value.to_f32().unwrap().to_bits() as usize, 32);
|
self.buffer.extends_from_slice(bytes.as_ref());
|
||||||
} else {
|
|
||||||
self.push_non_fit_bits(value.to_f32().unwrap().to_bits().into_bytes(), 32)
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
self.push_non_fit_bits(value.to_f64().unwrap().to_bits().into_bytes(), 64)
|
if size_of::<T>() == 4 {
|
||||||
|
if size_of::<T>() < USIZE_SIZE {
|
||||||
|
self.push_bits(value.to_f32().unwrap().to_bits() as usize, 32);
|
||||||
|
} else {
|
||||||
|
self.push_non_fit_bits(value.to_f32().unwrap().to_bits().into_bytes(), 32)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
self.push_non_fit_bits(value.to_f64().unwrap().to_bits().into_bytes(), 64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -205,10 +210,14 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
|
pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
|
||||||
bytes
|
if self.buffer.bit_len() & 7 == 0 {
|
||||||
.iter()
|
self.buffer.extends_from_slice(bytes);
|
||||||
.copied()
|
} else {
|
||||||
.for_each(|chunk| self.push_bits(chunk as usize, 8));
|
bytes
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.for_each(|chunk| self.push_bits(chunk as usize, 8));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use bitbuffer::{
|
||||||
};
|
};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
fn roundtrip<
|
fn roundtrip<
|
||||||
T: BitRead<'static, BigEndian>
|
T: BitRead<'static, BigEndian>
|
||||||
+ BitWrite<BigEndian>
|
+ BitWrite<BigEndian>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue