use std::ops::Rem;
use num_traits::{CheckedRem, NumCast};
use crate::datatypes::PrimitiveType;
use crate::{
array::{Array, PrimitiveArray},
compute::{
arithmetics::{ArrayCheckedRem, ArrayRem},
arity::{binary, binary_checked, unary, unary_checked},
},
};
use strength_reduce::{
StrengthReducedU16, StrengthReducedU32, StrengthReducedU64, StrengthReducedU8,
};
use super::NativeArithmetics;
pub fn rem<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
where
T: NativeArithmetics + Rem<Output = T>,
{
binary(lhs, rhs, lhs.data_type().clone(), |a, b| a % b)
}
pub fn checked_rem<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
where
T: NativeArithmetics + CheckedRem<Output = T>,
{
let op = move |a: T, b: T| a.checked_rem(&b);
binary_checked(lhs, rhs, lhs.data_type().clone(), op)
}
impl<T> ArrayRem<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeArithmetics + Rem<Output = T>,
{
fn rem(&self, rhs: &PrimitiveArray<T>) -> Self {
rem(self, rhs)
}
}
impl<T> ArrayCheckedRem<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeArithmetics + CheckedRem<Output = T>,
{
fn checked_rem(&self, rhs: &PrimitiveArray<T>) -> Self {
checked_rem(self, rhs)
}
}
pub fn rem_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeArithmetics + Rem<Output = T> + NumCast,
{
let rhs = *rhs;
match T::PRIMITIVE {
PrimitiveType::UInt64 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u64>>().unwrap();
let rhs = rhs.to_u64().unwrap();
let reduced_rem = StrengthReducedU64::new(rhs);
let r = unary(lhs, |a| a % reduced_rem, lhs.data_type().clone());
(&r as &dyn Array)
.as_any()
.downcast_ref::<PrimitiveArray<T>>()
.unwrap()
.clone()
}
PrimitiveType::UInt32 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u32>>().unwrap();
let rhs = rhs.to_u32().unwrap();
let reduced_rem = StrengthReducedU32::new(rhs);
let r = unary(lhs, |a| a % reduced_rem, lhs.data_type().clone());
(&r as &dyn Array)
.as_any()
.downcast_ref::<PrimitiveArray<T>>()
.unwrap()
.clone()
}
PrimitiveType::UInt16 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u16>>().unwrap();
let rhs = rhs.to_u16().unwrap();
let reduced_rem = StrengthReducedU16::new(rhs);
let r = unary(lhs, |a| a % reduced_rem, lhs.data_type().clone());
(&r as &dyn Array)
.as_any()
.downcast_ref::<PrimitiveArray<T>>()
.unwrap()
.clone()
}
PrimitiveType::UInt8 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u8>>().unwrap();
let rhs = rhs.to_u8().unwrap();
let reduced_rem = StrengthReducedU8::new(rhs);
let r = unary(lhs, |a| a % reduced_rem, lhs.data_type().clone());
(&r as &dyn Array)
.as_any()
.downcast_ref::<PrimitiveArray<T>>()
.unwrap()
.clone()
}
_ => unary(lhs, |a| a % rhs, lhs.data_type().clone()),
}
}
pub fn checked_rem_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeArithmetics + CheckedRem<Output = T>,
{
let rhs = *rhs;
let op = move |a: T| a.checked_rem(&rhs);
unary_checked(lhs, op, lhs.data_type().clone())
}
impl<T> ArrayRem<T> for PrimitiveArray<T>
where
T: NativeArithmetics + Rem<Output = T> + NumCast,
{
fn rem(&self, rhs: &T) -> Self {
rem_scalar(self, rhs)
}
}
impl<T> ArrayCheckedRem<T> for PrimitiveArray<T>
where
T: NativeArithmetics + CheckedRem<Output = T>,
{
fn checked_rem(&self, rhs: &T) -> Self {
checked_rem_scalar(self, rhs)
}
}