use std::ops::Div;
use num_traits::{CheckedDiv, NumCast, Zero};
use crate::compute::arithmetics::basic::{check_same_len, check_same_type};
use crate::datatypes::DataType;
use crate::{
array::{Array, PrimitiveArray},
compute::{
arithmetics::{ArrayCheckedDiv, ArrayDiv, NotI128},
arity::{binary, binary_checked, unary, unary_checked},
},
error::Result,
types::NativeType,
};
use strength_reduce::{
StrengthReducedU16, StrengthReducedU32, StrengthReducedU64, StrengthReducedU8,
};
pub fn div<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> Result<PrimitiveArray<T>>
where
T: NativeType + Div<Output = T>,
{
check_same_type(lhs, rhs)?;
if rhs.null_count() == 0 {
binary(lhs, rhs, lhs.data_type().clone(), |a, b| a / b)
} else {
check_same_len(lhs, rhs)?;
let values = lhs.iter().zip(rhs.iter()).map(|(l, r)| match (l, r) {
(Some(l), Some(r)) => Some(*l / *r),
_ => None,
});
Ok(PrimitiveArray::from_trusted_len_iter(values).to(lhs.data_type().clone()))
}
}
pub fn checked_div<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> Result<PrimitiveArray<T>>
where
T: NativeType + CheckedDiv<Output = T> + Zero,
{
check_same_type(lhs, rhs)?;
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: NativeType + Div<Output = T> + NotI128,
{
type Output = Self;
fn div(&self, rhs: &PrimitiveArray<T>) -> Result<Self::Output> {
div(self, rhs)
}
}
impl<T> ArrayCheckedDiv<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeType + CheckedDiv<Output = T> + Zero + NotI128,
{
type Output = Self;
fn checked_div(&self, rhs: &PrimitiveArray<T>) -> Result<Self::Output> {
checked_div(self, rhs)
}
}
pub fn div_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeType + Div<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_div = StrengthReducedU64::new(rhs);
unsafe {
std::mem::transmute::<PrimitiveArray<u64>, PrimitiveArray<T>>(unary(
lhs,
|a| a / reduced_div,
lhs.data_type().clone(),
))
}
}
DataType::UInt32 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u32>>().unwrap();
let rhs = rhs.to_u32().unwrap();
let reduced_div = StrengthReducedU32::new(rhs);
unsafe {
std::mem::transmute::<PrimitiveArray<u32>, PrimitiveArray<T>>(unary(
lhs,
|a| a / reduced_div,
lhs.data_type().clone(),
))
}
}
DataType::UInt16 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u16>>().unwrap();
let rhs = rhs.to_u16().unwrap();
let reduced_div = StrengthReducedU16::new(rhs);
unsafe {
std::mem::transmute::<PrimitiveArray<u16>, PrimitiveArray<T>>(unary(
lhs,
|a| a / reduced_div,
lhs.data_type().clone(),
))
}
}
DataType::UInt8 => {
let lhs = lhs.as_any().downcast_ref::<PrimitiveArray<u8>>().unwrap();
let rhs = rhs.to_u8().unwrap();
let reduced_div = StrengthReducedU8::new(rhs);
unsafe {
std::mem::transmute::<PrimitiveArray<u8>, PrimitiveArray<T>>(unary(
lhs,
|a| a / reduced_div,
lhs.data_type().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: NativeType + CheckedDiv<Output = T> + Zero,
{
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: NativeType + Div<Output = T> + NotI128 + NumCast,
{
type Output = Self;
fn div(&self, rhs: &T) -> Result<Self::Output> {
Ok(div_scalar(self, rhs))
}
}
impl<T> ArrayCheckedDiv<T> for PrimitiveArray<T>
where
T: NativeType + CheckedDiv<Output = T> + Zero + NotI128,
{
type Output = Self;
fn checked_div(&self, rhs: &T) -> Result<Self::Output> {
Ok(checked_div_scalar(self, rhs))
}
}