use crate::Bitmask;
use crate::enums::operators::ArithmeticOperator;
use num_traits::{Float, PrimInt, ToPrimitive, WrappingAdd, WrappingMul, WrappingSub};
#[inline(always)]
pub fn int_dense_body_std<T: PrimInt + ToPrimitive + WrappingAdd + WrappingSub + WrappingMul>(
op: ArithmeticOperator,
lhs: &[T],
rhs: &[T],
out: &mut [T],
) {
let n = lhs.len();
macro_rules! run {
(|$x:ident, $y:ident| $scalar:expr) => {{
for i in 0..n {
let $x = lhs[i];
let $y = rhs[i];
out[i] = $scalar;
}
}};
}
match op {
ArithmeticOperator::Add => run!(|x, y| x.wrapping_add(&y)),
ArithmeticOperator::Subtract => run!(|x, y| x.wrapping_sub(&y)),
ArithmeticOperator::Multiply => run!(|x, y| x.wrapping_mul(&y)),
ArithmeticOperator::Divide => run!(|x, y| {
if y == T::zero() {
panic!("Division by zero")
} else {
x / y
}
}),
ArithmeticOperator::Remainder => run!(|x, y| {
if y == T::zero() {
panic!("Remainder by zero")
} else {
x % y
}
}),
ArithmeticOperator::Power => run!(|x, y| x.pow(y.to_u32().unwrap_or(0))),
ArithmeticOperator::FloorDiv => run!(|x, y| {
if y == T::zero() {
panic!("Floor division by zero")
} else {
let d = x / y;
let r = x % y;
if r != T::zero() && (x ^ y) < T::zero() {
d - T::one()
} else {
d
}
}
}),
}
}
#[inline(always)]
pub fn int_masked_body_std<T: PrimInt + ToPrimitive + WrappingAdd + WrappingSub + WrappingMul>(
op: ArithmeticOperator,
lhs: &[T],
rhs: &[T],
mask: &Bitmask,
out: &mut [T],
out_mask: &mut Bitmask,
) {
let n = lhs.len();
macro_rules! run {
(|$x:ident, $y:ident| $scalar:expr) => {{
for i in 0..n {
let valid = unsafe { mask.get_unchecked(i) };
if valid {
let $x = lhs[i];
let $y = rhs[i];
let (result, final_valid) = $scalar;
out[i] = result;
unsafe {
out_mask.set_unchecked(i, final_valid);
}
} else {
out[i] = T::zero();
unsafe {
out_mask.set_unchecked(i, false);
}
}
}
}};
}
match op {
ArithmeticOperator::Add => run!(|x, y| (x.wrapping_add(&y), true)),
ArithmeticOperator::Subtract => run!(|x, y| (x.wrapping_sub(&y), true)),
ArithmeticOperator::Multiply => run!(|x, y| (x.wrapping_mul(&y), true)),
ArithmeticOperator::Divide => run!(|x, y| {
if y == T::zero() {
(T::zero(), false) } else {
(x / y, true)
}
}),
ArithmeticOperator::Remainder => run!(|x, y| {
if y == T::zero() {
(T::zero(), false) } else {
(x % y, true)
}
}),
ArithmeticOperator::Power => run!(|x, y| (x.pow(y.to_u32().unwrap_or(0)), true)),
ArithmeticOperator::FloorDiv => run!(|x, y| {
if y == T::zero() {
(T::zero(), false)
} else {
let d = x / y;
let r = x % y;
if r != T::zero() && (x ^ y) < T::zero() {
(d - T::one(), true)
} else {
(d, true)
}
}
}),
}
}
#[inline(always)]
pub fn float_dense_body_std<T: Float>(op: ArithmeticOperator, lhs: &[T], rhs: &[T], out: &mut [T]) {
let n = lhs.len();
macro_rules! run {
(|$x:ident, $y:ident| $scalar:expr) => {{
for i in 0..n {
let $x = lhs[i];
let $y = rhs[i];
out[i] = $scalar;
}
}};
}
match op {
ArithmeticOperator::Add => run!(|x, y| x + y),
ArithmeticOperator::Subtract => run!(|x, y| x - y),
ArithmeticOperator::Multiply => run!(|x, y| x * y),
ArithmeticOperator::Divide => run!(|x, y| x / y),
ArithmeticOperator::Remainder => run!(|x, y| x % y),
ArithmeticOperator::Power => run!(|x, y| (y * x.ln()).exp()),
ArithmeticOperator::FloorDiv => run!(|x, y| (x / y).floor()),
}
}
#[inline(always)]
pub fn float_masked_body_std<T: Float>(
op: ArithmeticOperator,
lhs: &[T],
rhs: &[T],
mask: &Bitmask,
out: &mut [T],
out_mask: &mut Bitmask,
) {
let n = lhs.len();
macro_rules! run {
(|$x:ident, $y:ident| $scalar:expr) => {{
for i in 0..n {
let valid = unsafe { mask.get_unchecked(i) };
if valid {
let $x = lhs[i];
let $y = rhs[i];
out[i] = $scalar;
unsafe {
out_mask.set_unchecked(i, true);
}
} else {
out[i] = T::zero();
unsafe {
out_mask.set_unchecked(i, false);
}
}
}
}};
}
match op {
ArithmeticOperator::Add => run!(|x, y| x + y),
ArithmeticOperator::Subtract => run!(|x, y| x - y),
ArithmeticOperator::Multiply => run!(|x, y| x * y),
ArithmeticOperator::Divide => run!(|x, y| x / y),
ArithmeticOperator::Remainder => run!(|x, y| x % y),
ArithmeticOperator::Power => run!(|x, y| (y * x.ln()).exp()),
ArithmeticOperator::FloorDiv => run!(|x, y| (x / y).floor()),
}
}
#[inline(always)]
pub fn fma_masked_body_std<T: Float>(
lhs: &[T],
rhs: &[T],
acc: &[T],
mask: &Bitmask,
out: &mut [T],
out_mask: &mut Bitmask,
) {
let n = lhs.len();
for i in 0..n {
let valid = unsafe { mask.get_unchecked(i) };
if valid {
out[i] = lhs[i].mul_add(rhs[i], acc[i]);
unsafe {
out_mask.set_unchecked(i, true);
}
} else {
out[i] = T::zero();
unsafe {
out_mask.set_unchecked(i, false);
}
}
}
}
#[inline(always)]
pub fn fma_dense_body_std<T: Float>(lhs: &[T], rhs: &[T], acc: &[T], out: &mut [T]) {
let n = lhs.len();
for i in 0..n {
out[i] = lhs[i].mul_add(rhs[i], acc[i]);
}
}