mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
use unchecked type conversions
this is safe because we already checked their bit size
This commit is contained in:
parent
8fdcd6b4c4
commit
bd012039d0
6 changed files with 209 additions and 18 deletions
|
|
@ -9,6 +9,7 @@ use num_traits::{Float, PrimInt};
|
|||
|
||||
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>();
|
||||
|
|
@ -192,7 +193,7 @@ where
|
|||
/// [`ReadError::TooManyBits`]: enum.ReadError.html#variant.TooManyBits
|
||||
pub fn read_int<T>(&self, position: usize, count: usize) -> Result<T>
|
||||
where
|
||||
T: PrimInt + BitOrAssign + IsSigned,
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
|
||||
{
|
||||
let value = {
|
||||
let type_bit_size = size_of::<T>() * 8;
|
||||
|
|
@ -210,9 +211,9 @@ where
|
|||
let raw = self.read_usize(position, count)?;
|
||||
let max_signed_value = (1 << (type_bit_size - 1)) - 1;
|
||||
if T::is_signed() && raw > max_signed_value {
|
||||
return Ok(T::zero() - T::from(raw & max_signed_value).unwrap());
|
||||
return Ok(T::zero() - T::from_unchecked(raw & max_signed_value));
|
||||
} else {
|
||||
T::from(raw).unwrap()
|
||||
T::from_unchecked(raw)
|
||||
}
|
||||
} else {
|
||||
let mut left_to_read = count;
|
||||
|
|
@ -223,7 +224,7 @@ where
|
|||
while left_to_read > 0 {
|
||||
let bits_left = self.bit_len - read_pos;
|
||||
let read = min(min(left_to_read, max_read), bits_left);
|
||||
let data = T::from(self.read_usize(read_pos, read)?).unwrap();
|
||||
let data = T::from_unchecked(self.read_usize(read_pos, read)?);
|
||||
if E::is_le() {
|
||||
partial |= data << bit_offset;
|
||||
} else {
|
||||
|
|
@ -400,14 +401,18 @@ where
|
|||
/// [`ReadError::NotEnoughData`]: enum.ReadError.html#variant.NotEnoughData
|
||||
pub fn read_float<T>(&self, position: usize) -> Result<T>
|
||||
where
|
||||
T: Float,
|
||||
T: Float + UncheckedPrimitiveFloat,
|
||||
{
|
||||
if size_of::<T>() == 4 {
|
||||
let int = self.read_int::<u32>(position, 32)?;
|
||||
Ok(T::from(f32::from_bits(int)).unwrap())
|
||||
let int = if size_of::<T>() < USIZE_SIZE {
|
||||
self.read_usize(position, 32)? as u32
|
||||
} else {
|
||||
self.read_int::<u32>(position, 32)?
|
||||
};
|
||||
Ok(T::from_f32_unchecked(f32::from_bits(int)))
|
||||
} else {
|
||||
let int = self.read_int::<u64>(position, 64)?;
|
||||
Ok(T::from(f64::from_bits(int)).unwrap())
|
||||
Ok(T::from_f64_unchecked(f64::from_bits(int)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ mod endianness;
|
|||
mod is_signed;
|
||||
mod read;
|
||||
mod stream;
|
||||
mod unchecked_primitive;
|
||||
|
||||
/// Errors that can be returned when trying to read from a buffer
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use num_traits::{Float, PrimInt};
|
|||
|
||||
use crate::endianness::Endianness;
|
||||
use crate::is_signed::IsSigned;
|
||||
use crate::unchecked_primitive::{UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
|
||||
use crate::BitBuffer;
|
||||
use crate::{BitRead, BitReadSized, ReadError, Result};
|
||||
|
||||
|
|
@ -143,7 +144,7 @@ where
|
|||
/// [`ReadError::TooManyBits`]: enum.ReadError.html#variant.TooManyBits
|
||||
pub fn read_int<T>(&mut self, count: usize) -> Result<T>
|
||||
where
|
||||
T: PrimInt + BitOrAssign + IsSigned,
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
|
||||
{
|
||||
self.verify_bits_left(count)?;
|
||||
let result = self.buffer.read_int(self.pos, count);
|
||||
|
|
@ -181,7 +182,7 @@ where
|
|||
/// [`ReadError::NotEnoughData`]: enum.ReadError.html#variant.NotEnoughData
|
||||
pub fn read_float<T>(&mut self) -> Result<T>
|
||||
where
|
||||
T: Float,
|
||||
T: Float + UncheckedPrimitiveFloat,
|
||||
{
|
||||
let count = size_of::<T>() * 8;
|
||||
self.verify_bits_left(count)?;
|
||||
|
|
|
|||
179
src/unchecked_primitive.rs
Normal file
179
src/unchecked_primitive.rs
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/// Allow casting floats unchecked
|
||||
pub trait UncheckedPrimitiveFloat: Sized {
|
||||
fn from_f32_unchecked(n: f32) -> Self;
|
||||
fn from_f64_unchecked(n: f64) -> Self;
|
||||
}
|
||||
|
||||
impl UncheckedPrimitiveFloat for f32 {
|
||||
#[inline(always)]
|
||||
fn from_f32_unchecked(n: f32) -> Self {
|
||||
n
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_f64_unchecked(n: f64) -> Self {
|
||||
n as f32
|
||||
}
|
||||
}
|
||||
|
||||
impl UncheckedPrimitiveFloat for f64 {
|
||||
#[inline(always)]
|
||||
fn from_f32_unchecked(n: f32) -> Self {
|
||||
n as f64
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_f64_unchecked(n: f64) -> Self {
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
/// Allow casting integers unchecked
|
||||
pub trait UncheckedPrimitiveInt: Sized {
|
||||
fn from_u8_unchecked(n: u8) -> Self;
|
||||
fn from_i8_unchecked(n: i8) -> Self;
|
||||
fn from_u16_unchecked(n: u16) -> Self;
|
||||
fn from_i16_unchecked(n: i16) -> Self;
|
||||
fn from_u32_unchecked(n: u32) -> Self;
|
||||
fn from_i32_unchecked(n: i32) -> Self;
|
||||
fn from_u64_unchecked(n: u64) -> Self;
|
||||
fn from_i64_unchecked(n: i64) -> Self;
|
||||
fn from_u128_unchecked(n: u128) -> Self;
|
||||
fn from_i128_unchecked(n: i128) -> Self;
|
||||
fn from_usize_unchecked(n: usize) -> Self;
|
||||
fn from_isize_unchecked(n: isize) -> Self;
|
||||
|
||||
fn into_u8_unchecked(self) -> u8;
|
||||
fn into_i8_unchecked(self) -> i8;
|
||||
fn into_u16_unchecked(self) -> u16;
|
||||
fn into_i16_unchecked(self) -> i16;
|
||||
fn into_u32_unchecked(self) -> u32;
|
||||
fn into_i32_unchecked(self) -> i32;
|
||||
fn into_u64_unchecked(self) -> u64;
|
||||
fn into_i64_unchecked(self) -> i64;
|
||||
fn into_u128_unchecked(self) -> u128;
|
||||
fn into_i128_unchecked(self) -> i128;
|
||||
fn into_usize_unchecked(self) -> usize;
|
||||
fn into_isize_unchecked(self) -> isize;
|
||||
|
||||
fn from_unchecked<N: UncheckedPrimitiveInt>(n: N) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! impl_unchecked_int {
|
||||
($type:ty, $conv:ident) => {
|
||||
impl UncheckedPrimitiveInt for $type {
|
||||
#[inline(always)]
|
||||
fn from_u8_unchecked(n: u8) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_i8_unchecked(n: i8) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_u16_unchecked(n: u16) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_i16_unchecked(n: i16) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_u32_unchecked(n: u32) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_i32_unchecked(n: i32) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_u64_unchecked(n: u64) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_i64_unchecked(n: i64) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_u128_unchecked(n: u128) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_i128_unchecked(n: i128) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_usize_unchecked(n: usize) -> Self {
|
||||
n as $type
|
||||
}
|
||||
#[inline(always)]
|
||||
fn from_isize_unchecked(n: isize) -> Self {
|
||||
n as $type
|
||||
}
|
||||
|
||||
fn into_u8_unchecked(self) -> u8 {
|
||||
self as u8
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_i8_unchecked(self) -> i8 {
|
||||
self as i8
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_u16_unchecked(self) -> u16 {
|
||||
self as u16
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_i16_unchecked(self) -> i16 {
|
||||
self as i16
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_u32_unchecked(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_i32_unchecked(self) -> i32 {
|
||||
self as i32
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_u64_unchecked(self) -> u64 {
|
||||
self as u64
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_i64_unchecked(self) -> i64 {
|
||||
self as i64
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_u128_unchecked(self) -> u128 {
|
||||
self as u128
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_i128_unchecked(self) -> i128 {
|
||||
self as i128
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_usize_unchecked(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
#[inline(always)]
|
||||
fn into_isize_unchecked(self) -> isize {
|
||||
self as isize
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn from_unchecked<N: UncheckedPrimitiveInt>(n: N) -> Self {
|
||||
n.$conv()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_unchecked_int!(u8, into_u8_unchecked);
|
||||
impl_unchecked_int!(i8, into_i8_unchecked);
|
||||
impl_unchecked_int!(u16, into_u16_unchecked);
|
||||
impl_unchecked_int!(i16, into_i16_unchecked);
|
||||
impl_unchecked_int!(u32, into_u32_unchecked);
|
||||
impl_unchecked_int!(i32, into_i32_unchecked);
|
||||
impl_unchecked_int!(u64, into_u64_unchecked);
|
||||
impl_unchecked_int!(i64, into_i64_unchecked);
|
||||
impl_unchecked_int!(u128, into_u128_unchecked);
|
||||
impl_unchecked_int!(i128, into_i128_unchecked);
|
||||
impl_unchecked_int!(usize, into_usize_unchecked);
|
||||
impl_unchecked_int!(isize, into_isize_unchecked);
|
||||
Loading…
Add table
Add a link
Reference in a new issue