Compare commits

...

15 Commits

Author SHA1 Message Date
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
9 changed files with 452 additions and 438 deletions

View File

@ -16,3 +16,7 @@ num-bigint = { version = "0.4.3", optional = true }
[dev-dependencies]
num-bigint = { version = "0.4.3" }
[profile.test]
opt-level = 2

View File

@ -37,7 +37,7 @@ impl From<&SmallInt> for BigInt {
match s.0 {
SmallIntType::Inline(i) => Self::from(i),
SmallIntType::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap();
let size = s.unsigned_abs();
let sign = s.signum();
let slice = unsafe { core::slice::from_raw_parts(r, size) };
let bs = match sign {

View File

@ -109,7 +109,7 @@ impl TryFrom<SmallInt> for u128 {
SmallIntType::Heap((r, s)) => {
let mut ret: u128 = 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) };
for i in slice {
if bits >= 128 {
@ -169,9 +169,9 @@ impl SmallUint {
/// Converts a `SmallInt` into a `SmallUint` and drops the sign instead of throwing an error.
pub fn from_smallint_unsigned(value: SmallInt) -> Self {
match value.0 {
SmallIntType::Inline(i) => Self::try_from(i.abs()).unwrap(),
SmallIntType::Inline(i) => Self::from(i.unsigned_abs()),
SmallIntType::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap();
let size = s.unsigned_abs();
if size > 4 {
let slice = unsafe { core::slice::from_raw_parts(r, size) };
let mut ret = vec![0; size];

View File

@ -1,16 +1,35 @@
use crate::smallint::SmallUintType;
use crate::SmallUint;
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! basic_op {
($imp:ident, $typ:ty, $fun:ident) => {
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 {
$fun(self, rhs)
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
}
}
}
}
@ -37,204 +56,280 @@ macro_rules! basic_op {
(&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
}
}
};
}
fn bitand(a: &SmallUint, b: &SmallUint) -> SmallUint {
match (&a.0, &b.0) {
(&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
SmallUint(SmallUintType::Inline(i & j))
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;
}
(&SmallUintType::Inline(i), &SmallUintType::Heap((r, s)))
| (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
let slice = unsafe { core::slice::from_raw_parts(r, s) };
let mut j = 0u128;
for i in 0..4 {
j <<= 32;
let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice());
j |= slice[3 - i] as u128;
}
SmallUint(SmallUintType::Inline(i & j))
$typ($typ_inner::Heap((retslice.as_mut_ptr(), retslice.len())))
}
}
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! heap_heap_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! heap_heap_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! heap_heap_return_heap {
($typ:ident, $typ_inner:ident; $res:ident) => {
let res = $res.into_boxed_slice();
heap_heap_return_heap_inner! { $typ, $typ_inner; res }
}
}
macro_rules! heap_heap_return_heap_neg {
($typ:ident, $typ_inner:ident; $res:ident) => {
let res = $res.into_boxed_slice();
heap_heap_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();
}
(&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
let slice2 = unsafe { core::slice::from_raw_parts(i, j) };
let min = std::cmp::min(slice1.len(), slice2.len());
let mut res = Vec::with_capacity(min);
for l in 0..min {
res.push(slice1[l] & slice2[l]);
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())))
}
}
}
while res.len() != 1 && res[res.len() - 1] == 0 {
res.pop();
}
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 } }
}
if res.len() <= 4 {
let mut r = 0u128;
for t in 0..res.len() {
r <<= 32;
r |= res[res.len() - 1 - t] as u128;
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 }},
{ heap_heap_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
}
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;
}
SmallUint(SmallUintType::Inline(r))
} else {
let mut slice = ManuallyDrop::new(res.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len())))
}
}
}
}
basic_op!(BitAnd, SmallUint, bitand);
impl<'a> BitAndAssign<&'a SmallUint> for SmallUint {
fn bitand_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() & rhs;
}
}
impl BitAndAssign<SmallUint> for SmallUint {
fn bitand_assign(&mut self, rhs: SmallUint) {
*self = self.clone() & rhs;
}
}
fn bitor(a: &SmallUint, b: &SmallUint) -> SmallUint {
match (&a.0, &b.0) {
(&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
SmallUint(SmallUintType::Inline(i | j))
}
(&SmallUintType::Inline(i), &SmallUintType::Heap((r, s)))
| (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
let slice = unsafe { core::slice::from_raw_parts(r, s) };
let mut retvec = slice.to_vec();
let mut v = i;
#[allow(clippy::needless_range_loop)]
for r in 0..4 {
retvec[r] |= v as u32;
v >>= 32;
}
let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice());
SmallUint(SmallUintType::Heap((retslice.as_mut_ptr(), retslice.len())))
}
(&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
let slice2 = unsafe { core::slice::from_raw_parts(i, j) };
let m = std::cmp::min(slice1.len(), slice2.len());
let mut retvec;
if slice1.len() > slice2.len() {
retvec = slice1.to_vec();
} else {
retvec = slice2.to_vec();
}
for t in 0..m {
retvec[t] = slice1[t] | slice2[t];
}
let mut slice = ManuallyDrop::new(retvec.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len())))
}
}
}
basic_op!(BitOr, SmallUint, bitor);
impl<'a> BitOrAssign<&'a SmallUint> for SmallUint {
fn bitor_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() | rhs;
}
}
impl BitOrAssign<SmallUint> for SmallUint {
fn bitor_assign(&mut self, rhs: SmallUint) {
*self = self.clone() | rhs;
}
}
fn bitxor(a: &SmallUint, b: &SmallUint) -> SmallUint {
match (&a.0, &b.0) {
(&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
SmallUint(SmallUintType::Inline(i ^ j))
}
(&SmallUintType::Inline(i), &SmallUintType::Heap((r, s)))
| (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
let slice = unsafe { core::slice::from_raw_parts(r, s) };
let mut retvec = slice.to_vec();
let mut v = i;
#[allow(clippy::needless_range_loop)]
for r in 0..4 {
retvec[r] ^= v as u32;
v >>= 32;
}
let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice());
SmallUint(SmallUintType::Heap((retslice.as_mut_ptr(), retslice.len())))
}
(&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
let slice2 = unsafe { core::slice::from_raw_parts(i, j) };
let m = std::cmp::min(slice1.len(), slice2.len());
let mut res;
if slice1.len() > slice2.len() {
res = slice1.to_vec();
} else {
res = slice2.to_vec();
}
for t in 0..m {
res[t] = slice1[t] ^ slice2[t];
}
while res.len() != 1 && res[res.len() - 1] == 0 {
res.pop();
}
if res.len() <= 4 {
let mut r = 0u128;
for t in 0..res.len() {
r <<= 32;
r |= res[res.len() - 1 - t] as u128;
heap_heap_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;
}
SmallUint(SmallUintType::Inline(r))
} else {
let mut slice = ManuallyDrop::new(res.into_boxed_slice());
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len())))
}
if lo == 0 && j != 0 {
let res2 = add_two_slices(&res, &[0, 0, 0, 0, 1]);
heap_heap_return_heap_neg! { SmallInt, SmallIntType; res2 }
} else {
heap_heap_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 } };
heap_heap_return_heap! { SmallInt, SmallIntType; res }
},
(Ordering::Greater, Ordering::Less) => {
let res = bitand_two_slices_mixed_sign(slice1, slice2);
heap_heap_return_heap! { SmallInt, SmallIntType; res }
},
(Ordering::Less, Ordering::Greater) => {
let res = bitand_two_slices_mixed_sign(slice2, slice1);
heap_heap_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]);
heap_heap_return_heap_neg! { SmallInt, SmallIntType; res }
},
(Ordering::Equal, _) | (_, Ordering::Equal) => unreachable!("0 must be inline"),
}
}
}
basic_op!(BitXor, SmallUint, bitxor);
impl<'a> BitXorAssign<&'a SmallUint> for SmallUint {
fn bitxor_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() ^ rhs;
}
}
impl BitXorAssign<SmallUint> for SmallUint {
fn bitxor_assign(&mut self, rhs: SmallUint) {
*self = self.clone() ^ rhs;
}
}

View File

@ -9,9 +9,17 @@ impl Neg for SmallInt {
fn neg(self) -> Self::Output {
match self.0 {
SmallIntType::Inline(i) => SmallInt(SmallIntType::Inline(-i)),
SmallIntType::Inline(i) => {
if let Some(n) = i.checked_neg() {
SmallInt(SmallIntType::Inline(n))
} 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 = usize::try_from(s.abs()).unwrap();
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);
@ -58,7 +66,7 @@ macro_rules! basic_op {
};
}
fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
pub(crate) fn add_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let s = slice1.len();
let j = slice2.len();
@ -217,7 +225,7 @@ impl AddAssign<SmallInt> for SmallInt {
}
}
fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
pub(crate) fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let b = slice1.len();
let s = slice2.len();
@ -582,7 +590,7 @@ impl MulAssign<SmallInt> for SmallInt {
}
}
fn div(a: &SmallUint, b: &SmallUint) -> SmallUint {
fn div(_a: &SmallUint, _b: &SmallUint) -> SmallUint {
todo!()
}
@ -600,7 +608,7 @@ impl DivAssign<SmallUint> for SmallUint {
}
}
fn div_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
fn div_signed(_a: &SmallInt, _b: &SmallInt) -> SmallInt {
todo!()
}

View File

@ -40,8 +40,8 @@ impl PartialOrd for SmallUint {
Ordering::Greater => Some(Ordering::Less),
Ordering::Less => Some(Ordering::Greater),
Ordering::Equal => {
let slice1 = unsafe { core::slice::from_raw_parts(r, *s) };
let slice2 = unsafe { core::slice::from_raw_parts(i, *j) };
let slice1 = unsafe { core::slice::from_raw_parts(*r, *s) };
let slice2 = unsafe { core::slice::from_raw_parts(*i, *j) };
for i in 0..*s {
match slice1[s - 1 - i].cmp(&slice2[s - 1 - i]) {
Ordering::Less => return Some(Ordering::Less),
@ -69,8 +69,8 @@ impl PartialEq for SmallInt {
Ordering::Greater => false,
Ordering::Less => false,
Ordering::Equal => {
let us = usize::try_from(s.abs()).unwrap();
let uj = usize::try_from(j.abs()).unwrap();
let us = s.unsigned_abs();
let uj = j.unsigned_abs();
let slice1 = unsafe { core::slice::from_raw_parts(r, us) };
let slice2 = unsafe { core::slice::from_raw_parts(i, uj) };
for i in 0..*s {

View File

@ -12,7 +12,7 @@ impl core::fmt::Debug for SmallInt {
SmallIntType::Inline(i) => {
write!(f, "{}", i)?;
}
SmallIntType::Heap((r, s)) => {
SmallIntType::Heap((_r, _s)) => {
#[cfg(feature = "num-bigint")]
write!(f, "{}", BigInt::from(self))?;
@ -30,7 +30,7 @@ impl core::fmt::Debug for SmallUint {
SmallUintType::Inline(i) => {
write!(f, "{}", i)?;
}
SmallUintType::Heap((r, s)) => {
SmallUintType::Heap((_r, _s)) => {
#[cfg(feature = "num-bigint")]
write!(f, "{}", BigUint::from(self))?;
@ -107,8 +107,7 @@ impl core::fmt::UpperHex for SmallInt {
_ => panic!("This should not happen."),
};
let slice =
unsafe { core::slice::from_raw_parts(r, usize::try_from(s.abs()).unwrap()) };
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)?;
@ -137,8 +136,7 @@ impl core::fmt::LowerHex for SmallInt {
_ => panic!("This should not happen."),
};
let slice =
unsafe { core::slice::from_raw_parts(r, usize::try_from(s.abs()).unwrap()) };
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)?;

View File

@ -22,7 +22,7 @@ pub enum SmallUintType {
impl Drop for SmallInt {
fn drop(&mut 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) };
unsafe { std::mem::drop(Box::from_raw(slice)) }
}
@ -58,7 +58,7 @@ impl Clone for SmallInt {
match self.0 {
SmallIntType::Inline(i) => Self(SmallIntType::Inline(i)),
SmallIntType::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap();
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);
@ -86,7 +86,7 @@ impl Hash for SmallInt {
match self.0 {
SmallIntType::Inline(i) => i.hash(state),
SmallIntType::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap();
let size = s.unsigned_abs();
let slice = unsafe { core::slice::from_raw_parts(r, size) };
slice.hash(state);
}

View File

@ -2,6 +2,7 @@
use crate::SmallInt;
use crate::SmallUint;
use core::fmt::Debug;
#[cfg(feature = "num-bigint")]
use num_bigint::{BigInt, BigUint, Sign};
@ -32,305 +33,213 @@ conversion_tests!(i64, test_i64);
conversion_tests!(u128, test_u128);
conversion_tests!(i128, test_i128);
#[cfg(feature = "num-bigint")]
fn run_tests_u_inner(test: impl Fn(BigUint)) {
for i in 0u8..=7 {
test(BigUint::from(i));
}
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]));
}
#[allow(dead_code)]
#[cfg(feature = "num-bigint")]
fn run_tests_u_1<T: Eq + Debug>(small: impl Fn(SmallUint) -> T, big: impl Fn(&BigUint) -> T) {
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
);
});
}
#[cfg(feature = "num-bigint")]
fn run_tests_u_2<T: Eq + Debug>(
small: impl Fn(SmallUint, SmallUint) -> T,
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]
#[cfg(feature = "num-bigint")]
fn test_cmp_u() {
let i = SmallUint::from(30u32);
let k = SmallUint::from(50u32);
assert!(i < k);
let i = SmallUint::from(u128::MAX);
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81]));
assert!(i < k);
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]));
assert!(i < k);
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() {
let i = SmallInt::from(30u32);
let k = SmallInt::from(50u32);
assert!(i < k);
let i = SmallInt::from(u128::MAX);
let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
assert!(i < k);
let i = SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1]));
let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
assert!(i < k);
let i = SmallInt::from(30u32);
let k = -SmallInt::from(50u32);
assert!(k < i);
let i = SmallInt::from(u128::MAX);
let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
assert!(k < i);
let i = SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1]));
let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
assert!(k < 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() {
let i = SmallUint::from(u128::MAX);
let k = SmallUint::from(u128::MAX);
let q = i + k;
assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) + u128::MAX);
let i = SmallUint::from(u128::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]) + u128::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])
run_tests_u_2(
|i, k| BigUint::from(&(i + k)),
|i, k| i + k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_add_i() {
let i = SmallInt::from(u128::MAX);
let k = -SmallInt::from(u128::MAX);
let q = i + k;
assert_eq!(BigInt::from(&q), BigInt::from(0));
let i = SmallInt::from(u128::MAX);
let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
let q = i + k;
assert_eq!(
BigInt::from(&q),
u128::MAX - BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])
);
let i = -SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1]));
let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
let q = i + k;
assert_eq!(
BigInt::from(&q),
BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])
- BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1])
run_tests_i_2(
|i, k| BigInt::from(&(i + k)),
|i, k| i + k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_mul_u() {
let i = SmallUint::from(u128::MAX);
let k = SmallUint::from(u128::MAX);
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])
run_tests_u_2(
|i, k| BigUint::from(&(i * k)),
|i, k| i * k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_mul_i() {
let i = -SmallInt::from(u128::MAX);
let k = SmallInt::from(u128::MAX);
let q = i * k;
assert_eq!(BigInt::from(&q), -BigInt::from(u128::MAX) * u128::MAX);
let i = -SmallInt::from(u32::MAX);
let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
let q = i * k;
assert_eq!(
BigInt::from(&q),
BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]) * u32::MAX
);
let i = -SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1]));
let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
let q = i * k;
assert_eq!(
BigInt::from(&q),
BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1])
* -BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])
run_tests_i_2(
|i, k| BigInt::from(&(i * k)),
|i, k| i * k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_sub_u() {
let i = SmallUint::from(u128::MAX);
let k = SmallUint::from(u128::MAX);
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])
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() {
let i = -SmallInt::from(u128::MAX);
let k = SmallInt::from(u128::MAX);
let q = i - k;
assert_eq!(BigInt::from(&q), -BigInt::from(u128::MAX) - u128::MAX);
let k = SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
let i = -SmallInt::from(u128::MAX);
let q = k - i;
assert_eq!(
BigInt::from(&q),
BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]) + u128::MAX
);
let k = -SmallInt::from(&BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81]));
let i = SmallInt::from(&BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1]));
let q = k - i;
assert_eq!(
BigInt::from(&q),
-(BigInt::new(Sign::Plus, vec![5, 4, 9, 3, 1, 81])
+ BigInt::new(Sign::Plus, vec![3, 9, 8, 3, 1]))
run_tests_i_2(
|i, k| BigInt::from(&(i - k)),
|i, k| i - k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_and_u() {
let i = SmallUint::from(u128::MAX);
let k = SmallUint::from(u128::MAX);
let q = i & k;
assert_eq!(
BigUint::from(&q),
BigUint::from(u128::MAX) & BigUint::from(u128::MAX)
run_tests_u_2(
|i, k| BigUint::from(&(i & k)),
|i, k| i & k,
);
}
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]) & BigUint::from(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_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() {
let i = SmallUint::from(u128::MAX);
let k = SmallUint::from(u128::MAX);
let q = i | k;
assert_eq!(
BigUint::from(&q),
BigUint::from(u128::MAX) | BigUint::from(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]) | BigUint::from(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])
run_tests_u_2(
|i, k| BigUint::from(&(i | k)),
|i, k| i | k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_xor_u() {
let i = SmallUint::from(u128::MAX);
let k = SmallUint::from(u128::MAX);
let q = i ^ k;
assert_eq!(
BigUint::from(&q),
BigUint::from(u128::MAX) ^ BigUint::from(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]) ^ BigUint::from(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])
run_tests_u_2(
|i, k| BigUint::from(&(i ^ k)),
|i, k| i ^ k,
);
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_op_neg() {
let i = SmallInt::from(u128::MAX);
let q = -i;
assert_eq!(BigInt::from(&q), -BigInt::from(u128::MAX));
let i = SmallInt::from(i64::MIN);
let q = -i;
assert_eq!(BigInt::from(&q), -BigInt::from(i64::MIN));
run_tests_i_1(|i| BigInt::from(&-i), |i| -i.clone());
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_conversion_sign_drop() {
let si = SmallInt::from(i128::MIN + 1);
let i = SmallUint::from_smallint_unsigned(si);
assert_eq!(BigUint::from(&i), BigUint::from(-(i128::MIN + 1) as u128))
run_tests_i_1(
|i| BigUint::from(&SmallUint::from_smallint_unsigned(i)),
|i| i.magnitude().clone()
);
}
#[test]