Compare commits

..

28 Commits

Author SHA1 Message Date
Solomon Ucko 5bea89295d improve ops.rs, rename BigUint::from_smallint_unsigned to SmallInt::unsigned_abs, etc. 2022-11-18 00:24:13 -05:00
Solomon Ucko c392ba8633 stuff 2022-11-17 23:03:42 -05:00
Solomon Ucko 234fce4b92 improve test coverage 2022-08-14 23:53:30 -04:00
Solomon Ucko 81739a1311 fix SmallUint::partial_cmp 2022-08-14 16:49:42 -04:00
Solomon Ucko 2e081c03c5 add #[cfg(feature = "num-bigint")] to some test helper functions 2022-08-14 15:44:16 -04:00
Solomon Ucko 7702b67f07 impl BitAnd for BigUint, add lots of tests 2022-08-14 15:08:28 -04:00
Solomon Ucko 70bc33217c use unsigned_abs 2022-08-10 23:10:32 -04:00
Solomon Ucko 1b4407ab45 make heap_heap_return_* compatible with BigInt 2022-08-10 21:27:09 -04:00
Solomon Ucko b04ccea008 parameterize references to u128 2022-08-10 21:04:19 -04:00
Solomon Ucko f890aab454 improve some variable names 2022-08-10 20:56:30 -04:00
Solomon Ucko 586a0f427e fix -SmallInt::from(i128::MIN) 2022-08-10 00:16:26 -04:00
Solomon Ucko 3cd8536296 fix hard-coded references to SmallUint 2022-08-09 23:53:15 -04:00
Solomon Ucko 96f7b1a5ef eliminate free function 2022-08-09 23:45:26 -04:00
Solomon Ucko 06ce35aa69 refactor macro structure 2022-08-09 23:42:27 -04:00
Solomon Ucko 8cf2d6b870 use function names instead of punctuation 2022-08-09 22:15:45 -04:00
Solomon Ucko ab76eb30f5 refactor some more 2022-08-09 22:13:10 -04:00
Solomon Ucko 570559ae27 fix some bugs 2022-08-09 21:51:42 -04:00
Solomon Ucko 45a3975d31 refactor logic.rs and optimize ...Assign impls (&* instead of clone) 2022-08-09 21:10:23 -04:00
Solomon Ucko 1fe105f58c stub implementation of Div and DivAssign for SmallInt and SmallUint 2022-08-09 20:43:15 -04:00
emh 51f1c7d38a cleaning up code 2022-08-08 21:35:08 -04:00
emh 2dc3f2472f 0.2.2 2022-08-08 00:23:27 -04:00
emh ef013a5b16 final formatting: 0.2.2 - todo: signed logic, assign ops, shifts, divrem, display 2022-08-08 00:22:57 -04:00
emh f9eb2a1afa all basic arith ops done (we don't talk about div) 2022-08-07 18:35:36 -04:00
emh 2e04862fc1 fixed clone + ord + eq, need to fix signed add 2022-08-07 18:15:59 -04:00
emh df10924284 signed stuff - todo: test partialord / ord / add for SmallInt 2022-08-07 14:05:19 -04:00
emh cf9c8b0b78 fmt 2022-08-06 16:40:19 -04:00
emh 64ad3189bf Merge branch 'ops' into 'master'
Basic operations for smalluint

See merge request artofrev/smallint!1
2022-08-06 20:39:04 +00:00
emh 85babc5e11 basic logic for smalluint 2022-08-06 16:38:22 -04:00
10 changed files with 1319 additions and 193 deletions
+5 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "smallint" name = "smallint"
version = "0.2.1" version = "0.2.2"
edition = "2021" edition = "2021"
authors = ["artofrev"] authors = ["artofrev"]
description = "A library for optimized arbitrary precision integers." description = "A library for optimized arbitrary precision integers."
@@ -16,3 +16,7 @@ num-bigint = { version = "0.4.3", optional = true }
[dev-dependencies] [dev-dependencies]
num-bigint = { version = "0.4.3" } num-bigint = { version = "0.4.3" }
[profile.test]
opt-level = 2
+1 -3
View File
@@ -37,7 +37,7 @@ impl From<&SmallInt> for BigInt {
match s.0 { match s.0 {
SmallIntType::Inline(i) => Self::from(i), SmallIntType::Inline(i) => Self::from(i),
SmallIntType::Heap((r, s)) => { SmallIntType::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap(); let size = s.unsigned_abs();
let sign = s.signum(); let sign = s.signum();
let slice = unsafe { core::slice::from_raw_parts(r, size) }; let slice = unsafe { core::slice::from_raw_parts(r, size) };
let bs = match sign { let bs = match sign {
@@ -79,5 +79,3 @@ impl From<&SmallUint> for BigUint {
} }
} }
} }
+62 -12
View File
@@ -1,7 +1,7 @@
use crate::SmallInt;
use crate::SmallUint;
use crate::SmallIntError;
use crate::smallint::{SmallIntType, SmallUintType}; use crate::smallint::{SmallIntType, SmallUintType};
use crate::SmallInt;
use crate::SmallIntError;
use crate::SmallUint;
use core::mem::ManuallyDrop; use core::mem::ManuallyDrop;
macro_rules! int_impl { macro_rules! int_impl {
@@ -98,10 +98,10 @@ impl From<u128> for SmallInt {
} }
} }
impl TryFrom<SmallInt> for u128 { impl TryFrom<&SmallInt> for u128 {
type Error = SmallIntError; type Error = SmallIntError;
fn try_from(s: SmallInt) -> Result<Self, Self::Error> { fn try_from(s: &SmallInt) -> Result<Self, Self::Error> {
match s.0 { match s.0 {
SmallIntType::Inline(i) => { SmallIntType::Inline(i) => {
u128::try_from(i).map_err(|_| SmallIntError::ConversionError) u128::try_from(i).map_err(|_| SmallIntError::ConversionError)
@@ -109,7 +109,7 @@ impl TryFrom<SmallInt> for u128 {
SmallIntType::Heap((r, s)) => { SmallIntType::Heap((r, s)) => {
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 = s.unsigned_abs();
let slice = unsafe { core::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 {
@@ -125,12 +125,49 @@ impl TryFrom<SmallInt> for u128 {
} }
} }
impl TryFrom<SmallInt> for u128 {
type Error = SmallIntError;
fn try_from(value: SmallInt) -> Result<Self, Self::Error> {
Self::try_from(&value)
}
}
impl From<SmallUint> for SmallInt { impl From<SmallUint> for SmallInt {
fn from(s: SmallUint) -> Self { fn from(s: SmallUint) -> Self {
match s.0 { match s.0 {
SmallUintType::Inline(i) => SmallInt::from(i), SmallUintType::Inline(i) => SmallInt::from(i),
SmallUintType::Heap((r, s)) => { SmallUintType::Heap((r, s)) => {
SmallInt(SmallIntType::Heap((r, isize::try_from(s).unwrap()))) let slice = unsafe { core::slice::from_raw_parts(r, s) };
let mut ret = vec![0; s];
ret.clone_from_slice(slice);
let mut val = ManuallyDrop::new(ret.into_boxed_slice());
SmallInt(SmallIntType::Heap((
val.as_mut_ptr(),
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 {
let slice = unsafe { core::slice::from_raw_parts(r, size) };
let mut ret = vec![0; size];
ret.clone_from_slice(slice);
let mut val = ManuallyDrop::new(ret.into_boxed_slice());
Ok(Self(SmallUintType::Heap((val.as_mut_ptr(), size))))
} else {
Ok(Self(SmallUintType::Inline(u128::try_from(value)?)))
}
} }
} }
} }
@@ -140,14 +177,27 @@ impl TryFrom<SmallInt> for SmallUint {
type Error = SmallIntError; type Error = SmallIntError;
fn try_from(value: SmallInt) -> Result<Self, Self::Error> { fn try_from(value: SmallInt) -> Result<Self, Self::Error> {
match value.0 { Self::try_from(&value)
SmallIntType::Inline(i) => Self::try_from(i), }
}
impl SmallInt {
/// Returns the absolute value of the `SmallInt` as a `SmallUint`.
pub fn unsigned_abs(&self) -> SmallUint {
match self.0 {
SmallIntType::Inline(i) => SmallUint::from(i.unsigned_abs()),
SmallIntType::Heap((r, s)) => { SmallIntType::Heap((r, s)) => {
let size = usize::try_from(s).map_err(|_| SmallIntError::ConversionError)?; let size = s.unsigned_abs();
if size > 4 { if size > 4 {
Ok(Self(SmallUintType::Heap((r, size)))) let slice = unsafe { core::slice::from_raw_parts(r, size) };
let mut ret = vec![0; size];
ret.clone_from_slice(slice);
let mut val = ManuallyDrop::new(ret.into_boxed_slice());
SmallUint(SmallUintType::Heap((val.as_mut_ptr(), size)))
} else if s >= 0 {
SmallUint(SmallUintType::Inline(u128::try_from(self).unwrap()))
} else { } else {
Ok(Self(SmallUintType::Inline(u128::try_from(value)?))) SmallUint(SmallUintType::Inline(u128::try_from(-self).unwrap()))
} }
} }
} }
+3
View File
@@ -19,6 +19,9 @@ mod error;
pub use error::SmallIntError; pub use error::SmallIntError;
mod convert; mod convert;
mod ord;
mod logic;
mod ops; mod ops;
mod bigint; mod bigint;
+437
View File
@@ -0,0 +1,437 @@
use crate::ops::{add_two_slices, sub_two_slices};
use crate::smallint::{SmallIntType, SmallUintType};
use crate::{SmallInt, SmallUint};
use core::cmp::Ordering;
use core::mem::ManuallyDrop;
use core::ops::{BitAnd, BitOr, BitXor};
use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign};
macro_rules! logic_op {
(
$imp:ident, $imp_assign:ident, $typ:ident, $typ_inner:ident, $fun:ident, $fun_assign:ident;
$i:ident, $j:ident, $p:ident, $q:ident, $s:ident, $t:ident;
$inline_heap:tt, $heap_heap:tt
) => {
impl<'a, 'b> $imp<&'a $typ> for &'b $typ {
type Output = $typ;
fn $fun(self, rhs: &$typ) -> Self::Output {
match (&self.0, &rhs.0) {
(&$typ_inner::Inline($i), &$typ_inner::Inline($j)) => {
$typ($typ_inner::Inline($i.$fun($j)))
}
(&$typ_inner::Inline($i), &$typ_inner::Heap(($p, $s)))
| (&$typ_inner::Heap(($p, $s)), &$typ_inner::Inline($i)) => {
$inline_heap
}
(&$typ_inner::Heap(($p, $s)), &$typ_inner::Heap(($q, $t))) => {
$heap_heap
}
}
}
}
impl<'a> $imp<$typ> for &'a $typ {
type Output = $typ;
fn $fun(self, rhs: $typ) -> Self::Output {
self.$fun(&rhs)
}
}
impl<'a> $imp<&'a $typ> for $typ {
type Output = $typ;
fn $fun(self, rhs: &$typ) -> Self::Output {
(&self).$fun(rhs)
}
}
impl $imp<$typ> for $typ {
type Output = $typ;
fn $fun(self, rhs: $typ) -> Self::Output {
(&self).$fun(&rhs)
}
}
impl<'a> $imp_assign<&'a $typ> for $typ {
fn $fun_assign(&mut self, rhs: &'a $typ) {
*self = (&*self).$fun(rhs);
}
}
impl $imp_assign<$typ> for $typ {
fn $fun_assign(&mut self, rhs: $typ) {
*self = (&*self).$fun(rhs);
}
}
};
(
$imp:ident, $imp_assign:ident, $typ:ident, $typ_inner:ident, $fun:ident, $fun_assign:ident;
$i:ident, $j:ident, $p:ident, $q:ident, $s:ident, $t:ident, $slice:ident, $slice1:ident, $slice2:ident, $min:ident, $res:ident;
$inline_heap_inner:tt, $heap_heap_create_res:tt, $heap_heap_return:tt
) => {
logic_op! {
$imp, $imp_assign, $typ, $typ_inner, $fun, $fun_assign;
$i, $j, $p, $q, $s, $t;
{
let $slice = unsafe { core::slice::from_raw_parts($p, $s) };
$inline_heap_inner
},
{
let $slice1 = unsafe { core::slice::from_raw_parts($p, $s) };
let $slice2 = unsafe { core::slice::from_raw_parts($q, $t) };
let $min = std::cmp::min($slice1.len(), $slice2.len());
#[allow(unused_mut)]
let mut $res = $heap_heap_create_res;
$heap_heap_return
}
}
};
}
macro_rules! heap_to_inline {
($typ_inline:ident; $slice:ident) => {
let mut j = 0;
for i in 0..4 {
j <<= 32;
j |= $slice[3 - i] as $typ_inline;
}
j
}
}
macro_rules! inline_heap_to_inline {
($fun:ident, $typ:ident, $typ_inner:ident, $typ_inline:ident; $i:ident, $slice:ident) => {
let j = { heap_to_inline! { $typ_inline; $slice } };
$typ($typ_inner::Inline($i.$fun(j)))
}
}
macro_rules! inline_heap_to_heap {
($fun_assign:ident, $typ:ident, $typ_inner:ident; $i:ident, $slice:ident) => {
let mut retvec = $slice.to_vec();
let mut v = $i;
#[allow(clippy::needless_range_loop)]
for r in 0..4 {
retvec[r].$fun_assign(v as u32);
v >>= 32;
}
let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice());
$typ($typ_inner::Heap((retslice.as_mut_ptr(), retslice.len().try_into().unwrap())))
}
}
macro_rules! heap_heap_create_res_shortest {
($fun:ident; $slice1:ident, $slice2:ident, $min:ident) => {
let mut res = Vec::with_capacity($min);
for l in 0..$min {
res.push($slice1[l].$fun($slice2[l]));
}
res
}
}
macro_rules! heap_heap_create_res_longest {
($fun:ident; $slice1:ident, $slice2:ident, $min:ident) => {
let mut res = if $slice1.len() > $slice2.len() {
$slice1.to_vec()
} else {
$slice2.to_vec()
};
for l in 0..$min {
res[l] = $slice1[l].$fun($slice2[l]);
}
res
}
}
macro_rules! return_heap_inner {
($typ:ident, $typ_inner:ident; $res:ident) => {
let mut slice = ManuallyDrop::new($res);
$typ($typ_inner::Heap((slice.as_mut_ptr(), slice.len().try_into().unwrap())))
}
}
macro_rules! return_heap_inner_neg {
($typ:ident, $typ_inner:ident; $res:ident) => {
let mut slice = ManuallyDrop::new($res);
$typ($typ_inner::Heap((slice.as_mut_ptr(), -isize::try_from(slice.len()).unwrap())))
}
}
macro_rules! return_heap {
($typ:ident, $typ_inner:ident; $res:ident) => {
let res = $res.into_boxed_slice();
return_heap_inner! { $typ, $typ_inner; res }
}
}
macro_rules! return_heap_neg {
($typ:ident, $typ_inner:ident; $res:ident) => {
let res = $res.into_boxed_slice();
return_heap_inner_neg! { $typ, $typ_inner; res }
}
}
macro_rules! heap_heap_return_any {
($typ:ident, $typ_inner:ident, $typ_inline:ident; $res:ident) => {
while $res.len() != 1 && $res[$res.len() - 1] == 0 {
$res.pop();
}
if $res.len() <= 4 {
let mut r = 0;
for t in 0..$res.len() {
r <<= 32;
r |= $res[$res.len() - 1 - t] as $typ_inline;
}
$typ($typ_inner::Inline(r))
} else {
let mut slice = ManuallyDrop::new($res.into_boxed_slice());
$typ($typ_inner::Heap((slice.as_mut_ptr(), slice.len().try_into().unwrap())))
}
}
}
logic_op! {
BitAnd, BitAndAssign, SmallUint, SmallUintType, bitand, bitand_assign;
i, j, p, q, s, t, slice, slice1, slice2, min, res;
{ inline_heap_to_inline! { bitand, SmallUint, SmallUintType, u128; i, slice } },
{ heap_heap_create_res_shortest! { bitand; slice1, slice2, min } },
{ heap_heap_return_any! { SmallUint, SmallUintType, u128; res } }
}
logic_op! {
BitOr, BitOrAssign, SmallUint, SmallUintType, bitor, bitor_assign;
i, j, p, q, s, t, slice, slice1, slice2, min, res;
{ inline_heap_to_heap! { bitor_assign, SmallUint, SmallUintType; i, slice } },
{ heap_heap_create_res_longest! { bitor; slice1, slice2, min }},
{ return_heap! { SmallUint, SmallUintType; res } }
}
logic_op! {
BitXor, BitXorAssign, SmallUint, SmallUintType, bitxor, bitxor_assign;
i, j, p, q, s, t, slice, slice1, slice2, min, res;
{ inline_heap_to_heap! { bitxor_assign, SmallUint, SmallUintType; i, slice } },
{ heap_heap_create_res_longest! { bitxor; slice1, slice2, min }},
{ heap_heap_return_any! { SmallUint, SmallUintType, u128; res } }
}
fn bitor_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let mut result = if slice1.len() > slice2.len() {
slice1.to_vec()
} else {
slice2.to_vec()
};
for l in 0..std::cmp::min(slice1.len(), slice2.len()) {
result[l] = slice1[l] | slice2[l];
}
result
}
fn bitand_two_slices_mixed_sign(positive: &[u32], negative: &[u32]) -> Vec<u32> {
// a & (-b) = (a | (b - 1)) + 1 - b
// 0 is not negative, so we can ignore it
let sub1 = sub_two_slices(negative, &[1]);
let or = bitor_two_slices(positive, &sub1);
let add = add_two_slices(&or, &[1]);
let sub2 = sub_two_slices(&add, negative);
sub2
}
fn bitand_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let mut result = if slice1.len() > slice2.len() {
slice1.to_vec()
} else {
slice2.to_vec()
};
for l in 0..std::cmp::min(slice1.len(), slice2.len()) {
result[l] = slice1[l] | slice2[l];
}
result
}
fn bitor_two_slices_mixed_sign(positive: &[u32], negative: &[u32]) -> Vec<u32> {
// a | (-b) = (a & (b - 1)) + 1 - b
// 0 is not negative, so we can ignore it
let sub1 = sub_two_slices(negative, &[1]);
let or = bitand_two_slices(positive, &sub1);
let add = add_two_slices(&or, &[1]);
let sub2 = sub_two_slices(&add, negative);
sub2
}
logic_op! {
BitAnd, BitAndAssign, SmallInt, SmallIntType, bitand, bitand_assign;
i, j, p, q, s, t;
{
let slice = unsafe { core::slice::from_raw_parts(p, s.unsigned_abs()) };
match (i.cmp(&0), s.cmp(&0)) {
(Ordering::Equal, _) => SmallInt(SmallIntType::Inline(0)),
(Ordering::Greater, Ordering::Greater) => {
let j = { heap_to_inline! { i128; slice } };
SmallInt(SmallIntType::Inline(i & j))
},
(Ordering::Greater, Ordering::Less) => {
let j = { heap_to_inline! { i128; slice } };
SmallInt(SmallIntType::Inline(i & -j))
},
(Ordering::Less, Ordering::Greater) => {
let mut res = <Box<[u32]>>::from(slice);
let mut inline = i;
for idx in 0..4 {
res[idx] &= inline as u32;
inline >>= 32;
}
return_heap_inner! { SmallInt, SmallIntType; res }
},
(Ordering::Less, Ordering::Less) => {
let mut res = <Box<[u32]>>::from(slice);
let j = { heap_to_inline! { i128; slice } };
let lo = (i & j.wrapping_neg()).wrapping_neg();
let mut lo_remaining = lo;
for idx in 0..4 {
res[idx] = lo_remaining as u32;
lo_remaining >>= 32;
}
if lo == 0 && j != 0 {
let res2 = add_two_slices(&res, &[0, 0, 0, 0, 1]);
return_heap_neg! { SmallInt, SmallIntType; res2 }
} else {
return_heap_inner_neg! { SmallInt, SmallIntType; res }
}
},
(_, Ordering::Equal) => unreachable!("0 must be inline"),
}
},
{
let slice1 = unsafe { core::slice::from_raw_parts(p, s.unsigned_abs()) };
let slice2 = unsafe { core::slice::from_raw_parts(q, t.unsigned_abs()) };
match (s.cmp(&0), t.cmp(&0)) {
(Ordering::Greater, Ordering::Greater) => {
let min = std::cmp::min(slice1.len(), slice2.len());
#[allow(unused_mut)]
let mut res = { heap_heap_create_res_shortest! { bitand; slice1, slice2, min } };
// TODO: shrink if needed, sometimes to Inline
return_heap! { SmallInt, SmallIntType; res }
},
(Ordering::Greater, Ordering::Less) => {
let res = bitand_two_slices_mixed_sign(slice1, slice2);
return_heap! { SmallInt, SmallIntType; res }
},
(Ordering::Less, Ordering::Greater) => {
let res = bitand_two_slices_mixed_sign(slice2, slice1);
return_heap! { SmallInt, SmallIntType; res }
},
(Ordering::Less, Ordering::Less) => {
// (-a) & (-b) = -(((a-1) | (b-1)) + 1)
// 0 is not negative, so we can ignore it
let sub1 = sub_two_slices(slice1, &[1]);
let sub2 = sub_two_slices(slice2, &[1]);
let tmp = bitor_two_slices(&sub1, &sub2);
let res = add_two_slices(&tmp, &[1]);
return_heap_neg! { SmallInt, SmallIntType; res }
},
(Ordering::Equal, _) | (_, Ordering::Equal) => unreachable!("0 must be inline"),
}
}
}
// logic_op! {
// BitOr, BitOrAssign, SmallInt, SmallIntType, bitor, bitor_assign;
// i, j, p, q, s, t;
// {
// let slice = unsafe { core::slice::from_raw_parts(p, s.unsigned_abs()) };
// match (i.cmp(&0), s.cmp(&0)) {
// (Ordering::Equal, _) => {
// let mut slice = ManuallyDrop::new(<Box<[_]>>::from(slice));
// SmallInt(SmallIntType::Heap((slice.as_mut_ptr(), s)))
// },
// (Ordering::Greater, Ordering::Greater) => {
// inline_heap_to_heap! { bitor_assign, SmallInt, SmallIntType; i, slice }
// },
// (Ordering::Greater, Ordering::Less) => {
// let mut res = <Box<[u32]>>::from(slice);
// let mut inline = i as u128;
// for idx in 0..4 {
// res[idx] = ((res[idx] as i32).wrapping_neg() | (inline as i32).wrapping_neg()).wrapping_neg() as u32;
// inline >>= 32;
// }
// return_heap_inner_neg! { SmallInt, SmallIntType; res }
// },
// (Ordering::Less, Ordering::Greater) => {
// let j = { heap_to_inline! { i128; slice } };
// SmallInt(SmallIntType::Inline(i | -j))
// },
// (Ordering::Less, Ordering::Less) => {
// let mut res = <Box<[u32]>>::from(slice);
// let j = { heap_to_inline! { i128; slice } };
// let lo = (i | j.wrapping_neg()).wrapping_neg();
// let mut lo_remaining = lo;
// for idx in 0..4 {
// res[idx] = lo_remaining as u32;
// lo_remaining >>= 32;
// }
//
// if lo == 0 && j != 0 {
// let res2 = add_two_slices(&res, &[0, 0, 0, 0, 1]);
// return_heap_neg! { SmallInt, SmallIntType; res2 }
// } else {
// return_heap_inner_neg! { SmallInt, SmallIntType; res }
// }
// },
// (_, Ordering::Equal) => unreachable!("0 must be inline"),
// }
// },
// {
// let slice1 = unsafe { core::slice::from_raw_parts(p, s.unsigned_abs()) };
// let slice2 = unsafe { core::slice::from_raw_parts(q, t.unsigned_abs()) };
// match (s.cmp(&0), t.cmp(&0)) {
// (Ordering::Greater, Ordering::Greater) => {
// let min = std::cmp::min(slice1.len(), slice2.len());
//
// #[allow(unused_mut)]
// let mut res = { heap_heap_create_res_longest! { bitor; slice1, slice2, min } };
//
// return_heap! { SmallInt, SmallIntType; res }
// },
// (Ordering::Greater, Ordering::Less) => {
// let res = bitor_two_slices_mixed_sign(slice1, slice2);
// return_heap! { SmallInt, SmallIntType; res }
// },
// (Ordering::Less, Ordering::Greater) => {
// let res = bitor_two_slices_mixed_sign(slice2, slice1);
// return_heap! { SmallInt, SmallIntType; res }
// },
// (Ordering::Less, Ordering::Less) => {
// // (-a) | (-b) = -(((a-1) & (b-1)) + 1)
// // 0 is not negative, so we can ignore it
// let sub1 = sub_two_slices(slice1, &[1]);
// let sub2 = sub_two_slices(slice2, &[1]);
// let tmp = bitand_two_slices(&sub1, &sub2);
// let res = add_two_slices(&tmp, &[1]);
// return_heap_neg! { SmallInt, SmallIntType; res }
// },
// (Ordering::Equal, _) | (_, Ordering::Equal) => unreachable!("0 must be inline"),
// }
// }
// }
+273 -88
View File
@@ -1,57 +1,80 @@
use crate::SmallUint; use crate::smallint::{SmallIntType, SmallUintType};
use crate::smallint::SmallUintType; use crate::{SmallInt, SmallUint};
use core::ops::{Add, Sub, Mul};
use core::mem::ManuallyDrop; use core::mem::ManuallyDrop;
use core::ops::{Add, Div, Mul, Neg, Sub};
use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
macro_rules! basic_op { impl Neg for &SmallInt {
($imp:ident, $typ:ty, $fun:ident) => { type Output = SmallInt;
impl<'a, 'b> $imp<&'a $typ> for &'b $typ { fn neg(self) -> SmallInt {
match self.0 {
type Output = $typ; SmallIntType::Inline(i) => {
if let Some(n) = i.checked_neg() {
fn $fun(self, rhs: &$typ) -> Self::Output { SmallInt(SmallIntType::Inline(n))
$fun(self, rhs) } else {
// -i128::MIN = i128::MAX + 1 = 0x8000...
let mut val = ManuallyDrop::new(Box::new([0, 0, 0, 0x80_00_00_00]));
SmallInt(SmallIntType::Heap((val.as_mut_ptr(), 4)))
}
},
SmallIntType::Heap((r, s)) => {
let size = s.unsigned_abs();
let slice = unsafe { core::slice::from_raw_parts(r, size) };
let mut ret = vec![0; size];
ret.clone_from_slice(slice);
let mut val = ManuallyDrop::new(ret.into_boxed_slice());
SmallInt(SmallIntType::Heap((val.as_mut_ptr(), -s)))
}
}
}
} }
impl Neg for SmallInt {
type Output = SmallInt;
fn neg(self) -> SmallInt {
(&self).neg()
}
}
macro_rules! basic_op {
($imp:ident, $lower:ident, $typ:ty, $fun:ident) => {
impl<'a, 'b> $imp<&'a $typ> for &'b $typ {
type Output = $typ;
fn $lower(self, rhs: &$typ) -> Self::Output {
$fun(self, rhs)
}
} }
impl<'a> $imp<$typ> for &'a $typ { impl<'a> $imp<$typ> for &'a $typ {
type Output = $typ; type Output = $typ;
fn $fun(self, rhs: $typ) -> Self::Output { fn $lower(self, rhs: $typ) -> Self::Output {
self.$fun(&rhs) self.$lower(&rhs)
} }
} }
impl<'a> $imp<&'a $typ> for $typ { impl<'a> $imp<&'a $typ> for $typ {
type Output = $typ; type Output = $typ;
fn $fun(self, rhs: &$typ) -> Self::Output { fn $lower(self, rhs: &$typ) -> Self::Output {
(&self).$fun(rhs) (&self).$lower(rhs)
} }
} }
impl $imp<$typ> for $typ { impl $imp<$typ> for $typ {
type Output = $typ; type Output = $typ;
fn $fun(self, rhs: $typ) -> Self::Output { fn $lower(self, rhs: $typ) -> Self::Output {
(&self).$fun(&rhs) (&self).$lower(&rhs)
}
} }
} }
};
} }
pub(crate) fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let s = slice1.len(); let s = slice1.len();
let j = slice2.len(); let j = slice2.len();
@@ -60,24 +83,14 @@ fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let mut carry = false; let mut carry = false;
for t in 0..larger { for t in 0..larger {
let value1 = if t < s { slice1[t] } else { 0 };
let value1 = if t < s { let value2 = if t < j { slice2[t] } else { 0 };
slice1[t]
} else {
0
};
let value2 = if t < j {
slice2[t]
} else {
0
};
let (val, overflow) = value1.overflowing_add(value2); let (val, overflow) = value1.overflowing_add(value2);
let (cval, coverflow) = val.overflowing_add(carry as u32); let (cval, coverflow) = val.overflowing_add(carry as u32);
res.push(cval); res.push(cval);
carry = overflow | coverflow; carry = overflow | coverflow;
} }
if carry { if carry {
@@ -89,12 +102,9 @@ fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
res res
} }
fn add(a: &SmallUint, b: &SmallUint) -> SmallUint { fn add(a: &SmallUint, b: &SmallUint) -> SmallUint {
match (&a.0, &b.0) { match (&a.0, &b.0) {
(&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => match i.overflowing_add(j) {
match i.overflowing_add(j) {
(t, false) => SmallUint(SmallUintType::Inline(t)), (t, false) => SmallUint(SmallUintType::Inline(t)),
(t, true) => { (t, true) => {
let mut res = [0, 0, 0, 0, 1]; let mut res = [0, 0, 0, 0, 1];
@@ -110,11 +120,10 @@ fn add(a: &SmallUint, b: &SmallUint) -> SmallUint {
let mut slice = ManuallyDrop::new(<Box<[u32]>>::from(res)); let mut slice = ManuallyDrop::new(<Box<[u32]>>::from(res));
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), 5))) SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), 5)))
}
} }
}, },
(&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) | (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => { (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i))
| (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
let mut res = [0, 0, 0, 0]; let mut res = [0, 0, 0, 0];
@@ -133,11 +142,8 @@ fn add(a: &SmallUint, b: &SmallUint) -> SmallUint {
let mut slice = ManuallyDrop::new(result.into_boxed_slice()); let mut slice = ManuallyDrop::new(result.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size)))
}
},
(&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; let slice2 = unsafe { core::slice::from_raw_parts(i, j) };
@@ -147,14 +153,87 @@ fn add(a: &SmallUint, b: &SmallUint) -> SmallUint {
let mut slice = ManuallyDrop::new(res.into_boxed_slice()); let mut slice = ManuallyDrop::new(res.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size)))
} }
} }
} }
basic_op!(Add, SmallUint, add); basic_op!(Add, add, SmallUint, add);
fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> { impl<'a> AddAssign<&'a SmallUint> for SmallUint {
fn add_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() + rhs;
}
}
impl AddAssign<SmallUint> for SmallUint {
fn add_assign(&mut self, rhs: SmallUint) {
*self = self.clone() + rhs;
}
}
fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
let a_sign;
match &a.0 {
SmallIntType::Inline(i) => a_sign = i.signum() as i8,
SmallIntType::Heap((_, s)) => a_sign = s.signum() as i8,
}
let b_sign;
match &b.0 {
SmallIntType::Inline(i) => b_sign = i.signum() as i8,
SmallIntType::Heap((_, s)) => b_sign = s.signum() as i8,
}
match (a_sign, b_sign) {
x if (x.0 >= 0 && x.1 >= 0) => SmallInt::from(
a.unsigned_abs()
+ b.unsigned_abs(),
),
x if (x.0 < 0 && x.1 < 0) => -SmallInt::from(
a.unsigned_abs()
+ b.unsigned_abs(),
),
x if (x.0 >= 0 && x.1 < 0) => {
let s = a.unsigned_abs();
let b = b.unsigned_abs();
if b <= s {
SmallInt::from(s - b)
} else {
-SmallInt::from(b - s)
}
}
x if (x.0 < 0 && x.1 >= 0) => {
let s = a.unsigned_abs();
let b = b.unsigned_abs();
if s <= b {
SmallInt::from(b - s)
} else {
-SmallInt::from(s - b)
}
}
(_, _) => {
panic!("This shouldn't happen. ");
}
}
}
basic_op!(Add, add, SmallInt, add_signed);
impl<'a> AddAssign<&'a SmallInt> for SmallInt {
fn add_assign(&mut self, rhs: &'a SmallInt) {
*self = self.clone() + rhs;
}
}
impl AddAssign<SmallInt> for SmallInt {
fn add_assign(&mut self, rhs: SmallInt) {
*self = self.clone() + rhs;
}
}
pub(crate) fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let b = slice1.len(); let b = slice1.len();
let s = slice2.len(); let s = slice2.len();
@@ -168,11 +247,7 @@ fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
for i in 0..b { for i in 0..b {
let mut value1 = slice1[i]; let mut value1 = slice1[i];
let value2 = if i < s { let value2 = if i < s { slice2[i] } else { 0 };
slice2[i]
} else {
0
};
if borrow { if borrow {
let (temp, b) = value1.overflowing_sub(1); let (temp, b) = value1.overflowing_sub(1);
@@ -186,7 +261,6 @@ fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let val = value1.wrapping_sub(value2); let val = value1.wrapping_sub(value2);
res.push(val); res.push(val);
} }
if borrow { if borrow {
@@ -194,11 +268,9 @@ fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
} }
res res
} }
fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint { fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint {
match (&a.0, &b.0) { match (&a.0, &b.0) {
(&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
if let (t, false) = i.overflowing_sub(j) { if let (t, false) = i.overflowing_sub(j) {
@@ -206,7 +278,7 @@ fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint {
} else { } else {
panic!("First number is smaller than second. "); panic!("First number is smaller than second. ");
} }
}, }
(&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => { (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
@@ -226,15 +298,11 @@ fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint {
let mut slice = ManuallyDrop::new(result.into_boxed_slice()); let mut slice = ManuallyDrop::new(result.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size)))
}
},
(&SmallUintType::Inline(_), &SmallUintType::Heap((_, _))) => { (&SmallUintType::Inline(_), &SmallUintType::Heap((_, _))) => {
panic!("First number is smaller than second. "); panic!("First number is smaller than second. ");
}
},
(&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; let slice2 = unsafe { core::slice::from_raw_parts(i, j) };
@@ -244,12 +312,41 @@ fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint {
let mut slice = ManuallyDrop::new(res.into_boxed_slice()); let mut slice = ManuallyDrop::new(res.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size)))
} }
} }
} }
basic_op!(Sub, SmallUint, sub); basic_op!(Sub, sub, SmallUint, sub);
impl<'a> SubAssign<&'a SmallUint> for SmallUint {
fn sub_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() - rhs;
}
}
impl SubAssign<SmallUint> for SmallUint {
fn sub_assign(&mut self, rhs: SmallUint) {
*self = self.clone() - rhs;
}
}
fn sub_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
a + (-b.clone())
}
basic_op!(Sub, sub, SmallInt, sub_signed);
impl<'a> SubAssign<&'a SmallInt> for SmallInt {
fn sub_assign(&mut self, rhs: &'a SmallInt) {
*self = self.clone() - rhs;
}
}
impl SubAssign<SmallInt> for SmallInt {
fn sub_assign(&mut self, rhs: SmallInt) {
*self = self.clone() - rhs;
}
}
// Taken from https://github.com/rust-lang/rust/issues/85532#issuecomment-916309635. Credit to // Taken from https://github.com/rust-lang/rust/issues/85532#issuecomment-916309635. Credit to
// AaronKutch. // AaronKutch.
@@ -288,13 +385,11 @@ const fn carrying_mul_u128(lhs: u128, rhs: u128, carry: u128) -> (u128, u128) {
} }
fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> { fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
// https://en.wikipedia.org/wiki/Karatsuba_algorithm // https://en.wikipedia.org/wiki/Karatsuba_algorithm
let l1 = slice1.len(); let l1 = slice1.len();
let l2 = slice2.len(); let l2 = slice2.len();
if l1 == 0 || l2 == 0 { if l1 == 0 || l2 == 0 {
return vec![]; return vec![];
} else if l1 == 1 { } else if l1 == 1 {
@@ -308,7 +403,6 @@ fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let m = r as u32; let m = r as u32;
overflow = (r >> 32) as u32; overflow = (r >> 32) as u32;
res.push(m); res.push(m);
} }
if overflow != 0 { if overflow != 0 {
@@ -317,7 +411,6 @@ fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
return res; return res;
} else if l2 == 1 { } else if l2 == 1 {
let mut overflow = 0; let mut overflow = 0;
let mut res: Vec<u32> = Vec::with_capacity(l2 + 1); let mut res: Vec<u32> = Vec::with_capacity(l2 + 1);
@@ -328,7 +421,6 @@ fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let m = r as u32; let m = r as u32;
overflow = (r >> 32) as u32; overflow = (r >> 32) as u32;
res.push(m); res.push(m);
} }
if overflow != 0 { if overflow != 0 {
@@ -356,8 +448,6 @@ fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
op0.reverse(); op0.reverse();
let mut op1 = sub_two_slices(&sub_two_slices(&z1, &z2), &z0); let mut op1 = sub_two_slices(&sub_two_slices(&z1, &z2), &z0);
op1.reverse(); op1.reverse();
@@ -367,10 +457,8 @@ fn mul_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
op1.reverse(); op1.reverse();
add_two_slices(&add_two_slices(&op0, &op1), &z0) add_two_slices(&add_two_slices(&op0, &op1), &z0)
} }
fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint { fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint {
match (&a.0, &b.0) { match (&a.0, &b.0) {
(&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
@@ -403,12 +491,12 @@ fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint {
let mut slice = ManuallyDrop::new(res.into_boxed_slice()); let mut slice = ManuallyDrop::new(res.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size)))
} }
} }
}, }
(&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) | (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => { (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i))
| (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
let mut res = [0, 0, 0, 0]; let mut res = [0, 0, 0, 0];
@@ -427,11 +515,9 @@ fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint {
let mut slice = ManuallyDrop::new(result.into_boxed_slice()); let mut slice = ManuallyDrop::new(result.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size)))
}
},
(&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; let slice2 = unsafe { core::slice::from_raw_parts(i, j) };
@@ -441,10 +527,109 @@ fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint {
let mut slice = ManuallyDrop::new(res.into_boxed_slice()); let mut slice = ManuallyDrop::new(res.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size))) SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), size)))
} }
} }
} }
basic_op!(Mul, SmallUint, mul); basic_op!(Mul, mul, SmallUint, mul);
impl<'a> MulAssign<&'a SmallUint> for SmallUint {
fn mul_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() * rhs;
}
}
impl MulAssign<SmallUint> for SmallUint {
fn mul_assign(&mut self, rhs: SmallUint) {
*self = self.clone() * rhs;
}
}
fn mul_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
let a_sign;
match &a.0 {
SmallIntType::Inline(i) => a_sign = i.signum() as i8,
SmallIntType::Heap((_, s)) => a_sign = s.signum() as i8,
}
let b_sign;
match &b.0 {
SmallIntType::Inline(i) => b_sign = i.signum() as i8,
SmallIntType::Heap((_, s)) => b_sign = s.signum() as i8,
}
match (a_sign, b_sign) {
x if (x.0 >= 0 && x.1 >= 0) => SmallInt::from(
a.unsigned_abs()
* b.unsigned_abs(),
),
x if (x.0 < 0 && x.1 < 0) => SmallInt::from(
a.unsigned_abs()
* b.unsigned_abs(),
),
x if (x.0 >= 0 && x.1 < 0) => -SmallInt::from(
a.unsigned_abs()
* b.unsigned_abs(),
),
x if (x.0 < 0 && x.1 >= 0) => -SmallInt::from(
a.unsigned_abs()
* b.unsigned_abs(),
),
(_, _) => {
panic!("This shouldn't happen. ");
}
}
}
basic_op!(Mul, mul, SmallInt, mul_signed);
impl<'a> MulAssign<&'a SmallInt> for SmallInt {
fn mul_assign(&mut self, rhs: &'a SmallInt) {
*self = self.clone() * rhs;
}
}
impl MulAssign<SmallInt> for SmallInt {
fn mul_assign(&mut self, rhs: SmallInt) {
*self = self.clone() * rhs;
}
}
fn div(_a: &SmallUint, _b: &SmallUint) -> SmallUint {
todo!()
}
basic_op!(Div, div, SmallUint, div);
impl<'a> DivAssign<&'a SmallUint> for SmallUint {
fn div_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() / rhs;
}
}
impl DivAssign<SmallUint> for SmallUint {
fn div_assign(&mut self, rhs: SmallUint) {
*self = self.clone() / rhs;
}
}
fn div_signed(_a: &SmallInt, _b: &SmallInt) -> SmallInt {
todo!()
}
basic_op!(Div, div, SmallInt, div_signed);
impl<'a> DivAssign<&'a SmallInt> for SmallInt {
fn div_assign(&mut self, rhs: &'a SmallInt) {
*self = self.clone() / rhs;
}
}
impl DivAssign<SmallInt> for SmallInt {
fn div_assign(&mut self, rhs: SmallInt) {
*self = self.clone() / rhs;
}
}
+96
View File
@@ -0,0 +1,96 @@
use crate::smallint::{SmallIntType, SmallUintType};
use crate::SmallInt;
use crate::SmallUint;
use std::cmp::Ordering;
impl PartialEq for SmallUint {
fn eq(&self, other: &SmallUint) -> bool {
match (&self.0, &other.0) {
(SmallUintType::Inline(i), SmallUintType::Inline(j)) => i == j,
(SmallUintType::Heap((p, s)), SmallUintType::Heap((q, t))) => {
let slice1 = unsafe { core::slice::from_raw_parts(*p, *s) };
let slice2 = unsafe { core::slice::from_raw_parts(*q, *t) };
slice1 == slice2
}
(_, _) => false,
}
}
}
impl Eq for SmallUint {}
impl PartialOrd for SmallUint {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SmallUint {
fn cmp(&self, other: &Self) -> Ordering {
match (&self.0, &other.0) {
(SmallUintType::Inline(i), SmallUintType::Inline(j)) => i.cmp(j),
(SmallUintType::Inline(_), SmallUintType::Heap((_, _))) => Ordering::Less,
(SmallUintType::Heap((_, _)), SmallUintType::Inline(_)) => Ordering::Greater,
(SmallUintType::Heap((p, s)), SmallUintType::Heap((q, t))) => match s.cmp(t) {
Ordering::Equal => {
let slice1 = unsafe { core::slice::from_raw_parts(*p, *s) };
let slice2 = unsafe { core::slice::from_raw_parts(*q, *t) };
for i in 0..*s {
match slice1[s - 1 - i].cmp(&slice2[s - 1 - i]) {
Ordering::Equal => {}
o => return o,
}
}
Ordering::Equal
}
o => o,
}
}
}
}
impl PartialEq for SmallInt {
fn eq(&self, other: &SmallInt) -> bool {
match (&self.0, &other.0) {
(SmallIntType::Inline(i), SmallIntType::Inline(j)) => i == j,
(SmallIntType::Heap((p, s)), SmallIntType::Heap((q, t))) => {
if s != t { // need to compare signs, at minimum
return false;
}
let slice1 = unsafe { core::slice::from_raw_parts(*p, s.unsigned_abs()) };
let slice2 = unsafe { core::slice::from_raw_parts(*q, t.unsigned_abs()) };
slice1 == slice2
}
(_, _) => false,
}
}
}
impl Eq for SmallInt {}
impl PartialOrd for SmallInt {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SmallInt {
fn cmp(&self, other: &Self) -> Ordering {
let a_sign = match &self.0 {
SmallIntType::Inline(i) => i.cmp(&0),
SmallIntType::Heap((_, s)) => s.cmp(&0),
};
let b_sign = match &other.0 {
SmallIntType::Inline(j) => j.cmp(&0),
SmallIntType::Heap((_, t)) => t.cmp(&0),
};
match a_sign.cmp(&b_sign) {
Ordering::Equal => match a_sign {
Ordering::Less => other.unsigned_abs().cmp(&self.unsigned_abs()),
Ordering::Equal => Ordering::Equal,
Ordering::Greater => self.unsigned_abs().cmp(&other.unsigned_abs()),
},
o => o,
}
}
}
+134 -5
View File
@@ -1,22 +1,151 @@
use crate::SmallInt; use crate::SmallInt;
use crate::SmallUint; use crate::SmallUint;
use crate::smallint::{SmallIntType, SmallUintType};
#[cfg(feature = "num-bigint")] #[cfg(feature = "num-bigint")]
use num_bigint::{BigInt, BigUint}; use num_bigint::{BigInt, BigUint};
#[cfg(feature = "num-bigint")]
impl core::fmt::Debug for SmallInt { impl core::fmt::Debug for SmallInt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", BigInt::from(self)) match self.0 {
SmallIntType::Inline(i) => {
write!(f, "{}", i)?;
}
SmallIntType::Heap((_r, _s)) => {
#[cfg(feature = "num-bigint")]
write!(f, "{}", BigInt::from(self))?;
#[cfg(not(feature = "num-bigint"))]
todo!();
}
}
Ok(())
} }
} }
#[cfg(feature = "num-bigint")]
impl core::fmt::Debug for SmallUint { impl core::fmt::Debug for SmallUint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", BigUint::from(self)) match self.0 {
SmallUintType::Inline(i) => {
write!(f, "{}", i)?;
}
SmallUintType::Heap((_r, _s)) => {
#[cfg(feature = "num-bigint")]
write!(f, "{}", BigUint::from(self))?;
#[cfg(not(feature = "num-bigint"))]
todo!();
}
}
Ok(())
} }
} }
impl core::fmt::Display for SmallInt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl core::fmt::Display for SmallUint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl core::fmt::UpperHex for SmallUint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
SmallUintType::Inline(i) => write!(f, "0x{:X}", i),
SmallUintType::Heap((r, s)) => {
let slice = unsafe { core::slice::from_raw_parts(r, s) };
let mut iter = slice.iter().rev();
if let Some(i) = iter.next() {
write!(f, "0x{:X}", i)?;
}
for i in iter {
write!(f, "{:08X}", i)?;
}
Ok(())
}
}
}
}
impl core::fmt::LowerHex for SmallUint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
SmallUintType::Inline(i) => write!(f, "0x{:x}", i),
SmallUintType::Heap((r, s)) => {
let slice = unsafe { core::slice::from_raw_parts(r, s) };
let mut iter = slice.iter().rev();
if let Some(i) = iter.next() {
write!(f, "0x{:x}", i)?;
}
for i in iter {
write!(f, "{:08x}", i)?;
}
Ok(())
}
}
}
}
impl core::fmt::UpperHex for SmallInt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
SmallIntType::Inline(i) => match i {
x if x >= 0 => write!(f, "0x{:X}", i),
x if x < 0 => write!(f, "-0x{:X}", -i),
_ => panic!("This should not happen."),
},
SmallIntType::Heap((r, s)) => {
let sign = match s.signum() {
x if x >= 0 => "",
x if x < 0 => "-",
_ => panic!("This should not happen."),
};
let slice = unsafe { core::slice::from_raw_parts(r, s.unsigned_abs()) };
let mut iter = slice.iter().rev();
if let Some(i) = iter.next() {
write!(f, "{}0x{:X}", sign, i)?;
}
for i in iter {
write!(f, "{:08X}", i)?;
}
Ok(())
}
}
}
}
impl core::fmt::LowerHex for SmallInt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
SmallIntType::Inline(i) => match i {
x if x >= 0 => write!(f, "0x{:x}", i),
x if x < 0 => write!(f, "-0x{:x}", -i),
_ => panic!("This should not happen."),
},
SmallIntType::Heap((r, s)) => {
let sign = match s.signum() {
x if x >= 0 => "",
x if x < 0 => "-",
_ => panic!("This should not happen."),
};
let slice = unsafe { core::slice::from_raw_parts(r, s.unsigned_abs()) };
let mut iter = slice.iter().rev();
if let Some(i) = iter.next() {
write!(f, "{}0x{:x}", sign, i)?;
}
for i in iter {
write!(f, "{:08x}", i)?;
}
Ok(())
}
}
}
}
+58 -6
View File
@@ -1,31 +1,28 @@
use core::hash::Hash;
use core::mem::ManuallyDrop;
/// An integer-like type that will store small integers up to `i128` inline. Larger integers are /// 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`. /// 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 SmallInt(pub(crate) SmallIntType); pub struct SmallInt(pub(crate) SmallIntType);
/// An integer-like type that will store small integers up to `u128` inline. Larger integers are /// 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`. /// 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(pub(crate) SmallUintType); pub struct SmallUint(pub(crate) SmallUintType);
#[derive(Clone, PartialEq, Eq)]
pub enum SmallIntType { pub enum SmallIntType {
Inline(i128), Inline(i128),
Heap((*mut u32, isize)), Heap((*mut u32, isize)),
} }
#[derive(Clone, PartialEq, Eq)]
pub enum SmallUintType { pub enum SmallUintType {
Inline(u128), Inline(u128),
Heap((*mut u32, usize)), Heap((*mut u32, usize)),
} }
impl Drop for SmallInt { impl Drop for SmallInt {
fn drop(&mut self) { fn drop(&mut self) {
if let Self(SmallIntType::Heap((r, s))) = self { if let Self(SmallIntType::Heap((r, s))) = self {
let size = usize::try_from(s.abs()).unwrap(); let size = s.unsigned_abs();
let slice = unsafe { core::slice::from_raw_parts_mut(*r, size) }; let slice = unsafe { core::slice::from_raw_parts_mut(*r, size) };
unsafe { std::mem::drop(Box::from_raw(slice)) } unsafe { std::mem::drop(Box::from_raw(slice)) }
} }
@@ -41,3 +38,58 @@ impl Drop for SmallUint {
} }
} }
impl Clone for SmallUint {
fn clone(&self) -> Self {
match self.0 {
SmallUintType::Inline(i) => Self(SmallUintType::Inline(i)),
SmallUintType::Heap((r, s)) => {
let slice = unsafe { core::slice::from_raw_parts(r, s) };
let mut ret = vec![0; s];
ret.clone_from_slice(slice);
let mut val = ManuallyDrop::new(ret.into_boxed_slice());
SmallUint(SmallUintType::Heap((val.as_mut_ptr(), s)))
}
}
}
}
impl Clone for SmallInt {
fn clone(&self) -> Self {
match self.0 {
SmallIntType::Inline(i) => Self(SmallIntType::Inline(i)),
SmallIntType::Heap((r, s)) => {
let size = s.unsigned_abs();
let slice = unsafe { core::slice::from_raw_parts(r, size) };
let mut ret = vec![0; size];
ret.clone_from_slice(slice);
let mut val = ManuallyDrop::new(ret.into_boxed_slice());
SmallInt(SmallIntType::Heap((val.as_mut_ptr(), s)))
}
}
}
}
impl Hash for SmallUint {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self.0 {
SmallUintType::Inline(i) => i.hash(state),
SmallUintType::Heap((r, s)) => {
let slice = unsafe { core::slice::from_raw_parts(r, s) };
slice.hash(state);
}
}
}
}
impl Hash for SmallInt {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self.0 {
SmallIntType::Inline(i) => i.hash(state),
SmallIntType::Heap((r, s)) => {
let size = s.unsigned_abs();
let slice = unsafe { core::slice::from_raw_parts(r, size) };
slice.hash(state);
}
}
}
}
+220 -48
View File
@@ -2,9 +2,10 @@
use crate::SmallInt; use crate::SmallInt;
use crate::SmallUint; use crate::SmallUint;
use core::fmt::Debug;
#[cfg(feature = "num-bigint")] #[cfg(feature = "num-bigint")]
use num_bigint::{BigInt, Sign, BigUint}; use num_bigint::{BigInt, BigUint, Sign};
macro_rules! conversion_tests { macro_rules! conversion_tests {
($t:ty, $i:ident) => { ($t:ty, $i:ident) => {
@@ -32,66 +33,237 @@ conversion_tests!(i64, test_i64);
conversion_tests!(u128, test_u128); conversion_tests!(u128, test_u128);
conversion_tests!(i128, test_i128); conversion_tests!(i128, test_i128);
#[test]
#[cfg(feature = "num-bigint")] #[cfg(feature = "num-bigint")]
fn test_op_add_u_u() { fn run_tests_u_inner(test: impl Fn(BigUint)) {
let i = SmallUint::from(u128::MAX); for i in 0u8..=7 {
let k = SmallUint::from(u128::MAX); test(BigUint::from(i));
let q = i + k; }
assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) + u128::MAX); for shift_scale in 1..=16 {
for shift_offset in -2..=2 {
let shift: i16 = (shift_scale * 32) + shift_offset;
test(BigUint::from(1u8) << shift);
for offset in 1u8..=7 {
test((BigUint::from(1u8) << shift) + BigUint::from(offset));
test((BigUint::from(1u8) << shift) - BigUint::from(offset));
}
}
}
test(BigUint::new(vec![3, 9, 8, 3, 1]));
test(BigUint::new(vec![5, 4, 9, 3, 1, 81]));
}
let i = SmallUint::from(u128::MAX); #[allow(dead_code)]
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); #[cfg(feature = "num-bigint")]
let q = i + k; fn run_tests_u_1<T: Eq + Debug>(small: impl Fn(SmallUint) -> T, big: impl Fn(&BigUint) -> T) {
assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) + u128::MAX); run_tests_u_inner(|i| {
let small_result = small(SmallUint::from(&i));
let big_result = big(&i);
assert_eq!(
small_result,
big_result,
"{:#x}", i
);
});
}
let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); #[cfg(feature = "num-bigint")]
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); fn run_tests_u_2<T: Eq + Debug>(
let q = i + k; small: impl Fn(SmallUint, SmallUint) -> T,
assert_eq!(BigUint::from(&q), BigUint::new(vec![3, 9, 8, 3, 1]) + BigUint::new(vec![5, 4, 9, 3, 1, 81])); big: impl Fn(&BigUint, &BigUint) -> T
) {
run_tests_u_inner(|i| run_tests_u_inner(|k| {
let small_result = small(SmallUint::from(&i), SmallUint::from(&k));
let big_result = big(&i, &k);
assert_eq!(
small_result,
big_result,
"{:#x} {:#x}", i, k
);
}));
}
#[cfg(feature = "num-bigint")]
fn run_tests_i_inner(test: impl Fn(BigInt)) {
run_tests_u_inner(|value| {
test(BigInt::from_biguint(Sign::Plus, value.clone()));
test(BigInt::from_biguint(Sign::Minus, value));
});
}
#[cfg(feature = "num-bigint")]
fn run_tests_i_1<T: Eq + Debug>(small: impl Fn(SmallInt) -> T, big: impl Fn(&BigInt) -> T) {
run_tests_i_inner(|i| {
let small_result = small(SmallInt::from(&i));
let big_result = big(&i);
assert_eq!(
small_result,
big_result,
"{:#x}", i
);
});
}
#[cfg(feature = "num-bigint")]
fn run_tests_i_2<T: Eq + Debug>(
small: impl Fn(SmallInt, SmallInt) -> T,
big: impl Fn(&BigInt, &BigInt) -> T
) {
run_tests_i_inner(|i| run_tests_i_inner(|k| {
let small_result = small(SmallInt::from(&i), SmallInt::from(&k));
let big_result = big(&i, &k);
assert_eq!(
small_result,
big_result,
"{:#x} {:#x}", i, k
);
}));
} }
#[test] #[test]
#[cfg(feature = "num-bigint")] #[cfg(feature = "num-bigint")]
fn test_op_mul_u_u() { fn test_convert_biguint() {
let i = SmallUint::from(u128::MAX); run_tests_u_1(|i| BigUint::from(&i), |i| i.clone());
let k = SmallUint::from(u128::MAX); run_tests_u_1(|i| i, |i| SmallUint::from(i));
let q = i * k;
assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) * u128::MAX);
let i = SmallUint::from(u32::MAX);
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81]));
let q = i * k;
assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) * u32::MAX);
let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1]));
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81]));
let q = i * k;
assert_eq!(BigUint::from(&q), BigUint::new(vec![3, 9, 8, 3, 1]) * BigUint::new(vec![5, 4, 9, 3, 1, 81]));
} }
#[test] #[test]
#[cfg(feature = "num-bigint")] #[cfg(feature = "num-bigint")]
fn test_op_sub_u_u() { fn test_convert_bigint() {
let i = SmallUint::from(u128::MAX); run_tests_i_1(|i| BigInt::from(&i), |i| i.clone());
let k = SmallUint::from(u128::MAX); run_tests_i_1(|i| i, |i| SmallInt::from(i));
let q = i - k;
assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) - u128::MAX);
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81]));
let i = SmallUint::from(u128::MAX);
let q = k - i;
assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) - u128::MAX);
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81]));
let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1]));
let q = k - i;
assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) - BigUint::new(vec![3, 9, 8, 3, 1]));
} }
#[test]
#[cfg(feature = "num-bigint")]
fn test_cmp_u() {
run_tests_u_2(
|i, k| i.partial_cmp(&k),
|i, k| i.partial_cmp(&k),
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_cmp_i() {
run_tests_i_2(
|i, k| i.partial_cmp(&k),
|i, k| i.partial_cmp(&k),
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_add_u() {
run_tests_u_2(
|i, k| BigUint::from(&(i + k)),
|i, k| i + k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_add_i() {
run_tests_i_2(
|i, k| BigInt::from(&(i + k)),
|i, k| i + k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_mul_u() {
run_tests_u_2(
|i, k| BigUint::from(&(i * k)),
|i, k| i * k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_mul_i() {
run_tests_i_2(
|i, k| BigInt::from(&(i * k)),
|i, k| i * k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_sub_u() {
run_tests_u_2(
|i, k| (i >= k).then(|| BigUint::from(&(i - k))),
|i, k| (i >= k).then(|| i - k),
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_sub_i() {
run_tests_i_2(
|i, k| BigInt::from(&(i - k)),
|i, k| i - k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_and_u() {
run_tests_u_2(
|i, k| BigUint::from(&(i & k)),
|i, k| i & k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_and_i() {
run_tests_i_2(
|i, k| BigInt::from(&(i & k)),
|i, k| i & k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_or_u() {
run_tests_u_2(
|i, k| BigUint::from(&(i | k)),
|i, k| i | k,
);
}
// #[test]
// #[cfg(feature = "num-bigint")]
// fn test_op_or_i() {
// run_tests_i_2(
// |i, k| BigInt::from(&(i | k)),
// |i, k| i | k,
// );
// }
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_xor_u() {
run_tests_u_2(
|i, k| BigUint::from(&(i ^ k)),
|i, k| i ^ k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_neg() {
run_tests_i_1(|i| BigInt::from(&-i), |i| -i.clone());
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_conversion_sign_drop() {
run_tests_i_1(
|i| BigUint::from(&SmallInt::unsigned_abs(&i)),
|i| i.magnitude().clone()
);
}
#[test] #[test]
#[cfg(feature = "num-bigint")] #[cfg(feature = "num-bigint")]