From 85babc5e1107703a59798a0e3e429fc3fa50fc85 Mon Sep 17 00:00:00 2001 From: EvilMuffinHa Date: Sat, 6 Aug 2022 16:38:22 -0400 Subject: [PATCH] basic logic for smalluint --- src/lib.rs | 1 + src/logic.rs | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/ops.rs | 1 + src/tests.rs | 61 ++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 src/logic.rs diff --git a/src/lib.rs b/src/lib.rs index 56b9710..2de2b64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ pub use error::SmallIntError; mod convert; mod ops; +mod logic; mod bigint; diff --git a/src/logic.rs b/src/logic.rs new file mode 100644 index 0000000..c678d80 --- /dev/null +++ b/src/logic.rs @@ -0,0 +1,219 @@ +use crate::SmallUint; +use crate::smallint::SmallUintType; +use core::ops::{BitAnd, BitOr, BitXor}; +use core::mem::ManuallyDrop; + +macro_rules! basic_op { + ($imp:ident, $typ:ty, $fun:ident) => { + + impl<'a, 'b> $imp<&'a $typ> for &'b $typ { + + type Output = $typ; + + fn $fun(self, rhs: &$typ) -> Self::Output { + $fun(self, rhs) + } + + } + + impl<'a> $imp<$typ> for &'a $typ { + + type Output = $typ; + + fn $fun(self, rhs: $typ) -> Self::Output { + self.$fun(&rhs) + } + + } + + impl<'a> $imp<&'a $typ> for $typ { + + type Output = $typ; + + fn $fun(self, rhs: &$typ) -> Self::Output { + (&self).$fun(rhs) + } + + } + + + impl $imp<$typ> for $typ { + + type Output = $typ; + + fn $fun(self, rhs: $typ) -> Self::Output { + (&self).$fun(&rhs) + } + + } + } +} + +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))) | (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => { + let slice = unsafe { core::slice::from_raw_parts(r, s) }; + let mut j = 0u128; + for i in 0..4 { + j <<= 32; + + j |= slice[3 - i] as u128; + + } + SmallUint(SmallUintType::Inline(i & j)) + }, + + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { + + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; + + let min = std::cmp::min(slice1.len(), slice2.len()); + + let mut res = Vec::with_capacity(min); + + for l in 0..min { + res.push(slice1[l] & slice2[l]); + } + + while res.len() != 1 && res[res.len() - 1] == 0 { + res.pop(); + } + + if res.len() <= 4 { + let mut r = 0u128; + for t in 0..res.len() { + r <<= 32; + r |= res[res.len() - 1 - t] as u128; + } + SmallUint(SmallUintType::Inline(r)) + } else { + let mut slice = ManuallyDrop::new(res.into_boxed_slice()); + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len()))) + } + } + } +} + +basic_op!(BitAnd, SmallUint, bitand); + +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); + +fn bitxor(a: &SmallUint, b: &SmallUint) -> SmallUint { + match (&a.0, &b.0) { + (&SmallUintType::Inline(i), &SmallUintType::Inline(j)) => { + SmallUint(SmallUintType::Inline(i ^ j)) + } + (&SmallUintType::Inline(i), &SmallUintType::Heap((r, s))) | (&SmallUintType::Heap((r, s)), &SmallUintType::Inline(i)) => { + let slice = unsafe { core::slice::from_raw_parts(r, s) }; + + let mut retvec = slice.to_vec(); + + let mut v = i; + #[allow(clippy::needless_range_loop)] + for r in 0..4 { + retvec[r] ^= v as u32; + + v >>= 32; + } + + let mut retslice = ManuallyDrop::new(retvec.into_boxed_slice()); + + SmallUint(SmallUintType::Heap((retslice.as_mut_ptr(), retslice.len()))) + + + }, + + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { + + let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; + let slice2 = unsafe { core::slice::from_raw_parts(i, j) }; + + let m = std::cmp::min(slice1.len(), slice2.len()); + + let mut res; + if slice1.len() > slice2.len() { + res = slice1.to_vec(); + } else { + res = slice2.to_vec(); + } + + for t in 0..m { + res[t] = slice1[t] ^ slice2[t]; + } + + while res.len() != 1 && res[res.len() - 1] == 0 { + res.pop(); + } + + if res.len() <= 4 { + let mut r = 0u128; + for t in 0..res.len() { + r <<= 32; + r |= res[res.len() - 1 - t] as u128; + } + SmallUint(SmallUintType::Inline(r)) + } else { + let mut slice = ManuallyDrop::new(res.into_boxed_slice()); + SmallUint(SmallUintType::Heap((slice.as_mut_ptr(), slice.len()))) + } + } + } +} + +basic_op!(BitXor, SmallUint, bitxor); diff --git a/src/ops.rs b/src/ops.rs index bba35bd..7cef35e 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -430,6 +430,7 @@ fn mul(a: &SmallUint, b: &SmallUint) -> SmallUint { }, + (&SmallUintType::Heap((r, s)), &SmallUintType::Heap((i, j))) => { let slice1 = unsafe { core::slice::from_raw_parts(r, s) }; diff --git a/src/tests.rs b/src/tests.rs index 7e4818b..e75196d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -93,6 +93,67 @@ fn test_op_sub_u_u() { } +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_and_u_u() { + let i = SmallUint::from(u128::MAX); + let k = SmallUint::from(u128::MAX); + let q = i & k; + assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) & BigUint::from(u128::MAX)); + + let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); + let i = SmallUint::from(u128::MAX); + let q = k & i; + assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3]) & BigUint::from(u128::MAX)); + + let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); + let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); + let q = k & i; + assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) & BigUint::new(vec![3, 9, 8, 3, 1])); +} + + +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_or_u_u() { + let i = SmallUint::from(u128::MAX); + let k = SmallUint::from(u128::MAX); + let q = i | k; + assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) | BigUint::from(u128::MAX)); + + let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); + let i = SmallUint::from(u128::MAX); + let q = k | i; + assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) | BigUint::from(u128::MAX)); + + let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); + let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); + let q = k | i; + assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) | BigUint::new(vec![3, 9, 8, 3, 1])); + +} + +#[test] +#[cfg(feature = "num-bigint")] +fn test_op_xor_u_u() { + let i = SmallUint::from(u128::MAX); + let k = SmallUint::from(u128::MAX); + let q = i ^ k; + assert_eq!(BigUint::from(&q), BigUint::from(u128::MAX) ^ BigUint::from(u128::MAX)); + + let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); + let i = SmallUint::from(u128::MAX); + let q = k ^ i; + assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) ^ BigUint::from(u128::MAX)); + + let k = SmallUint::from(&BigUint::new(vec![5, 4, 9, 3, 1, 81])); + let i = SmallUint::from(&BigUint::new(vec![3, 9, 8, 3, 1])); + let q = k ^ i; + assert_eq!(BigUint::from(&q), BigUint::new(vec![5, 4, 9, 3, 1, 81]) ^ BigUint::new(vec![3, 9, 8, 3, 1])); + +} + + #[test] #[cfg(feature = "num-bigint")] fn test_bigint() {