mirror of
https://gitlab.com/artofrev/smallint.git
synced 2024-12-04 17:11:38 -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;
|
pub use error::SmallIntError;
|
||||||
|
|
||||||
mod convert;
|
mod convert;
|
||||||
|
mod ord;
|
||||||
|
|
||||||
mod logic;
|
mod logic;
|
||||||
mod ops;
|
mod ops;
|
||||||
|
|
||||||
|
|
96
src/ops.rs
96
src/ops.rs
|
@ -1,14 +1,32 @@
|
||||||
use crate::smallint::SmallUintType;
|
use crate::smallint::{SmallIntType, SmallUintType};
|
||||||
use crate::SmallUint;
|
use crate::{SmallInt, SmallUint};
|
||||||
use core::mem::ManuallyDrop;
|
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 {
|
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 {
|
impl<'a, 'b> $imp<&'a $typ> for &'b $typ {
|
||||||
type Output = $typ;
|
type Output = $typ;
|
||||||
|
|
||||||
fn $fun(self, rhs: &$typ) -> Self::Output {
|
fn $lower(self, rhs: &$typ) -> Self::Output {
|
||||||
$fun(self, rhs)
|
$fun(self, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,24 +34,24 @@ macro_rules! basic_op {
|
||||||
impl<'a> $imp<$typ> for &'a $typ {
|
impl<'a> $imp<$typ> for &'a $typ {
|
||||||
type Output = $typ;
|
type Output = $typ;
|
||||||
|
|
||||||
fn $fun(self, rhs: $typ) -> Self::Output {
|
fn $lower(self, rhs: $typ) -> Self::Output {
|
||||||
self.$fun(&rhs)
|
self.$lower(&rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> $imp<&'a $typ> for $typ {
|
impl<'a> $imp<&'a $typ> for $typ {
|
||||||
type Output = $typ;
|
type Output = $typ;
|
||||||
|
|
||||||
fn $fun(self, rhs: &$typ) -> Self::Output {
|
fn $lower(self, rhs: &$typ) -> Self::Output {
|
||||||
(&self).$fun(rhs)
|
(&self).$lower(rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $imp<$typ> for $typ {
|
impl $imp<$typ> for $typ {
|
||||||
type Output = $typ;
|
type Output = $typ;
|
||||||
|
|
||||||
fn $fun(self, rhs: $typ) -> Self::Output {
|
fn $lower(self, rhs: $typ) -> Self::Output {
|
||||||
(&self).$fun(&rhs)
|
(&self).$lower(&rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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> {
|
fn sub_two_slices(slice1: &[u32], slice2: &[u32]) -> Vec<u32> {
|
||||||
let b = slice1.len();
|
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
|
// Taken from https://github.com/rust-lang/rust/issues/85532#issuecomment-916309635. Credit to
|
||||||
// AaronKutch.
|
// 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
|
/// 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)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct SmallUint(pub(crate) SmallUintType);
|
pub struct SmallUint(pub(crate) SmallUintType);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
@ -14,7 +14,7 @@ pub enum SmallIntType {
|
||||||
Heap((*mut u32, isize)),
|
Heap((*mut u32, isize)),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum SmallUintType {
|
pub enum SmallUintType {
|
||||||
Inline(u128),
|
Inline(u128),
|
||||||
Heap((*mut u32, usize)),
|
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]
|
#[test]
|
||||||
#[cfg(feature = "num-bigint")]
|
#[cfg(feature = "num-bigint")]
|
||||||
fn test_bigint() {
|
fn test_bigint() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user