use std::ops::Rem;
use num_traits::{CheckedRem, NumCast, Zero};
use crate::compute::arithmetics::basic::check_same_type;
use crate::datatypes::DataType;
use crate::{
array::{Array, PrimitiveArray},
compute::{
arithmetics::{ArrayCheckedRem, ArrayRem, NotI128},
arity::{binary, binary_checked, unary, unary_checked},
},
error::Result,
types::NativeType,
};
use strength_reduce::{
StrengthReducedU16, StrengthReducedU32, StrengthReducedU64, StrengthReducedU8,
};
pub fn rem<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> Result<PrimitiveArray<T>>
where
T: NativeType + Rem<Output = T>,
{
check_same_type(lhs, rhs)?;
binary(lhs, rhs, lhs.data_type().clone(), |a, b| a % b)
}
pub fn checked_rem<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> Result<PrimitiveArray<T>>
where
T: NativeType + CheckedRem<Output = T> + Zero,
{
check_same_type(lhs, rhs)?;
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: NativeType + Rem<Output = T> + NotI128,
{
type Output = Self;
fn rem(&self, rhs: &PrimitiveArray<T>) -> Result<Self::Output> {
rem(self, rhs)
}
}
impl<T> ArrayCheckedRem<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeType + CheckedRem<Output = T> + Zero + NotI128,
{
type Output = Self;
fn checked_rem(&self, rhs: &PrimitiveArray<T>) -> Result<Self::Output> {
checked_rem(self, rhs)
}
}
pub fn rem_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeType + Rem<Output = T> + NumCast,
{
let rhs = *rhs;
match T::DATA_TYPE {
DataType::UInt64 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u64>>().unwrap();
let rhs = rhs.to_u64().unwrap();
let reduced_rem = StrengthReducedU64::new(rhs);
unsafe {
std::mem::transmute::<PrimitiveArray<u64>, PrimitiveArray<T>>(unary(
lhs,
|a| a % reduced_rem,
lhs.data_type().clone(),
))
}
}
DataType::UInt32 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u32>>().unwrap();
let rhs = rhs.to_u32().unwrap();
let reduced_rem = StrengthReducedU32::new(rhs);
unsafe {
std::mem::transmute::<PrimitiveArray<u32>, PrimitiveArray<T>>(unary(
lhs,
|a| a % reduced_rem,
lhs.data_type().clone(),
))
}
}
DataType::UInt16 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u16>>().unwrap();
let rhs = rhs.to_u16().unwrap();
let reduced_rem = StrengthReducedU16::new(rhs);
unsafe {
std::mem::transmute::<PrimitiveArray<u16>, PrimitiveArray<T>>(unary(
lhs,
|a| a % reduced_rem,
lhs.data_type().clone(),
))
}
}
DataType::UInt8 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u8>>().unwrap();
let rhs = rhs.to_u8().unwrap();
let reduced_rem = StrengthReducedU8::new(rhs);
unsafe {
std::mem::transmute::<PrimitiveArray<u8>, PrimitiveArray<T>>(unary(
lhs,
|a| a % reduced_rem,
lhs.data_type().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: NativeType + CheckedRem<Output = T> + Zero,
{
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: NativeType + Rem<Output = T> + NotI128 + NumCast,
{
type Output = Self;
fn rem(&self, rhs: &T) -> Result<Self::Output> {
Ok(rem_scalar(self, rhs))
}
}
impl<T> ArrayCheckedRem<T> for PrimitiveArray<T>
where
T: NativeType + CheckedRem<Output = T> + Zero + NotI128,
{
type Output = Self;
fn checked_rem(&self, rhs: &T) -> Result<Self::Output> {
Ok(checked_rem_scalar(self, rhs))
}
}