pub mod basic;
pub mod decimal;
pub mod time;
use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
use num_traits::{CheckedNeg, NumCast, WrappingNeg, Zero};
use crate::datatypes::{DataType, IntervalUnit, TimeUnit};
use crate::error::{ArrowError, Result};
use crate::types::NativeType;
use crate::{array::*, bitmap::Bitmap};
use super::arity::{unary, unary_checked};
macro_rules! primitive {
($lhs: expr, $rhs: expr, $op: expr, $array_type: ty) => {{
let res_lhs = $lhs.as_any().downcast_ref().unwrap();
let res_rhs = $rhs.as_any().downcast_ref().unwrap();
arithmetic_primitive::<$array_type>(res_lhs, $op, res_rhs)
.map(Box::new)
.map(|x| x as Box<dyn Array>)
}};
}
pub fn arithmetic(lhs: &dyn Array, op: Operator, rhs: &dyn Array) -> Result<Box<dyn Array>> {
use DataType::*;
use Operator::*;
match (lhs.data_type(), op, rhs.data_type()) {
(Int8, _, Int8) => primitive!(lhs, rhs, op, i8),
(Int16, _, Int16) => primitive!(lhs, rhs, op, i16),
(Int32, _, Int32) => primitive!(lhs, rhs, op, i32),
(Int64, _, Int64) | (Duration(_), _, Duration(_)) => {
primitive!(lhs, rhs, op, i64)
}
(UInt8, _, UInt8) => primitive!(lhs, rhs, op, u8),
(UInt16, _, UInt16) => primitive!(lhs, rhs, op, u16),
(UInt32, _, UInt32) => primitive!(lhs, rhs, op, u32),
(UInt64, _, UInt64) => primitive!(lhs, rhs, op, u64),
(Float32, _, Float32) => primitive!(lhs, rhs, op, f32),
(Float64, _, Float64) => primitive!(lhs, rhs, op, f64),
(Decimal(_, _), _, Decimal(_, _)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
let res = match op {
Add => decimal::add::add(lhs, rhs),
Subtract => decimal::sub::sub(lhs, rhs),
Multiply => decimal::mul::mul(lhs, rhs),
Divide => decimal::div::div(lhs, rhs),
Remainder => {
return Err(ArrowError::NotYetImplemented(format!(
"Arithmetics of ({:?}, {:?}, {:?}) is not supported",
lhs, op, rhs
)))
}
};
res.map(|x| Box::new(x) as Box<dyn Array>)
}
(Time32(TimeUnit::Second), Add, Duration(_))
| (Time32(TimeUnit::Millisecond), Add, Duration(_))
| (Date32, Add, Duration(_)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::add_duration::<i32>(lhs, rhs).map(|x| Box::new(x) as Box<dyn Array>)
}
(Time32(TimeUnit::Second), Subtract, Duration(_))
| (Time32(TimeUnit::Millisecond), Subtract, Duration(_))
| (Date32, Subtract, Duration(_)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::subtract_duration::<i32>(lhs, rhs).map(|x| Box::new(x) as Box<dyn Array>)
}
(Time64(TimeUnit::Microsecond), Add, Duration(_))
| (Time64(TimeUnit::Nanosecond), Add, Duration(_))
| (Date64, Add, Duration(_))
| (Timestamp(_, _), Add, Duration(_)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::add_duration::<i64>(lhs, rhs).map(|x| Box::new(x) as Box<dyn Array>)
}
(Timestamp(_, _), Add, Interval(IntervalUnit::MonthDayNano)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::add_interval(lhs, rhs).map(|x| Box::new(x) as Box<dyn Array>)
}
(Time64(TimeUnit::Microsecond), Subtract, Duration(_))
| (Time64(TimeUnit::Nanosecond), Subtract, Duration(_))
| (Date64, Subtract, Duration(_))
| (Timestamp(_, _), Subtract, Duration(_)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::subtract_duration::<i64>(lhs, rhs).map(|x| Box::new(x) as Box<dyn Array>)
}
(Timestamp(_, None), Subtract, Timestamp(_, None)) => {
let lhs = lhs.as_any().downcast_ref().unwrap();
let rhs = rhs.as_any().downcast_ref().unwrap();
time::subtract_timestamps(lhs, rhs).map(|x| Box::new(x) as Box<dyn Array>)
}
(lhs, op, rhs) => Err(ArrowError::NotYetImplemented(format!(
"Arithmetics of ({:?}, {:?}, {:?}) is not supported",
lhs, op, rhs
))),
}
}
pub fn can_arithmetic(lhs: &DataType, op: Operator, rhs: &DataType) -> bool {
use DataType::*;
use Operator::*;
if let (Decimal(_, _), Remainder, Decimal(_, _)) = (lhs, op, rhs) {
return false;
};
matches!(
(lhs, op, rhs),
(Int8, _, Int8)
| (Int16, _, Int16)
| (Int32, _, Int32)
| (Int64, _, Int64)
| (UInt8, _, UInt8)
| (UInt16, _, UInt16)
| (UInt32, _, UInt32)
| (UInt64, _, UInt64)
| (Float64, _, Float64)
| (Float32, _, Float32)
| (Duration(_), _, Duration(_))
| (Decimal(_, _), _, Decimal(_, _))
| (Date32, Subtract, Duration(_))
| (Date32, Add, Duration(_))
| (Date64, Subtract, Duration(_))
| (Date64, Add, Duration(_))
| (Time32(TimeUnit::Millisecond), Subtract, Duration(_))
| (Time32(TimeUnit::Second), Subtract, Duration(_))
| (Time32(TimeUnit::Millisecond), Add, Duration(_))
| (Time32(TimeUnit::Second), Add, Duration(_))
| (Time64(TimeUnit::Microsecond), Subtract, Duration(_))
| (Time64(TimeUnit::Nanosecond), Subtract, Duration(_))
| (Time64(TimeUnit::Microsecond), Add, Duration(_))
| (Time64(TimeUnit::Nanosecond), Add, Duration(_))
| (Timestamp(_, _), Subtract, Duration(_))
| (Timestamp(_, _), Add, Duration(_))
| (Timestamp(_, _), Add, Interval(IntervalUnit::MonthDayNano))
| (Timestamp(_, None), Subtract, Timestamp(_, None))
)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Operator {
Add,
Subtract,
Multiply,
Divide,
Remainder,
}
pub fn arithmetic_primitive<T>(
lhs: &PrimitiveArray<T>,
op: Operator,
rhs: &PrimitiveArray<T>,
) -> Result<PrimitiveArray<T>>
where
T: NativeType
+ Div<Output = T>
+ Zero
+ Add<Output = T>
+ Sub<Output = T>
+ Mul<Output = T>
+ Rem<Output = T>,
{
match op {
Operator::Add => basic::add(lhs, rhs),
Operator::Subtract => basic::sub(lhs, rhs),
Operator::Multiply => basic::mul(lhs, rhs),
Operator::Divide => basic::div(lhs, rhs),
Operator::Remainder => basic::rem(lhs, rhs),
}
}
pub fn arithmetic_primitive_scalar<T>(
lhs: &PrimitiveArray<T>,
op: Operator,
rhs: &T,
) -> Result<PrimitiveArray<T>>
where
T: NativeType
+ Div<Output = T>
+ Zero
+ Add<Output = T>
+ Sub<Output = T>
+ Mul<Output = T>
+ Rem<Output = T>
+ NumCast,
{
match op {
Operator::Add => Ok(basic::add_scalar(lhs, rhs)),
Operator::Subtract => Ok(basic::sub_scalar(lhs, rhs)),
Operator::Multiply => Ok(basic::mul_scalar(lhs, rhs)),
Operator::Divide => Ok(basic::div_scalar(lhs, rhs)),
Operator::Remainder => Ok(basic::rem_scalar(lhs, rhs)),
}
}
pub fn negate<T>(array: &PrimitiveArray<T>) -> PrimitiveArray<T>
where
T: NativeType + Neg<Output = T>,
{
unary(array, |a| -a, array.data_type().clone())
}
pub fn checked_negate<T>(array: &PrimitiveArray<T>) -> PrimitiveArray<T>
where
T: NativeType + CheckedNeg,
{
unary_checked(array, |a| a.checked_neg(), array.data_type().clone())
}
pub fn wrapping_negate<T>(array: &PrimitiveArray<T>) -> PrimitiveArray<T>
where
T: NativeType + WrappingNeg,
{
unary(array, |a| a.wrapping_neg(), array.data_type().clone())
}
pub trait ArrayAdd<Rhs> {
type Output;
fn add(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayWrappingAdd<Rhs> {
type Output;
fn wrapping_add(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayCheckedAdd<Rhs> {
type Output;
fn checked_add(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArraySaturatingAdd<Rhs> {
type Output;
fn saturating_add(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayOverflowingAdd<Rhs> {
type Output;
fn overflowing_add(&self, rhs: &Rhs) -> Result<(Self::Output, Bitmap)>;
}
pub trait ArraySub<Rhs> {
type Output;
fn sub(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayWrappingSub<Rhs> {
type Output;
fn wrapping_sub(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayCheckedSub<Rhs> {
type Output;
fn checked_sub(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArraySaturatingSub<Rhs> {
type Output;
fn saturating_sub(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayOverflowingSub<Rhs> {
type Output;
fn overflowing_sub(&self, rhs: &Rhs) -> Result<(Self::Output, Bitmap)>;
}
pub trait ArrayMul<Rhs> {
type Output;
fn mul(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayWrappingMul<Rhs> {
type Output;
fn wrapping_mul(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayCheckedMul<Rhs> {
type Output;
fn checked_mul(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArraySaturatingMul<Rhs> {
type Output;
fn saturating_mul(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayOverflowingMul<Rhs> {
type Output;
fn overflowing_mul(&self, rhs: &Rhs) -> Result<(Self::Output, Bitmap)>;
}
pub trait ArrayDiv<Rhs> {
type Output;
fn div(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayCheckedDiv<Rhs> {
type Output;
fn checked_div(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayRem<Rhs> {
type Output;
fn rem(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub trait ArrayCheckedRem<Rhs> {
type Output;
fn checked_rem(&self, rhs: &Rhs) -> Result<Self::Output>;
}
pub unsafe trait NotI128 {}
unsafe impl NotI128 for u8 {}
unsafe impl NotI128 for u16 {}
unsafe impl NotI128 for u32 {}
unsafe impl NotI128 for u64 {}
unsafe impl NotI128 for i8 {}
unsafe impl NotI128 for i16 {}
unsafe impl NotI128 for i32 {}
unsafe impl NotI128 for i64 {}
unsafe impl NotI128 for f32 {}
unsafe impl NotI128 for f64 {}