use std::ops::Div;
use num_traits::{CheckedDiv, NumCast};
use crate::datatypes::PrimitiveType;
use crate::{
array::{Array, PrimitiveArray},
compute::{
arithmetics::{ArrayCheckedDiv, ArrayDiv},
arity::{binary, binary_checked, unary, unary_checked},
utils::check_same_len,
},
};
use strength_reduce::{
StrengthReducedU16, StrengthReducedU32, StrengthReducedU64, StrengthReducedU8,
};
use super::NativeArithmetics;
pub fn div<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
where
T: NativeArithmetics + Div<Output = T>,
{
if rhs.null_count() == 0 {
binary(lhs, rhs, lhs.data_type().clone(), |a, b| a / b)
} else {
check_same_len(lhs, rhs).unwrap();
let values = lhs.iter().zip(rhs.iter()).map(|(l, r)| match (l, r) {
(Some(l), Some(r)) => Some(*l / *r),
_ => None,
});
PrimitiveArray::from_trusted_len_iter(values).to(lhs.data_type().clone())
}
}
pub fn checked_div<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
where
T: NativeArithmetics + CheckedDiv<Output = T>,
{
let op = move |a: T, b: T| a.checked_div(&b);
binary_checked(lhs, rhs, lhs.data_type().clone(), op)
}
impl<T> ArrayDiv<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeArithmetics + Div<Output = T>,
{
fn div(&self, rhs: &PrimitiveArray<T>) -> Self {
div(self, rhs)
}
}
impl<T> ArrayCheckedDiv<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeArithmetics + CheckedDiv<Output = T>,
{
fn checked_div(&self, rhs: &PrimitiveArray<T>) -> Self {
checked_div(self, rhs)
}
}
pub fn div_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeArithmetics + Div<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_div = StrengthReducedU64::new(rhs);
let r = unary(lhs, |a| a / reduced_div, 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_div = StrengthReducedU32::new(rhs);
let r = unary(lhs, |a| a / reduced_div, 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_div = StrengthReducedU16::new(rhs);
let r = unary(lhs, |a| a / reduced_div, 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_div = StrengthReducedU8::new(rhs);
let r = unary(lhs, |a| a / reduced_div, 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_div_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeArithmetics + CheckedDiv<Output = T>,
{
let rhs = *rhs;
let op = move |a: T| a.checked_div(&rhs);
unary_checked(lhs, op, lhs.data_type().clone())
}
impl<T> ArrayDiv<T> for PrimitiveArray<T>
where
T: NativeArithmetics + Div<Output = T> + NumCast,
{
fn div(&self, rhs: &T) -> Self {
div_scalar(self, rhs)
}
}
impl<T> ArrayCheckedDiv<T> for PrimitiveArray<T>
where
T: NativeArithmetics + CheckedDiv<Output = T>,
{
fn checked_div(&self, rhs: &T) -> Self {
checked_div_scalar(self, rhs)
}
}