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
//! 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.
@ -15,8 +18,8 @@ pub enum SmallIntError {
impl std::error::Error for SmallIntError {}
impl std::fmt::Display for SmallIntError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl core::fmt::Display for SmallIntError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let Self::ConversionError = self;
write!(f, "Error converting integer to SmallInt.")
}
@ -37,7 +40,18 @@ pub enum SmallInt {
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 {
($itype:ty) => {
@ -102,7 +116,7 @@ impl TryFrom<SmallInt> for u128 {
let mut ret: u128 = 0;
let mut bits = 0;
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 {
if bits >= 128 {
return Err(SmallIntError::ConversionError);
@ -144,7 +158,7 @@ impl From<SmallInt> for BigInt {
SmallInt::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap();
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 {
0 => Sign::NoSign,
-1 => Sign::Minus,
@ -162,27 +176,41 @@ impl From<SmallInt> for BigInt {
mod conversion_tests {
use crate::SmallInt;
use num_bigint::{BigInt, Sign};
macro_rules! conversion_tests {
($t:ty, $i:ident) => {
#[test]
fn test_u8() {
let i = u8::MAX;
fn $i() {
let i = <$t>::MAX;
let s = SmallInt::from(i);
assert_eq!(u8::try_from(s).unwrap(), i);
assert_eq!(<$t>::try_from(s).unwrap(), i);
let i = u8::MIN;
let i = <$t>::MIN;
let s = SmallInt::from(i);
assert_eq!(u8::try_from(s).unwrap(), i);
assert_eq!(<$t>::try_from(s).unwrap(), i);
}
#[test]
fn test_i8() {
let i = i8::MIN;
let s = SmallInt::from(i);
assert_eq!(i8::try_from(s).unwrap(), i);
let i = i8::MAX;
let s = SmallInt::from(i);
assert_eq!(i8::try_from(s).unwrap(), i);
}
}
conversion_tests!(u8, test_u8);
conversion_tests!(i8, test_i8);
conversion_tests!(u16, test_u16);
conversion_tests!(i16, test_i16);
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);
#[test]
fn test_bigint() {
let i = BigInt::new(Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]);
let s = SmallInt::from(i);
assert_eq!(BigInt::from(s).to_u32_digits(), (Sign::Plus, vec![5, 4, 8, 3, 2, 9, 3]));
}
}