mirror of
https://codeberg.org/icewind/bitbuffer.git
synced 2026-06-03 16:44:06 +02:00
fix reading large signed ints
This commit is contained in:
parent
b46bc881f0
commit
efed5a68cb
3 changed files with 72 additions and 14 deletions
|
|
@ -5,7 +5,7 @@ use std::marker::PhantomData;
|
|||
use std::mem::size_of;
|
||||
use std::ops::{BitOrAssign, BitXor, Index, Range, RangeFrom};
|
||||
|
||||
use num_traits::{Float, PrimInt};
|
||||
use num_traits::{Float, PrimInt, WrappingSub};
|
||||
|
||||
use crate::endianness::Endianness;
|
||||
use crate::num_traits::{IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
|
||||
|
|
@ -360,7 +360,7 @@ where
|
|||
#[inline]
|
||||
pub fn read_int<T>(&self, position: usize, count: usize) -> Result<T>
|
||||
where
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + BitXor,
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + BitXor + WrappingSub,
|
||||
{
|
||||
let type_bit_size = size_of::<T>() * 8;
|
||||
|
||||
|
|
@ -395,7 +395,7 @@ where
|
|||
#[inline]
|
||||
pub unsafe fn read_int_unchecked<T>(&self, position: usize, count: usize, end: bool) -> T
|
||||
where
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + BitXor,
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + BitXor + WrappingSub,
|
||||
{
|
||||
let type_bit_size = size_of::<T>() * 8;
|
||||
|
||||
|
|
@ -453,14 +453,14 @@ where
|
|||
|
||||
fn make_signed<T>(&self, value: T, count: usize) -> T
|
||||
where
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + BitXor,
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + BitXor + WrappingSub,
|
||||
{
|
||||
if count == 0 {
|
||||
T::zero()
|
||||
} else if T::is_signed() {
|
||||
let sign_bit = value >> (count - 1) & T::one();
|
||||
if sign_bit == T::one() {
|
||||
value | (T::zero() - T::one()) ^ ((T::one() << count) - T::one())
|
||||
value | (T::zero() - T::one()) ^ (T::one() << count).wrapping_sub(&T::one())
|
||||
} else {
|
||||
value
|
||||
}
|
||||
|
|
@ -718,6 +718,7 @@ where
|
|||
pub fn read_float<T>(&self, position: usize) -> Result<T>
|
||||
where
|
||||
T: Float + UncheckedPrimitiveFloat,
|
||||
<T as UncheckedPrimitiveFloat>::INT: WrappingSub,
|
||||
{
|
||||
let type_bit_size = size_of::<T>() * 8;
|
||||
if position + type_bit_size + USIZE_BIT_SIZE > self.bit_len() {
|
||||
|
|
@ -745,6 +746,7 @@ where
|
|||
pub unsafe fn read_float_unchecked<T>(&self, position: usize, end: bool) -> T
|
||||
where
|
||||
T: Float + UncheckedPrimitiveFloat,
|
||||
<T as UncheckedPrimitiveFloat>::INT: WrappingSub,
|
||||
{
|
||||
if position & 7 == 0 {
|
||||
let byte_pos = position / 8;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::mem::size_of;
|
||||
use std::ops::BitOrAssign;
|
||||
|
||||
use num_traits::{Float, PrimInt};
|
||||
use num_traits::{Float, PrimInt, WrappingSub};
|
||||
|
||||
use crate::endianness::Endianness;
|
||||
use crate::num_traits::{IsSigned, UncheckedPrimitiveFloat, UncheckedPrimitiveInt};
|
||||
|
|
@ -141,7 +141,7 @@ where
|
|||
#[inline]
|
||||
pub fn read_int<T>(&mut self, count: usize) -> Result<T>
|
||||
where
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + WrappingSub,
|
||||
{
|
||||
let result = self.buffer.read_int(self.pos, count);
|
||||
if result.is_ok() {
|
||||
|
|
@ -154,7 +154,7 @@ where
|
|||
#[inline]
|
||||
pub unsafe fn read_int_unchecked<T>(&mut self, count: usize, end: bool) -> T
|
||||
where
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt,
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + WrappingSub,
|
||||
{
|
||||
let result = self.buffer.read_int_unchecked(self.pos, count, end);
|
||||
self.pos += count;
|
||||
|
|
@ -191,6 +191,7 @@ where
|
|||
pub fn read_float<T>(&mut self) -> Result<T>
|
||||
where
|
||||
T: Float + UncheckedPrimitiveFloat,
|
||||
<T as UncheckedPrimitiveFloat>::INT: WrappingSub,
|
||||
{
|
||||
let count = size_of::<T>() * 8;
|
||||
let result = self.buffer.read_float(self.pos);
|
||||
|
|
@ -205,6 +206,7 @@ where
|
|||
pub unsafe fn read_float_unchecked<T>(&mut self, end: bool) -> T
|
||||
where
|
||||
T: Float + UncheckedPrimitiveFloat,
|
||||
<T as UncheckedPrimitiveFloat>::INT: WrappingSub,
|
||||
{
|
||||
let count = size_of::<T>() * 8;
|
||||
let result = self.buffer.read_float_unchecked(self.pos, end);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
use bitbuffer::num_traits::{IsSigned, SplitFitUsize, UncheckedPrimitiveInt};
|
||||
use bitbuffer::{BigEndian, BitReadBuffer, BitReadStream, BitWriteStream, LittleEndian};
|
||||
use num_traits::{PrimInt, WrappingSub};
|
||||
use std::any::type_name;
|
||||
use std::fmt::Debug;
|
||||
use std::mem::size_of;
|
||||
use std::ops::BitOrAssign;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -216,8 +222,6 @@ fn test_write_to_slice() {
|
|||
stream.write_int(13253u64, 64).unwrap();
|
||||
}
|
||||
|
||||
dbg!(&data);
|
||||
|
||||
let mut read = BitReadStream::from(BitReadBuffer::new(&data[..], LittleEndian));
|
||||
|
||||
assert!(read.read_bool().unwrap());
|
||||
|
|
@ -248,16 +252,66 @@ fn test_write_last_slice() {
|
|||
fn test_write_be_long() {
|
||||
let mut bytes = vec![];
|
||||
let mut writer = BitWriteStream::new(&mut bytes, BigEndian);
|
||||
let num1 = 0b11000_00111110usize;
|
||||
let num2 = 0b1111111_11100100_00100100_11011101_00000011_11100000_01100111_11011011usize;
|
||||
let num1 = 0b11000_00111110u64;
|
||||
let num2 = 0b1111111_11100100_00100100_11011101_00000011_11100000_01100111_11011011u64;
|
||||
writer.write_int(num1, 13).unwrap();
|
||||
writer.write_int(num2, 63).unwrap();
|
||||
|
||||
let buffer = BitReadBuffer::new(&bytes, BigEndian);
|
||||
let mut reader = BitReadStream::new(buffer);
|
||||
let num1actual = reader.read_int::<usize>(13).unwrap();
|
||||
let num2actual = reader.read_int::<usize>(63).unwrap();
|
||||
let num1actual = reader.read_int::<u64>(13).unwrap();
|
||||
let num2actual = reader.read_int::<u64>(63).unwrap();
|
||||
|
||||
assert_eq!(num1actual, num1);
|
||||
assert_eq!(num2actual, num2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_all_lengths() {
|
||||
let pattern = 0b10101010u8;
|
||||
test_write_all_lengths_ty::<u8>(pattern);
|
||||
test_write_all_lengths_ty::<u16>(u16::from_le_bytes([pattern; 2]));
|
||||
test_write_all_lengths_ty::<u32>(u32::from_le_bytes([pattern; 4]));
|
||||
test_write_all_lengths_ty::<u64>(u64::from_le_bytes([pattern; 8]));
|
||||
test_write_all_lengths_ty::<u128>(u128::from_le_bytes([pattern; 16]));
|
||||
test_write_all_lengths_ty::<usize>(usize::from_le_bytes([pattern; size_of::<usize>()]));
|
||||
|
||||
test_write_all_lengths_ty::<i8>(i8::from_le_bytes([pattern; 1]));
|
||||
test_write_all_lengths_ty::<i16>(i16::from_le_bytes([pattern; 2]));
|
||||
test_write_all_lengths_ty::<i32>(i32::from_le_bytes([pattern; 4]));
|
||||
test_write_all_lengths_ty::<i64>(i64::from_le_bytes([pattern; 8]));
|
||||
test_write_all_lengths_ty::<i128>(i128::from_le_bytes([pattern; 16]));
|
||||
test_write_all_lengths_ty::<isize>(isize::from_le_bytes([pattern; size_of::<isize>()]));
|
||||
}
|
||||
|
||||
fn test_write_all_lengths_ty<
|
||||
T: PrimInt + BitOrAssign + IsSigned + UncheckedPrimitiveInt + Debug + SplitFitUsize + WrappingSub,
|
||||
>(
|
||||
pattern: T,
|
||||
) {
|
||||
let max_bits = size_of::<T>() * 8;
|
||||
let mut bytes = Vec::new();
|
||||
let mut writer = BitWriteStream::new(&mut bytes, BigEndian);
|
||||
|
||||
let mut expected = Vec::<T>::new();
|
||||
|
||||
for bits in 1..max_bits {
|
||||
let value = pattern >> (max_bits - bits);
|
||||
expected.push(value);
|
||||
writer.write_int(value, bits).unwrap();
|
||||
}
|
||||
|
||||
let buffer = BitReadBuffer::new(&bytes, BigEndian);
|
||||
let mut reader = BitReadStream::new(buffer);
|
||||
|
||||
for (bits, expected_value) in (1..max_bits).zip(expected.into_iter()) {
|
||||
let actual = reader.read_int::<T>(bits).unwrap();
|
||||
assert_eq!(
|
||||
expected_value,
|
||||
actual,
|
||||
"write + read for {} bits {}",
|
||||
bits,
|
||||
type_name::<T>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue