use std::ops::Add;
use num_traits::{ops::overflowing::OverflowingAdd, CheckedAdd, SaturatingAdd, WrappingAdd, Zero};
use crate::compute::arithmetics::basic::check_same_type;
use crate::compute::arithmetics::ArrayWrappingAdd;
use crate::{
array::{Array, PrimitiveArray},
bitmap::Bitmap,
compute::{
arithmetics::{
ArrayAdd, ArrayCheckedAdd, ArrayOverflowingAdd, ArraySaturatingAdd, NotI128,
},
arity::{
binary, binary_checked, binary_with_bitmap, unary, unary_checked, unary_with_bitmap,
},
},
error::Result,
types::NativeType,
};
pub fn add<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> Result<PrimitiveArray<T>>
where
T: NativeType + Add<Output = T>,
{
check_same_type(lhs, rhs)?;
binary(lhs, rhs, lhs.data_type().clone(), |a, b| a + b)
}
pub fn wrapping_add<T>(
lhs: &PrimitiveArray<T>,
rhs: &PrimitiveArray<T>,
) -> Result<PrimitiveArray<T>>
where
T: NativeType + WrappingAdd<Output = T>,
{
check_same_type(lhs, rhs)?;
let op = move |a: T, b: T| a.wrapping_add(&b);
binary(lhs, rhs, lhs.data_type().clone(), op)
}
pub fn checked_add<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> Result<PrimitiveArray<T>>
where
T: NativeType + CheckedAdd<Output = T> + Zero,
{
check_same_type(lhs, rhs)?;
let op = move |a: T, b: T| a.checked_add(&b);
binary_checked(lhs, rhs, lhs.data_type().clone(), op)
}
pub fn saturating_add<T>(
lhs: &PrimitiveArray<T>,
rhs: &PrimitiveArray<T>,
) -> Result<PrimitiveArray<T>>
where
T: NativeType + SaturatingAdd<Output = T>,
{
check_same_type(lhs, rhs)?;
let op = move |a: T, b: T| a.saturating_add(&b);
binary(lhs, rhs, lhs.data_type().clone(), op)
}
pub fn overflowing_add<T>(
lhs: &PrimitiveArray<T>,
rhs: &PrimitiveArray<T>,
) -> Result<(PrimitiveArray<T>, Bitmap)>
where
T: NativeType + OverflowingAdd<Output = T>,
{
check_same_type(lhs, rhs)?;
let op = move |a: T, b: T| a.overflowing_add(&b);
binary_with_bitmap(lhs, rhs, lhs.data_type().clone(), op)
}
impl<T> ArrayAdd<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeType + Add<Output = T> + NotI128,
{
type Output = Self;
fn add(&self, rhs: &PrimitiveArray<T>) -> Result<Self::Output> {
add(self, rhs)
}
}
impl<T> ArrayWrappingAdd<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeType + WrappingAdd<Output = T> + NotI128,
{
type Output = Self;
fn wrapping_add(&self, rhs: &PrimitiveArray<T>) -> Result<Self::Output> {
wrapping_add(self, rhs)
}
}
impl<T> ArrayCheckedAdd<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeType + CheckedAdd<Output = T> + Zero + NotI128,
{
type Output = Self;
fn checked_add(&self, rhs: &PrimitiveArray<T>) -> Result<Self::Output> {
checked_add(self, rhs)
}
}
impl<T> ArraySaturatingAdd<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeType + SaturatingAdd<Output = T> + NotI128,
{
type Output = Self;
fn saturating_add(&self, rhs: &PrimitiveArray<T>) -> Result<Self::Output> {
saturating_add(self, rhs)
}
}
impl<T> ArrayOverflowingAdd<PrimitiveArray<T>> for PrimitiveArray<T>
where
T: NativeType + OverflowingAdd<Output = T> + NotI128,
{
type Output = Self;
fn overflowing_add(&self, rhs: &PrimitiveArray<T>) -> Result<(Self::Output, Bitmap)> {
overflowing_add(self, rhs)
}
}
pub fn add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeType + Add<Output = T>,
{
let rhs = *rhs;
unary(lhs, |a| a + rhs, lhs.data_type().clone())
}
pub fn wrapping_add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeType + WrappingAdd<Output = T>,
{
unary(lhs, |a| a.wrapping_add(rhs), lhs.data_type().clone())
}
pub fn checked_add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeType + CheckedAdd<Output = T> + Zero,
{
let rhs = *rhs;
let op = move |a: T| a.checked_add(&rhs);
unary_checked(lhs, op, lhs.data_type().clone())
}
pub fn saturating_add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
where
T: NativeType + SaturatingAdd<Output = T>,
{
let rhs = *rhs;
let op = move |a: T| a.saturating_add(&rhs);
unary(lhs, op, lhs.data_type().clone())
}
pub fn overflowing_add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> (PrimitiveArray<T>, Bitmap)
where
T: NativeType + OverflowingAdd<Output = T>,
{
let rhs = *rhs;
let op = move |a: T| a.overflowing_add(&rhs);
unary_with_bitmap(lhs, op, lhs.data_type().clone())
}
impl<T> ArrayAdd<T> for PrimitiveArray<T>
where
T: NativeType + Add<Output = T> + NotI128,
{
type Output = Self;
fn add(&self, rhs: &T) -> Result<Self::Output> {
Ok(add_scalar(self, rhs))
}
}
impl<T> ArrayCheckedAdd<T> for PrimitiveArray<T>
where
T: NativeType + CheckedAdd<Output = T> + Zero + NotI128,
{
type Output = Self;
fn checked_add(&self, rhs: &T) -> Result<Self::Output> {
Ok(checked_add_scalar(self, rhs))
}
}
impl<T> ArraySaturatingAdd<T> for PrimitiveArray<T>
where
T: NativeType + SaturatingAdd<Output = T> + NotI128,
{
type Output = Self;
fn saturating_add(&self, rhs: &T) -> Result<Self::Output> {
Ok(saturating_add_scalar(self, rhs))
}
}
impl<T> ArrayOverflowingAdd<T> for PrimitiveArray<T>
where
T: NativeType + OverflowingAdd<Output = T> + NotI128,
{
type Output = Self;
fn overflowing_add(&self, rhs: &T) -> Result<(Self::Output, Bitmap)> {
Ok(overflowing_add_scalar(self, rhs))
}
}