mirror of
				https://gitlab.com/artofrev/smallint.git
				synced 2025-10-30 22:41:12 -04:00 
			
		
		
		
	ver. 0.2.0: add unsigned integer type; private raw fields
This commit is contained in:
		
							parent
							
								
									209cd7aa83
								
							
						
					
					
						commit
						5eb006e4c7
					
				| @ -1,6 +1,6 @@ | ||||
| [package] | ||||
| name = "smallint" | ||||
| version = "0.1.0" | ||||
| version = "0.2.0" | ||||
| edition = "2021" | ||||
| authors = ["artofrev"] | ||||
| description = "A library for optimized arbitrary precision integers." | ||||
|  | ||||
							
								
								
									
										199
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										199
									
								
								src/lib.rs
									
									
									
									
									
								
							| @ -5,9 +5,17 @@ | ||||
| //! 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.
 | ||||
| 
 | ||||
| 
 | ||||
| // Invariant: If a small integer is within the bounds of an inline value, it must be inline.
 | ||||
| // Invariant: If a small integer is on the heap, the size is the minimum digits required to
 | ||||
| // represent it.
 | ||||
| 
 | ||||
| #[cfg(feature="num-bigint")] | ||||
| use num_bigint::BigInt; | ||||
| 
 | ||||
| #[cfg(feature="num-bigint")] | ||||
| use num_bigint::BigUint; | ||||
| 
 | ||||
| #[cfg(feature="num-bigint")] | ||||
| use num_bigint::Sign; | ||||
| 
 | ||||
| @ -30,23 +38,34 @@ impl core::fmt::Display for SmallIntError { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /// An integer-like type that will store small integers up to `i64` inline. Larger integers are
 | ||||
| /// represented as `BigInt` types, which are stored on the heap.
 | ||||
| /// An integer-like type that will store small integers up to `i128` inline. Larger integers are
 | ||||
| /// represented as a slice to a sequence of base 2<sup>32</sup> digits represented as a `*mut u32`.
 | ||||
| #[derive(Clone, PartialEq, Eq)] | ||||
| pub enum SmallInt { | ||||
|     /// An integer stored inline.
 | ||||
| pub struct SmallInt(SmallIntType); | ||||
| 
 | ||||
| 
 | ||||
| /// An integer-like type that will store small integers up to `u128` inline. Larger integers are
 | ||||
| /// represented as a slice to a sequence of base 2<sup>32</sup> digits represented as a `*mut u32`.
 | ||||
| #[derive(Clone, PartialEq, Eq)] | ||||
| pub struct SmallUint(SmallUintType); | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone, PartialEq, Eq)] | ||||
| enum SmallIntType { | ||||
|     Inline(i128), | ||||
|     /// A larger integer stored on the heap. This value is represented in base 2<sup>32</sup> and
 | ||||
|     /// ordered least significant digit first. Also stored with the size and sign of the integer.
 | ||||
|     ///
 | ||||
|     /// It is assumed that values stored on the heap are larger than the maximum value of inline
 | ||||
|     /// integers.
 | ||||
|     Heap((*mut u32, isize)) | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, PartialEq, Eq)] | ||||
| enum SmallUintType { | ||||
|     Inline(u128), | ||||
|     Heap((*mut u32, usize)) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| impl Drop for SmallInt { | ||||
|     fn drop(&mut self) { | ||||
|         if let Self::Heap((r, s)) = self { | ||||
|         if let Self(SmallIntType::Heap((r, s))) = self { | ||||
|             let size = usize::try_from(s.abs()).unwrap(); | ||||
|             let slice = unsafe { core::slice::from_raw_parts_mut(*r, size) }; | ||||
|             unsafe { std::mem::drop(Box::from_raw(slice)) } | ||||
| @ -55,43 +74,90 @@ impl Drop for SmallInt { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| impl Drop for SmallUint { | ||||
|     fn drop(&mut self) { | ||||
|         if let Self(SmallUintType::Heap((r, s))) = self { | ||||
|             let slice = unsafe { core::slice::from_raw_parts_mut(*r, *s) }; | ||||
|             unsafe { std::mem::drop(Box::from_raw(slice)) } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| macro_rules! int_impl { | ||||
|     ($itype:ty) => { | ||||
|         impl From<$itype> for SmallInt { | ||||
|     ($itype:ty, $rt:tt, $rtt:tt, $n:tt) => { | ||||
|         impl From<$itype> for $rt { | ||||
|             fn from(a: $itype) -> Self { | ||||
|                 SmallInt::Inline(i128::from(a)) | ||||
|                 Self(<$rtt>::Inline($n::from(a))) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl TryFrom<SmallInt> for $itype { | ||||
|         impl TryFrom<$rt> for $itype { | ||||
| 
 | ||||
|             type Error = SmallIntError; | ||||
| 
 | ||||
|             fn try_from(s: SmallInt) -> Result<Self, Self::Error> { | ||||
|                 match s { | ||||
|                     SmallInt::Inline(i) => <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError), | ||||
|                     SmallInt::Heap((_, _)) => Err(SmallIntError::ConversionError), | ||||
|             fn try_from(s: $rt) -> Result<Self, Self::Error> { | ||||
|                 match s.0 { | ||||
|                     $rtt::Inline(i) => <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError), | ||||
|                     $rtt::Heap((_, _)) => Err(SmallIntError::ConversionError), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int_impl!(u8); | ||||
| int_impl!(u16); | ||||
| int_impl!(u32); | ||||
| int_impl!(u64); | ||||
| int_impl!(i8); | ||||
| int_impl!(i16); | ||||
| int_impl!(i32); | ||||
| int_impl!(i64); | ||||
| int_impl!(i128); | ||||
| int_impl!(u8, SmallInt, SmallIntType,   i128); | ||||
| int_impl!(u16, SmallInt, SmallIntType,  i128); | ||||
| int_impl!(u32, SmallInt, SmallIntType,  i128); | ||||
| int_impl!(u64, SmallInt, SmallIntType,  i128); | ||||
| int_impl!(i8, SmallInt, SmallIntType,   i128); | ||||
| int_impl!(i16, SmallInt, SmallIntType,  i128); | ||||
| int_impl!(i32, SmallInt, SmallIntType,  i128); | ||||
| int_impl!(i64, SmallInt, SmallIntType,  i128); | ||||
| int_impl!(i128, SmallInt, SmallIntType, i128); | ||||
| 
 | ||||
| int_impl!(u8, SmallUint, SmallUintType,   u128); | ||||
| int_impl!(u16, SmallUint, SmallUintType,  u128); | ||||
| int_impl!(u32, SmallUint, SmallUintType,  u128); | ||||
| int_impl!(u64, SmallUint, SmallUintType,  u128); | ||||
| int_impl!(u128, SmallUint, SmallUintType, u128); | ||||
| 
 | ||||
| macro_rules! try_from_itou { | ||||
|     ($itype:ty) => { | ||||
|         impl TryFrom<$itype> for SmallUint { | ||||
| 
 | ||||
|             type Error = SmallIntError; | ||||
| 
 | ||||
|             fn try_from(a: $itype) -> Result<Self, Self::Error> { | ||||
|                 Ok(Self(SmallUintType::Inline(u128::try_from(a).map_err(|_| SmallIntError::ConversionError)?))) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl TryFrom<SmallUint> for $itype { | ||||
| 
 | ||||
|             type Error = SmallIntError; | ||||
| 
 | ||||
|             fn try_from(s: SmallUint) -> Result<Self, Self::Error> { | ||||
|                 match s.0 { | ||||
|                     SmallUintType::Inline(i) => <$itype>::try_from(i).map_err(|_| SmallIntError::ConversionError), | ||||
|                     SmallUintType::Heap((_, _)) => Err(SmallIntError::ConversionError), | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| try_from_itou!(i8); | ||||
| try_from_itou!(i16); | ||||
| try_from_itou!(i32); | ||||
| try_from_itou!(i64); | ||||
| try_from_itou!(i128); | ||||
| 
 | ||||
| 
 | ||||
| impl From<u128> for SmallInt { | ||||
|     fn from(a: u128) -> Self { | ||||
|         match i128::try_from(a) { | ||||
|             Ok(i) => Self::Inline(i), | ||||
|             Ok(i) => Self(SmallIntType::Inline(i)), | ||||
|             Err(_) => { | ||||
|                 let mut v = a; | ||||
|                 let mut vec = Vec::with_capacity(4); | ||||
| @ -101,7 +167,7 @@ impl From<u128> for SmallInt { | ||||
|                     v >>= 32; | ||||
|                 } | ||||
|                 let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); | ||||
|                 SmallInt::Heap((slice.as_mut_ptr(), isize::try_from(slice.len()).unwrap())) | ||||
|                 Self(SmallIntType::Heap((slice.as_mut_ptr(), isize::try_from(slice.len()).unwrap()))) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -112,9 +178,9 @@ impl TryFrom<SmallInt> for u128 { | ||||
|     type Error = SmallIntError; | ||||
| 
 | ||||
|     fn try_from(s: SmallInt) -> Result<Self, Self::Error> { | ||||
|         match s { | ||||
|             SmallInt::Inline(i) => u128::try_from(i).map_err(|_| SmallIntError::ConversionError), | ||||
|             SmallInt::Heap((r, s)) => { | ||||
|         match s.0 { | ||||
|             SmallIntType::Inline(i) => u128::try_from(i).map_err(|_| SmallIntError::ConversionError), | ||||
|             SmallIntType::Heap((r, s)) => { | ||||
|                 let mut ret: u128 = 0; | ||||
|                 let mut bits = 0; | ||||
|                 let size = usize::try_from(s.abs()).unwrap(); | ||||
| @ -133,12 +199,42 @@ impl TryFrom<SmallInt> for u128 { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<SmallUint> for SmallInt { | ||||
|     fn from(s: SmallUint) -> Self { | ||||
|         match s.0 { | ||||
|             SmallUintType::Inline(i) => SmallInt::from(i), | ||||
|             SmallUintType::Heap((r, s)) => SmallInt(SmallIntType::Heap((r, isize::try_from(s).unwrap()))) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TryFrom<SmallInt> for SmallUint { | ||||
| 
 | ||||
|     type Error = SmallIntError; | ||||
| 
 | ||||
|     fn try_from(value: SmallInt) -> Result<Self, Self::Error> { | ||||
|         match value.0 { | ||||
|             SmallIntType::Inline(i) => Self::try_from(i), | ||||
|             SmallIntType::Heap((r, s)) => { | ||||
|                 let size = usize::try_from(s).map_err(|_| SmallIntError::ConversionError)?; | ||||
|                 if size > 4 { | ||||
|                     Ok(Self(SmallUintType::Heap((r, size)))) | ||||
|                 } else { | ||||
|                     Ok(Self(SmallUintType::Inline(u128::try_from(value)?))) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[cfg(feature="num-bigint")] | ||||
| impl From<BigInt> for SmallInt { | ||||
|     fn from(b: BigInt) -> Self { | ||||
|         match (&b).try_into() { | ||||
|             Ok(i) => SmallInt::Inline(i), | ||||
|             Ok(i) => Self(SmallIntType::Inline(i)), | ||||
|             Err(_) => { | ||||
|                 let (sign, vec) = b.to_u32_digits(); | ||||
|                 let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); | ||||
| @ -147,7 +243,7 @@ impl From<BigInt> for SmallInt { | ||||
|                     Sign::NoSign => panic!("Shouldn't happen; BigInts which store zero should convert to inline."), | ||||
|                     Sign::Plus => isize::try_from(slice.len()).unwrap() | ||||
|                 }; | ||||
|                 SmallInt::Heap((slice.as_mut_ptr(), size)) } | ||||
|                 Self(SmallIntType::Heap((slice.as_mut_ptr(), size))) } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -155,9 +251,9 @@ impl From<BigInt> for SmallInt { | ||||
| #[cfg(feature="num-bigint")] | ||||
| impl From<SmallInt> for BigInt { | ||||
|     fn from(s: SmallInt) -> Self { | ||||
|         match s { | ||||
|             SmallInt::Inline(i) => Self::from(i), | ||||
|             SmallInt::Heap((r, s)) => { | ||||
|         match s.0 { | ||||
|             SmallIntType::Inline(i) => Self::from(i), | ||||
|             SmallIntType::Heap((r, s)) => { | ||||
|                 let size = usize::try_from(s.abs()).unwrap(); | ||||
|                 let sign = s.signum(); | ||||
|                 let slice = unsafe { core::slice::from_raw_parts(r, size) }; | ||||
| @ -174,6 +270,35 @@ impl From<SmallInt> for BigInt { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature="num-bigint")] | ||||
| impl From<BigUint> for SmallUint { | ||||
|     fn from(b: BigUint) -> Self { | ||||
|         match (&b).try_into() { | ||||
|             Ok(i) => Self(SmallUintType::Inline(i)), | ||||
|             Err(_) => { | ||||
|                 let vec = b.to_u32_digits(); | ||||
|                 let mut slice = ManuallyDrop::new(vec.into_boxed_slice()); | ||||
|                 let size = slice.len(); | ||||
|                 Self(SmallUintType::Heap((slice.as_mut_ptr(), size))) } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[cfg(feature="num-bigint")] | ||||
| impl From<SmallUint> for BigUint { | ||||
|     fn from(s: SmallUint) -> Self { | ||||
|         match s.0 { | ||||
|             SmallUintType::Inline(i) => Self::from(i), | ||||
|             SmallUintType::Heap((r, s)) => { | ||||
|                 let slice = unsafe { core::slice::from_raw_parts(r, s) }; | ||||
| 
 | ||||
|                 BigUint::new(slice.to_vec()) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod conversion_tests { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user