This commit is contained in:
EvilMuffinHa 2022-08-02 03:41:25 -04:00
parent c5e952d7d7
commit a5620cdda9

View File

@ -1,3 +1,6 @@
#![deny(missing_docs)]
#![warn(clippy::all)]
//! A crate for small integer optimization. Provides the [`SmallInt`] type. When possible this will //! A crate for small integer optimization. Provides the [`SmallInt`] type. When possible this will
//! inline an integer and store it on the stack if that integer is small. However, for larger values, //! inline an integer and store it on the stack if that integer is small. However, for larger values,
//! this will be instead stored on the heap as a pointer to a `u32` slice, a length, and a sign. //! this will be instead stored on the heap as a pointer to a `u32` slice, a length, and a sign.
@ -15,8 +18,8 @@ pub enum SmallIntError {
impl std::error::Error for SmallIntError {} impl std::error::Error for SmallIntError {}
impl std::fmt::Display for SmallIntError { impl core::fmt::Display for SmallIntError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let Self::ConversionError = self; let Self::ConversionError = self;
write!(f, "Error converting integer to SmallInt.") write!(f, "Error converting integer to SmallInt.")
} }
@ -37,7 +40,18 @@ pub enum SmallInt {
Heap((*mut u32, isize)) Heap((*mut u32, isize))
} }
impl Drop for SmallInt {
fn drop(&mut self) {
if let Self::Heap((r, s)) = self {
let size = usize::try_from(s.abs()).unwrap();
let mut slice = unsafe { core::slice::from_raw_parts(r, size) };
unsafe {
core::ptr::drop_in_place(&mut slice);
}
}
}
}
macro_rules! int_impl { macro_rules! int_impl {
($itype:ty) => { ($itype:ty) => {
@ -102,7 +116,7 @@ impl TryFrom<SmallInt> for u128 {
let mut ret: u128 = 0; let mut ret: u128 = 0;
let mut bits = 0; let mut bits = 0;
let size = usize::try_from(s.abs()).unwrap(); let size = usize::try_from(s.abs()).unwrap();
let slice = unsafe { std::slice::from_raw_parts(r, size) }; let slice = unsafe { core::slice::from_raw_parts(r, size) };
for i in slice { for i in slice {
if bits >= 128 { if bits >= 128 {
return Err(SmallIntError::ConversionError); return Err(SmallIntError::ConversionError);
@ -144,7 +158,7 @@ impl From<SmallInt> for BigInt {
SmallInt::Heap((r, s)) => { SmallInt::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap(); let size = usize::try_from(s.abs()).unwrap();
let sign = s.signum(); let sign = s.signum();
let slice = unsafe { std::slice::from_raw_parts(r, size) }; let slice = unsafe { core::slice::from_raw_parts(r, size) };
let bs = match sign { let bs = match sign {
0 => Sign::NoSign, 0 => Sign::NoSign,
-1 => Sign::Minus, -1 => Sign::Minus,
@ -162,27 +176,41 @@ impl From<SmallInt> for BigInt {
mod conversion_tests { mod conversion_tests {
use crate::SmallInt; use crate::SmallInt;
use num_bigint::{BigInt, Sign};
#[test] macro_rules! conversion_tests {
fn test_u8() { ($t:ty, $i:ident) => {
let i = u8::MAX; #[test]
let s = SmallInt::from(i); fn $i() {
assert_eq!(u8::try_from(s).unwrap(), i); let i = <$t>::MAX;
let s = SmallInt::from(i);
assert_eq!(<$t>::try_from(s).unwrap(), i);
let i = u8::MIN; let i = <$t>::MIN;
let s = SmallInt::from(i); let s = SmallInt::from(i);
assert_eq!(u8::try_from(s).unwrap(), i); assert_eq!(<$t>::try_from(s).unwrap(), i);
}
}
} }
#[test] conversion_tests!(u8, test_u8);
fn test_i8() { conversion_tests!(i8, test_i8);
let i = i8::MIN; conversion_tests!(u16, test_u16);
let s = SmallInt::from(i); conversion_tests!(i16, test_i16);
assert_eq!(i8::try_from(s).unwrap(), i); conversion_tests!(u32, test_u32);
conversion_tests!(i32, test_i32);
conversion_tests!(u64, test_u64);
conversion_tests!(i64, test_i64);
conversion_tests!(u128, test_u128);
conversion_tests!(i128, test_i128);
let i = i8::MAX; #[test]
fn test_bigint() {
let i = BigInt::new(Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]);
let s = SmallInt::from(i); let s = SmallInt::from(i);
assert_eq!(i8::try_from(s).unwrap(), i); assert_eq!(BigInt::from(s).to_u32_digits(), (Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]));
} }
} }