signed stuff - todo: test partialord / ord / add for SmallInt

This commit is contained in:
EvilMuffinHa 2022-08-07 14:05:19 -04:00
parent cf9c8b0b78
commit df10924284
6 changed files with 169 additions and 16 deletions

View File

@ -153,3 +153,26 @@ impl TryFrom<SmallInt> for SmallUint {
}
}
}
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::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap();
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());
Self(SmallUintType::Heap((val.as_mut_ptr(), size)))
} else if s >= 0 {
Self(SmallUintType::Inline(u128::try_from(value).unwrap()))
} else {
Self(SmallUintType::Inline(u128::try_from(-value).unwrap()))
}
}
}
}
}

View File

@ -19,6 +19,8 @@ mod error;
pub use error::SmallIntError;
mod convert;
mod ord;
mod logic;
mod ops;

View File

@ -1,14 +1,32 @@
use crate::smallint::SmallUintType;
use crate::SmallUint;
use crate::smallint::{SmallIntType, SmallUintType};
use crate::{SmallInt, SmallUint};
use core::mem::ManuallyDrop;
use core::ops::{Add, Mul, Sub};
use core::ops::{Add, Mul, Neg, Sub};
impl Neg for SmallInt {
type Output = Self;
fn neg(self) -> Self::Output {
match self.0 {
SmallIntType::Inline(i) => SmallInt(SmallIntType::Inline(-i)),
SmallIntType::Heap((r, s)) => {
let size = usize::try_from(s.abs()).unwrap();
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)))
}
}
}
}
macro_rules! basic_op {
($imp:ident, $typ:ty, $fun:ident) => {
($imp:ident, $lower:ident, $typ:ty, $fun:ident) => {
impl<'a, 'b> $imp<&'a $typ> for &'b $typ {
type Output = $typ;
fn $fun(self, rhs: &$typ) -> Self::Output {
fn $lower(self, rhs: &$typ) -> Self::Output {
$fun(self, rhs)
}
}
@ -16,24 +34,24 @@ macro_rules! basic_op {
impl<'a> $imp<$typ> for &'a $typ {
type Output = $typ;
fn $fun(self, rhs: $typ) -> Self::Output {
self.$fun(&rhs)
fn $lower(self, rhs: $typ) -> Self::Output {
self.$lower(&rhs)
}
}
impl<'a> $imp<&'a $typ> for $typ {
type Output = $typ;
fn $fun(self, rhs: &$typ) -> Self::Output {
(&self).$fun(rhs)
fn $lower(self, rhs: &$typ) -> Self::Output {
(&self).$lower(rhs)
}
}
impl $imp<$typ> for $typ {
type Output = $typ;
fn $fun(self, rhs: $typ) -> Self::Output {
(&self).$fun(&rhs)
fn $lower(self, rhs: $typ) -> Self::Output {
(&self).$lower(&rhs)
}
}
};
@ -122,7 +140,57 @@ fn add(a: &SmallUint, b: &SmallUint) -> SmallUint {
}
}
basic_op!(Add, SmallUint, add);
basic_op!(Add, add, SmallUint, add);
fn add_signed(a: &SmallInt, b: &SmallInt) -> SmallInt {
let a_sign;
match &a.0 {
SmallIntType::Inline(i) => a_sign = i.signum() as i8,
SmallIntType::Heap((_, s)) => a_sign = s.signum() as i8,
}
let b_sign;
match &b.0 {
SmallIntType::Inline(i) => b_sign = i.signum() as i8,
SmallIntType::Heap((_, s)) => b_sign = s.signum() as i8,
}
match (a_sign, b_sign) {
x if (x.0 >= 0 && x.1 >= 0) => SmallInt::from(
SmallUint::from_smallint_unsigned(a.clone())
+ SmallUint::from_smallint_unsigned(b.clone()),
),
x if (x.0 < 0 && x.1 < 0) => -SmallInt::from(
SmallUint::from_smallint_unsigned(a.clone())
+ SmallUint::from_smallint_unsigned(b.clone()),
),
x if (x.0 >= 0 && x.1 < 0) => {
let s = SmallUint::from_smallint_unsigned(a.clone());
let b = SmallUint::from_smallint_unsigned(b.clone());
if b <= s {
SmallInt::from(s - b)
} else {
-SmallInt::from(b - s)
}
}
x if (x.0 < 0 && x.1 >= 0) => {
let s = SmallUint::from_smallint_unsigned(a.clone());
let b = SmallUint::from_smallint_unsigned(b.clone());
if s <= b {
SmallInt::from(b - s)
} else {
-SmallInt::from(s - b)
}
}
(_, _) => {
panic!("This shouldn't happen. ");
}
}
}
basic_op!(Add, add, SmallInt, add_signed);
fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
let b = slice1.len();
@ -207,7 +275,7 @@ fn sub(a: &SmallUint, b: &SmallUint) -> SmallUint {
}
}
basic_op!(Sub, SmallUint, sub);
basic_op!(Sub, sub, SmallUint, sub);
// Taken from https://github.com/rust-lang/rust/issues/85532#issuecomment-916309635. Credit to
// AaronKutch.
@ -392,4 +460,4 @@ fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint {
}
}
basic_op!(Mul, SmallUint, mul);
basic_op!(Mul, mul, SmallUint, mul);

40
src/ord.rs Normal file
View File

@ -0,0 +1,40 @@
use crate::smallint::SmallIntType;
use crate::SmallInt;
use crate::SmallUint;
use std::cmp::Ordering;
impl PartialOrd for SmallInt {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let a_sign;
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 {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).expect("This should not happen.")
}
}

View File

@ -5,7 +5,7 @@ pub struct SmallInt(pub(crate) SmallIntType);
/// An integer-like type that will store small integers up to `u128` inline. Larger integers are
/// represented as a slice to a sequence of base 2<sup>32</sup> digits represented as a `*mut u32`.
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct SmallUint(pub(crate) SmallUintType);
#[derive(Clone, PartialEq, Eq)]
@ -14,7 +14,7 @@ pub enum SmallIntType {
Heap((*mut u32, isize)),
}
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum SmallUintType {
Inline(u128),
Heap((*mut u32, usize)),

View File

@ -191,6 +191,26 @@ fn test_op_xor_u_u() {
);
}
#[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));
}
#[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))
}
#[test]
#[cfg(feature = "num-bigint")]
fn test_bigint() {