smallint/src/logic.rs
2022-08-08 21:35:08 -04:00

241 lines
7.0 KiB
Rust

use crate::smallint::SmallUintType;
use crate::SmallUint;
use core::mem::ManuallyDrop;
use core::ops::{BitAnd, BitOr, BitXor};
use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign};
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);
impl<'a> BitAndAssign<&'a SmallUint> for SmallUint {
fn bitand_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() & rhs;
}
}
impl BitAndAssign<SmallUint> for SmallUint {
fn bitand_assign(&mut self, rhs: SmallUint) {
*self = self.clone() & rhs;
}
}
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);
impl<'a> BitOrAssign<&'a SmallUint> for SmallUint {
fn bitor_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() | rhs;
}
}
impl BitOrAssign<SmallUint> for SmallUint {
fn bitor_assign(&mut self, rhs: SmallUint) {
*self = self.clone() | rhs;
}
}
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);
impl<'a> BitXorAssign<&'a SmallUint> for SmallUint {
fn bitxor_assign(&mut self, rhs: &'a SmallUint) {
*self = self.clone() ^ rhs;
}
}
impl BitXorAssign<SmallUint> for SmallUint {
fn bitxor_assign(&mut self, rhs: SmallUint) {
*self = self.clone() ^ rhs;
}
}