mirror of
https://gitlab.com/artofrev/smallint.git
synced 2024-12-04 09:01:39 -05:00
signed stuff - todo: test partialord / ord / add for SmallInt
This commit is contained in:
parent
cf9c8b0b78
commit
df10924284
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ mod error;
|
|||
pub use error::SmallIntError;
|
||||
|
||||
mod convert;
|
||||
mod ord;
|
||||
|
||||
mod logic;
|
||||
mod ops;
|
||||
|
||||
|
|
96
src/ops.rs
96
src/ops.rs
|
@ -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
40
src/ord.rs
Normal 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.")
|
||||
}
|
||||
}
|
|
@ -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)),
|
||||
|
|
20
src/tests.rs
20
src/tests.rs
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user