mirror of
https://gitlab.com/artofrev/smallint.git
synced 2026-07-26 10:50:21 -04:00
Compare commits
24 Commits
df10924284
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5bea89295d | |||
| c392ba8633 | |||
| 234fce4b92 | |||
| 81739a1311 | |||
| 2e081c03c5 | |||
| 7702b67f07 | |||
| 70bc33217c | |||
| 1b4407ab45 | |||
| b04ccea008 | |||
| f890aab454 | |||
| 586a0f427e | |||
| 3cd8536296 | |||
| 96f7b1a5ef | |||
| 06ce35aa69 | |||
| 8cf2d6b870 | |||
| ab76eb30f5 | |||
| 570559ae27 | |||
| 45a3975d31 | |||
| 1fe105f58c | |||
| 51f1c7d38a | |||
| 2dc3f2472f | |||
| ef013a5b16 | |||
| f9eb2a1afa | |||
| 2e04862fc1 |
+5
-1
@@ -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
-1
@@ -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 {
|
||||||
|
|||||||
+51
-24
@@ -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,37 +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),
|
|
||||||
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)?)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SmallUint {
|
impl SmallInt {
|
||||||
/// Converts a `SmallInt` into a `SmallUint` and drops the sign instead of throwing an error.
|
/// Returns the absolute value of the `SmallInt` as a `SmallUint`.
|
||||||
pub fn from_smallint_unsigned(value: SmallInt) -> Self {
|
pub fn unsigned_abs(&self) -> SmallUint {
|
||||||
match value.0 {
|
match self.0 {
|
||||||
SmallIntType::Inline(i) => Self::try_from(i.abs()).unwrap(),
|
SmallIntType::Inline(i) => SmallUint::from(i.unsigned_abs()),
|
||||||
SmallIntType::Heap((r, s)) => {
|
SmallIntType::Heap((r, s)) => {
|
||||||
let size = usize::try_from(s.abs()).unwrap();
|
let size = s.unsigned_abs();
|
||||||
if size > 4 {
|
if size > 4 {
|
||||||
let slice = unsafe { core::slice::from_raw_parts(r, size) };
|
let slice = unsafe { core::slice::from_raw_parts(r, size) };
|
||||||
let mut ret = vec![0; size];
|
let mut ret = vec![0; size];
|
||||||
ret.clone_from_slice(slice);
|
ret.clone_from_slice(slice);
|
||||||
let mut val = ManuallyDrop::new(ret.into_boxed_slice());
|
let mut val = ManuallyDrop::new(ret.into_boxed_slice());
|
||||||
Self(SmallUintType::Heap((val.as_mut_ptr(), size)))
|
SmallUint(SmallUintType::Heap((val.as_mut_ptr(), size)))
|
||||||
} else if s >= 0 {
|
} else if s >= 0 {
|
||||||
Self(SmallUintType::Inline(u128::try_from(value).unwrap()))
|
SmallUint(SmallUintType::Inline(u128::try_from(self).unwrap()))
|
||||||
} else {
|
} else {
|
||||||
Self(SmallUintType::Inline(u128::try_from(-value).unwrap()))
|
SmallUint(SmallUintType::Inline(u128::try_from(-self).unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+388
-154
@@ -1,15 +1,35 @@
|
|||||||
use crate::smallint::SmallUintType;
|
use crate::ops::{add_two_slices, sub_two_slices};
|
||||||
use crate::SmallUint;
|
use crate::smallint::{SmallIntType, SmallUintType};
|
||||||
|
use crate::{SmallInt, SmallUint};
|
||||||
|
use core::cmp::Ordering;
|
||||||
use core::mem::ManuallyDrop;
|
use core::mem::ManuallyDrop;
|
||||||
use core::ops::{BitAnd, BitOr, BitXor};
|
use core::ops::{BitAnd, BitOr, BitXor};
|
||||||
|
use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign};
|
||||||
|
|
||||||
macro_rules! basic_op {
|
macro_rules! logic_op {
|
||||||
($imp:ident, $typ:ty, $fun:ident) => {
|
(
|
||||||
|
$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 {
|
impl<'a, 'b> $imp<&'a $typ> for &'b $typ {
|
||||||
type Output = $typ;
|
type Output = $typ;
|
||||||
|
|
||||||
fn $fun(self, rhs: &$typ) -> Self::Output {
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,168 +56,382 @@ macro_rules! basic_op {
|
|||||||
(&self).$fun(&rhs)
|
(&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))
|
|
||||||
}
|
|
||||||
|
|
||||||
(&SmallUintType::Inline(i), &SmallUintType::Heap((r, s)))
|
macro_rules! heap_to_inline {
|
||||||
| (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
|
($typ_inline:ident; $slice:ident) => {
|
||||||
let slice = unsafe { core::slice::from_raw_parts(r, s) };
|
let mut j = 0;
|
||||||
let mut j = 0u128;
|
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
j <<= 32;
|
j <<= 32;
|
||||||
|
j |= $slice[3 - i] as $typ_inline;
|
||||||
j |= slice[3 - i] as u128;
|
}
|
||||||
|
j
|
||||||
}
|
}
|
||||||
SmallUint(SmallUintType::Inline(i & j))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
|
macro_rules! inline_heap_to_inline {
|
||||||
let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
|
($fun:ident, $typ:ident, $typ_inner:ident, $typ_inline:ident; $i:ident, $slice:ident) => {
|
||||||
let slice2 = unsafe { core::slice::from_raw_parts(i, j) };
|
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());
|
let min = std::cmp::min(slice1.len(), slice2.len());
|
||||||
|
|
||||||
let mut res = Vec::with_capacity(min);
|
#[allow(unused_mut)]
|
||||||
|
let mut res = { heap_heap_create_res_shortest! { bitand; slice1, slice2, min } };
|
||||||
for l in 0..min {
|
// TODO: shrink if needed, sometimes to Inline
|
||||||
res.push(slice1[l] & slice2[l]);
|
return_heap! { SmallInt, SmallIntType; res }
|
||||||
}
|
},
|
||||||
|
(Ordering::Greater, Ordering::Less) => {
|
||||||
while res.len() != 1 && res[res.len() - 1] == 0 {
|
let res = bitand_two_slices_mixed_sign(slice1, slice2);
|
||||||
res.pop();
|
return_heap! { SmallInt, SmallIntType; res }
|
||||||
}
|
},
|
||||||
|
(Ordering::Less, Ordering::Greater) => {
|
||||||
if res.len() <= 4 {
|
let res = bitand_two_slices_mixed_sign(slice2, slice1);
|
||||||
let mut r = 0u128;
|
return_heap! { SmallInt, SmallIntType; res }
|
||||||
for t in 0..res.len() {
|
},
|
||||||
r <<= 32;
|
(Ordering::Less, Ordering::Less) => {
|
||||||
r |= res[res.len() - 1 - t] as u128;
|
// (-a) & (-b) = -(((a-1) | (b-1)) + 1)
|
||||||
}
|
// 0 is not negative, so we can ignore it
|
||||||
SmallUint(SmallUintType::Inline(r))
|
let sub1 = sub_two_slices(slice1, &[1]);
|
||||||
} else {
|
let sub2 = sub_two_slices(slice2, &[1]);
|
||||||
let mut slice = ManuallyDrop::new(res.into_boxed_slice());
|
let tmp = bitor_two_slices(&sub1, &sub2);
|
||||||
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len())))
|
let res = add_two_slices(&tmp, &[1]);
|
||||||
}
|
return_heap_neg! { SmallInt, SmallIntType; res }
|
||||||
}
|
},
|
||||||
}
|
(Ordering::Equal, _) | (_, Ordering::Equal) => unreachable!("0 must be inline"),
|
||||||
}
|
|
||||||
|
|
||||||
basic_op!(BitAnd, SmallUint, bitand);
|
|
||||||
|
|
||||||
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);
|
// logic_op! {
|
||||||
|
// BitOr, BitOrAssign, SmallInt, SmallIntType, bitor, bitor_assign;
|
||||||
fn bitxor(a: &SmallUint, b: &SmallUint) -> SmallUint {
|
// i, j, p, q, s, t;
|
||||||
match (&a.0, &b.0) {
|
// {
|
||||||
(&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => {
|
// let slice = unsafe { core::slice::from_raw_parts(p, s.unsigned_abs()) };
|
||||||
SmallUint(SmallUintType::Inline(i ^ j))
|
// match (i.cmp(&0), s.cmp(&0)) {
|
||||||
}
|
// (Ordering::Equal, _) => {
|
||||||
(&SmallUintType::Inline(i), &SmallUintType::Heap((r, s)))
|
// let mut slice = ManuallyDrop::new(<Box<[_]>>::from(slice));
|
||||||
| (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => {
|
// SmallInt(SmallIntType::Heap((slice.as_mut_ptr(), s)))
|
||||||
let slice = unsafe { core::slice::from_raw_parts(r, s) };
|
// },
|
||||||
|
// (Ordering::Greater, Ordering::Greater) => {
|
||||||
let mut retvec = slice.to_vec();
|
// inline_heap_to_heap! { bitor_assign, SmallInt, SmallIntType; i, slice }
|
||||||
|
// },
|
||||||
let mut v = i;
|
// (Ordering::Greater, Ordering::Less) => {
|
||||||
#[allow(clippy::needless_range_loop)]
|
// let mut res = <Box<[u32]>>::from(slice);
|
||||||
for r in 0..4 {
|
// let mut inline = i as u128;
|
||||||
retvec[r] ^= v as u32;
|
// for idx in 0..4 {
|
||||||
|
// res[idx] = ((res[idx] as i32).wrapping_neg() | (inline as i32).wrapping_neg()).wrapping_neg() as u32;
|
||||||
v >>= 32;
|
// inline >>= 32;
|
||||||
}
|
// }
|
||||||
|
// return_heap_inner_neg! { SmallInt, SmallIntType; res }
|
||||||
let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice());
|
// },
|
||||||
|
// (Ordering::Less, Ordering::Greater) => {
|
||||||
SmallUint(SmallUintType::Heap((retslice.as_mut_ptr(), retslice.len())))
|
// let j = { heap_to_inline! { i128; slice } };
|
||||||
}
|
// SmallInt(SmallIntType::Inline(i | -j))
|
||||||
|
// },
|
||||||
(&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => {
|
// (Ordering::Less, Ordering::Less) => {
|
||||||
let slice1 = unsafe { core::slice::from_raw_parts(r, s) };
|
// let mut res = <Box<[u32]>>::from(slice);
|
||||||
let slice2 = unsafe { core::slice::from_raw_parts(i, j) };
|
// let j = { heap_to_inline! { i128; slice } };
|
||||||
|
// let lo = (i | j.wrapping_neg()).wrapping_neg();
|
||||||
let m = std::cmp::min(slice1.len(), slice2.len());
|
// let mut lo_remaining = lo;
|
||||||
|
// for idx in 0..4 {
|
||||||
let mut res;
|
// res[idx] = lo_remaining as u32;
|
||||||
if slice1.len() > slice2.len() {
|
// lo_remaining >>= 32;
|
||||||
res = slice1.to_vec();
|
// }
|
||||||
} else {
|
//
|
||||||
res = slice2.to_vec();
|
// if lo == 0 && j != 0 {
|
||||||
}
|
// let res2 = add_two_slices(&res, &[0, 0, 0, 0, 1]);
|
||||||
|
// return_heap_neg! { SmallInt, SmallIntType; res2 }
|
||||||
for t in 0..m {
|
// } else {
|
||||||
res[t] = slice1[t] ^ slice2[t];
|
// return_heap_inner_neg! { SmallInt, SmallIntType; res }
|
||||||
}
|
// }
|
||||||
|
// },
|
||||||
while res.len() != 1 && res[res.len() - 1] == 0 {
|
// (_, Ordering::Equal) => unreachable!("0 must be inline"),
|
||||||
res.pop();
|
// }
|
||||||
}
|
// },
|
||||||
|
// {
|
||||||
if res.len() <= 4 {
|
// let slice1 = unsafe { core::slice::from_raw_parts(p, s.unsigned_abs()) };
|
||||||
let mut r = 0u128;
|
// let slice2 = unsafe { core::slice::from_raw_parts(q, t.unsigned_abs()) };
|
||||||
for t in 0..res.len() {
|
// match (s.cmp(&0), t.cmp(&0)) {
|
||||||
r <<= 32;
|
// (Ordering::Greater, Ordering::Greater) => {
|
||||||
r |= res[res.len() - 1 - t] as u128;
|
// let min = std::cmp::min(slice1.len(), slice2.len());
|
||||||
}
|
//
|
||||||
SmallUint(SmallUintType::Inline(r))
|
// #[allow(unused_mut)]
|
||||||
} else {
|
// let mut res = { heap_heap_create_res_longest! { bitor; slice1, slice2, min } };
|
||||||
let mut slice = ManuallyDrop::new(res.into_boxed_slice());
|
//
|
||||||
SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len())))
|
// return_heap! { SmallInt, SmallIntType; res }
|
||||||
}
|
// },
|
||||||
}
|
// (Ordering::Greater, Ordering::Less) => {
|
||||||
}
|
// let res = bitor_two_slices_mixed_sign(slice1, slice2);
|
||||||
}
|
// return_heap! { SmallInt, SmallIntType; res }
|
||||||
|
// },
|
||||||
basic_op!(BitXor, SmallUint, bitxor);
|
// (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"),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
+188
-16
@@ -1,16 +1,25 @@
|
|||||||
use crate::smallint::{SmallIntType, SmallUintType};
|
use crate::smallint::{SmallIntType, SmallUintType};
|
||||||
use crate::{SmallInt, SmallUint};
|
use crate::{SmallInt, SmallUint};
|
||||||
use core::mem::ManuallyDrop;
|
use core::mem::ManuallyDrop;
|
||||||
use core::ops::{Add, Mul, Neg, Sub};
|
use core::ops::{Add, Div, Mul, Neg, Sub};
|
||||||
|
use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
|
||||||
|
|
||||||
impl Neg for SmallInt {
|
impl Neg for &SmallInt {
|
||||||
type Output = Self;
|
type Output = SmallInt;
|
||||||
|
|
||||||
fn neg(self) -> Self::Output {
|
fn neg(self) -> SmallInt {
|
||||||
match self.0 {
|
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)) => {
|
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 slice = unsafe { core::slice::from_raw_parts(r, size) };
|
||||||
let mut ret = vec![0; size];
|
let mut ret = vec![0; size];
|
||||||
ret.clone_from_slice(slice);
|
ret.clone_from_slice(slice);
|
||||||
@@ -21,6 +30,14 @@ impl Neg for SmallInt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Neg for SmallInt {
|
||||||
|
type Output = SmallInt;
|
||||||
|
|
||||||
|
fn neg(self) -> SmallInt {
|
||||||
|
(&self).neg()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! basic_op {
|
macro_rules! basic_op {
|
||||||
($imp:ident, $lower:ident, $typ:ty, $fun:ident) => {
|
($imp:ident, $lower:ident, $typ:ty, $fun:ident) => {
|
||||||
impl<'a, 'b> $imp<&'a $typ> for &'b $typ {
|
impl<'a, 'b> $imp<&'a $typ> for &'b $typ {
|
||||||
@@ -57,7 +74,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 s = slice1.len();
|
||||||
let j = slice2.len();
|
let j = slice2.len();
|
||||||
|
|
||||||
@@ -142,6 +159,18 @@ fn add(a: &SmallUint, b: &SmallUint) -> SmallUint {
|
|||||||
|
|
||||||
basic_op!(Add, add, SmallUint, add);
|
basic_op!(Add, add, SmallUint, add);
|
||||||
|
|
||||||
|
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 {
|
fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
|
||||||
let a_sign;
|
let a_sign;
|
||||||
match &a.0 {
|
match &a.0 {
|
||||||
@@ -157,17 +186,17 @@ fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
|
|||||||
|
|
||||||
match (a_sign, b_sign) {
|
match (a_sign, b_sign) {
|
||||||
x if (x.0 >= 0 && x.1 >= 0) => SmallInt::from(
|
x if (x.0 >= 0 && x.1 >= 0) => SmallInt::from(
|
||||||
SmallUint::from_smallint_unsigned(a.clone())
|
a.unsigned_abs()
|
||||||
+ SmallUint::from_smallint_unsigned(b.clone()),
|
+ b.unsigned_abs(),
|
||||||
),
|
),
|
||||||
x if (x.0 < 0 && x.1 < 0) => -SmallInt::from(
|
x if (x.0 < 0 && x.1 < 0) => -SmallInt::from(
|
||||||
SmallUint::from_smallint_unsigned(a.clone())
|
a.unsigned_abs()
|
||||||
+ SmallUint::from_smallint_unsigned(b.clone()),
|
+ b.unsigned_abs(),
|
||||||
),
|
),
|
||||||
|
|
||||||
x if (x.0 >= 0 && x.1 < 0) => {
|
x if (x.0 >= 0 && x.1 < 0) => {
|
||||||
let s = SmallUint::from_smallint_unsigned(a.clone());
|
let s = a.unsigned_abs();
|
||||||
let b = SmallUint::from_smallint_unsigned(b.clone());
|
let b = b.unsigned_abs();
|
||||||
if b <= s {
|
if b <= s {
|
||||||
SmallInt::from(s - b)
|
SmallInt::from(s - b)
|
||||||
} else {
|
} else {
|
||||||
@@ -176,8 +205,8 @@ fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
x if (x.0 < 0 && x.1 >= 0) => {
|
x if (x.0 < 0 && x.1 >= 0) => {
|
||||||
let s = SmallUint::from_smallint_unsigned(a.clone());
|
let s = a.unsigned_abs();
|
||||||
let b = SmallUint::from_smallint_unsigned(b.clone());
|
let b = b.unsigned_abs();
|
||||||
if s <= b {
|
if s <= b {
|
||||||
SmallInt::from(b - s)
|
SmallInt::from(b - s)
|
||||||
} else {
|
} else {
|
||||||
@@ -192,7 +221,19 @@ fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
|
|||||||
|
|
||||||
basic_op!(Add, add, SmallInt, add_signed);
|
basic_op!(Add, add, SmallInt, add_signed);
|
||||||
|
|
||||||
fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
|
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();
|
||||||
|
|
||||||
@@ -277,6 +318,36 @@ fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint {
|
|||||||
|
|
||||||
basic_op!(Sub, 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.
|
||||||
const fn carrying_mul_u128(lhs: u128, rhs: u128, carry: u128) -> (u128, u128) {
|
const fn carrying_mul_u128(lhs: u128, rhs: u128, carry: u128) -> (u128, u128) {
|
||||||
@@ -461,3 +532,104 @@ fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
basic_op!(Mul, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+83
-27
@@ -1,40 +1,96 @@
|
|||||||
use crate::smallint::SmallIntType;
|
use crate::smallint::{SmallIntType, SmallUintType};
|
||||||
use crate::SmallInt;
|
use crate::SmallInt;
|
||||||
use crate::SmallUint;
|
use crate::SmallUint;
|
||||||
use std::cmp::Ordering;
|
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 {
|
impl PartialOrd for SmallInt {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
let a_sign;
|
Some(self.cmp(other))
|
||||||
match &self.0 {
|
|
||||||
SmallIntType::Inline(i) => a_sign = i.signum() as i8,
|
|
||||||
SmallIntType::Heap((_, s)) => a_sign = s.signum() as i8,
|
|
||||||
}
|
|
||||||
|
|
||||||
let b_sign;
|
|
||||||
match &other.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) => Some(Ordering::Greater),
|
|
||||||
|
|
||||||
x if (x.0 < 0 && x.1 >= 0) => Some(Ordering::Less),
|
|
||||||
|
|
||||||
x if (x.0 >= 0 && x.1 >= 0) => SmallUint::from_smallint_unsigned(self.clone())
|
|
||||||
.partial_cmp(&SmallUint::from_smallint_unsigned(other.clone())),
|
|
||||||
|
|
||||||
x if (x.0 < 0 && x.1 < 0) => SmallUint::from_smallint_unsigned(other.clone())
|
|
||||||
.partial_cmp(&SmallUint::from_smallint_unsigned(self.clone())),
|
|
||||||
|
|
||||||
(_, _) => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for SmallInt {
|
impl Ord for SmallInt {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.partial_cmp(other).expect("This should not happen.")
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+136
-4
@@ -1,19 +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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+60
-5
@@ -1,20 +1,19 @@
|
|||||||
|
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, PartialOrd, Ord)]
|
|
||||||
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, PartialOrd, Ord)]
|
|
||||||
pub enum SmallUintType {
|
pub enum SmallUintType {
|
||||||
Inline(u128),
|
Inline(u128),
|
||||||
Heap((*mut u32, usize)),
|
Heap((*mut u32, usize)),
|
||||||
@@ -23,7 +22,7 @@ pub enum SmallUintType {
|
|||||||
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)) }
|
||||||
}
|
}
|
||||||
@@ -38,3 +37,59 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+187
-133
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
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, BigUint, Sign};
|
use num_bigint::{BigInt, BigUint, Sign};
|
||||||
@@ -32,183 +33,236 @@ 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);
|
||||||
|
|
||||||
|
#[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]
|
#[test]
|
||||||
#[cfg(feature = "num-bigint")]
|
#[cfg(feature = "num-bigint")]
|
||||||
fn test_op_add_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(u128::MAX);
|
#[test]
|
||||||
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81]));
|
#[cfg(feature = "num-bigint")]
|
||||||
let q = i + k;
|
fn test_convert_bigint() {
|
||||||
assert_eq!(
|
run_tests_i_1(|i| BigInt::from(&i), |i| i.clone());
|
||||||
BigUint::from(&q),
|
run_tests_i_1(|i| i, |i| SmallInt::from(i));
|
||||||
BigUint::new(vec![5, 4, 9, 3, 1, 81]) + u128::MAX
|
}
|
||||||
);
|
|
||||||
|
|
||||||
let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1]));
|
#[test]
|
||||||
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81]));
|
#[cfg(feature = "num-bigint")]
|
||||||
let q = i + k;
|
fn test_cmp_u() {
|
||||||
assert_eq!(
|
run_tests_u_2(
|
||||||
BigUint::from(&q),
|
|i, k| i.partial_cmp(&k),
|
||||||
BigUint::new(vec![3, 9, 8, 3, 1]) + BigUint::new(vec![5, 4, 9, 3, 1, 81])
|
|i, k| i.partial_cmp(&k),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "num-bigint")]
|
#[cfg(feature = "num-bigint")]
|
||||||
fn test_op_mul_u_u() {
|
fn test_cmp_i() {
|
||||||
let i = SmallUint::from(u128::MAX);
|
run_tests_i_2(
|
||||||
let k = SmallUint::from(u128::MAX);
|
|i, k| i.partial_cmp(&k),
|
||||||
let q = i * k;
|
|i, k| i.partial_cmp(&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_op_add_u() {
|
||||||
let i = SmallUint::from(u128::MAX);
|
run_tests_u_2(
|
||||||
let k = SmallUint::from(u128::MAX);
|
|i, k| BigUint::from(&(i + k)),
|
||||||
let q = i - k;
|
|i, k| 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]
|
#[test]
|
||||||
#[cfg(feature = "num-bigint")]
|
#[cfg(feature = "num-bigint")]
|
||||||
fn test_op_and_u_u() {
|
fn test_op_add_i() {
|
||||||
let i = SmallUint::from(u128::MAX);
|
run_tests_i_2(
|
||||||
let k = SmallUint::from(u128::MAX);
|
|i, k| BigInt::from(&(i + k)),
|
||||||
let q = i & k;
|
|i, k| 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]) & 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]
|
#[test]
|
||||||
#[cfg(feature = "num-bigint")]
|
#[cfg(feature = "num-bigint")]
|
||||||
fn test_op_or_u_u() {
|
fn test_op_mul_u() {
|
||||||
let i = SmallUint::from(u128::MAX);
|
run_tests_u_2(
|
||||||
let k = SmallUint::from(u128::MAX);
|
|i, k| BigUint::from(&(i * k)),
|
||||||
let q = i | k;
|
|i, k| 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])
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "num-bigint")]
|
#[cfg(feature = "num-bigint")]
|
||||||
fn test_op_xor_u_u() {
|
fn test_op_mul_i() {
|
||||||
let i = SmallUint::from(u128::MAX);
|
run_tests_i_2(
|
||||||
let k = SmallUint::from(u128::MAX);
|
|i, k| BigInt::from(&(i * k)),
|
||||||
let q = i ^ k;
|
|i, k| 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]));
|
#[test]
|
||||||
let i = SmallUint::from(u128::MAX);
|
#[cfg(feature = "num-bigint")]
|
||||||
let q = k ^ i;
|
fn test_op_sub_u() {
|
||||||
assert_eq!(
|
run_tests_u_2(
|
||||||
BigUint::from(&q),
|
|i, k| (i >= k).then(|| BigUint::from(&(i - k))),
|
||||||
BigUint::new(vec![5, 4, 9, 3, 1, 81]) ^ BigUint::from(u128::MAX)
|
|i, k| (i >= k).then(|| i - k),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81]));
|
#[test]
|
||||||
let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1]));
|
#[cfg(feature = "num-bigint")]
|
||||||
let q = k ^ i;
|
fn test_op_sub_i() {
|
||||||
assert_eq!(
|
run_tests_i_2(
|
||||||
BigUint::from(&q),
|
|i, k| BigInt::from(&(i - k)),
|
||||||
BigUint::new(vec![5, 4, 9, 3, 1, 81]) ^ BigUint::new(vec![3, 9, 8, 3, 1])
|
|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]
|
#[test]
|
||||||
#[cfg(feature = "num-bigint")]
|
#[cfg(feature = "num-bigint")]
|
||||||
fn test_op_neg() {
|
fn test_op_neg() {
|
||||||
let i = SmallInt::from(u128::MAX);
|
run_tests_i_1(|i| BigInt::from(&-i), |i| -i.clone());
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "num-bigint")]
|
#[cfg(feature = "num-bigint")]
|
||||||
fn test_conversion_sign_drop() {
|
fn test_conversion_sign_drop() {
|
||||||
let si = SmallInt::from(i128::MIN + 1);
|
run_tests_i_1(
|
||||||
let i = SmallUint::from_smallint_unsigned(si);
|
|i| BigUint::from(&SmallInt::unsigned_abs(&i)),
|
||||||
assert_eq!(BigUint::from(&i), BigUint::from(-(i128::MIN + 1) as u128))
|
|i| i.magnitude().clone()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user