use super::traits::*;
use crate::Transcendental;
use std::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
pub fn add_slices<T: Transcendental, const N: usize, V>(a: &[T], b: &[T], out: &mut [T])
where
V: Vector<T, N>,
{
assert_eq!(a.len(), b.len());
assert_eq!(a.len(), out.len());
let chunks = a.len() / N;
let remainder = a.len() % N;
for i in 0..chunks {
let start = i * N;
let a_vec = V::load(&a[start..start + N]);
let b_vec = V::load(&b[start..start + N]);
let result = a_vec + b_vec;
result.store(&mut out[start..start + N]);
}
if remainder > 0 {
let start = chunks * N;
for i in 0..remainder {
out[start + i] = a[start + i] + b[start + i];
}
}
}
pub fn sub_slices<T: Transcendental, const N: usize, V>(a: &[T], b: &[T], out: &mut [T])
where
V: Vector<T, N>,
{
assert_eq!(a.len(), b.len());
assert_eq!(a.len(), out.len());
let chunks = a.len() / N;
let remainder = a.len() % N;
for i in 0..chunks {
let start = i * N;
let a_vec = V::load(&a[start..start + N]);
let b_vec = V::load(&b[start..start + N]);
let result = a_vec - b_vec;
result.store(&mut out[start..start + N]);
}
if remainder > 0 {
let start = chunks * N;
for i in 0..remainder {
out[start + i] = a[start + i] - b[start + i];
}
}
}
pub fn mul_slices<T: Transcendental, const N: usize, V>(a: &[T], b: &[T], out: &mut [T])
where
V: Vector<T, N>,
{
assert_eq!(a.len(), b.len());
assert_eq!(a.len(), out.len());
let chunks = a.len() / N;
let remainder = a.len() % N;
for i in 0..chunks {
let start = i * N;
let a_vec = V::load(&a[start..start + N]);
let b_vec = V::load(&b[start..start + N]);
let result = a_vec * b_vec;
result.store(&mut out[start..start + N]);
}
if remainder > 0 {
let start = chunks * N;
for i in 0..remainder {
out[start + i] = a[start + i] * b[start + i];
}
}
}
pub fn div_slices<T: Transcendental, const N: usize, V>(a: &[T], b: &[T], out: &mut [T])
where
V: Vector<T, N>,
{
assert_eq!(a.len(), b.len());
assert_eq!(a.len(), out.len());
let chunks = a.len() / N;
let remainder = a.len() % N;
for i in 0..chunks {
let start = i * N;
let a_vec = V::load(&a[start..start + N]);
let b_vec = V::load(&b[start..start + N]);
let result = a_vec / b_vec;
result.store(&mut out[start..start + N]);
}
if remainder > 0 {
let start = chunks * N;
for i in 0..remainder {
out[start + i] = a[start + i] / b[start + i];
}
}
}
pub fn mul_scalar_slice<T: Transcendental, const N: usize, V>(a: &[T], scalar: T, out: &mut [T])
where
V: Vector<T, N>,
{
assert_eq!(a.len(), out.len());
let scalar_vec = V::splat(scalar);
let chunks = a.len() / N;
let remainder = a.len() % N;
for i in 0..chunks {
let start = i * N;
let a_vec = V::load(&a[start..start + N]);
let result = a_vec * scalar_vec;
result.store(&mut out[start..start + N]);
}
if remainder > 0 {
let start = chunks * N;
for i in 0..remainder {
out[start + i] = a[start + i] * scalar;
}
}
}
pub fn add_scalar_slice<T: Transcendental, const N: usize, V>(a: &[T], scalar: T, out: &mut [T])
where
V: Vector<T, N>,
{
assert_eq!(a.len(), out.len());
let scalar_vec = V::splat(scalar);
let chunks = a.len() / N;
let remainder = a.len() % N;
for i in 0..chunks {
let start = i * N;
let a_vec = V::load(&a[start..start + N]);
let result = a_vec + scalar_vec;
result.store(&mut out[start..start + N]);
}
if remainder > 0 {
let start = chunks * N;
for i in 0..remainder {
out[start + i] = a[start + i] + scalar;
}
}
}
#[derive(Debug)]
pub struct SliceMut<'a, T>(pub &'a mut [T]);
impl<'a, T: Transcendental> SliceMut<'a, T> {
#[inline(always)]
pub fn new(slice: &'a mut [T]) -> Self {
Self(slice)
}
#[inline(always)]
pub fn into_inner(self) -> &'a mut [T] {
self.0
}
}
impl<'a, T: Transcendental> AddAssign<&[T]> for SliceMut<'a, T> {
fn add_assign(&mut self, rhs: &[T]) {
for (a, &b) in self.0.iter_mut().zip(rhs.iter()) {
*a += b;
}
}
}
impl<'a, T: Transcendental> SubAssign<&[T]> for SliceMut<'a, T> {
fn sub_assign(&mut self, rhs: &[T]) {
for (a, &b) in self.0.iter_mut().zip(rhs.iter()) {
*a -= b;
}
}
}
impl<'a, T: Transcendental> MulAssign<&[T]> for SliceMut<'a, T> {
fn mul_assign(&mut self, rhs: &[T]) {
for (a, &b) in self.0.iter_mut().zip(rhs.iter()) {
*a *= b;
}
}
}
impl<'a, T: Transcendental> DivAssign<&[T]> for SliceMut<'a, T> {
fn div_assign(&mut self, rhs: &[T]) {
for (a, &b) in self.0.iter_mut().zip(rhs.iter()) {
*a /= b;
}
}
}
impl<'a, T: Transcendental> AddAssign<T> for SliceMut<'a, T> {
fn add_assign(&mut self, rhs: T) {
for v in self.0.iter_mut() {
*v = *v + rhs;
}
}
}
impl<'a, T: Transcendental> SubAssign<T> for SliceMut<'a, T> {
fn sub_assign(&mut self, rhs: T) {
for v in self.0.iter_mut() {
*v = *v - rhs;
}
}
}
impl<'a, T: Transcendental> MulAssign<T> for SliceMut<'a, T> {
fn mul_assign(&mut self, rhs: T) {
for v in self.0.iter_mut() {
*v = *v * rhs;
}
}
}
impl<'a, T: Transcendental> DivAssign<T> for SliceMut<'a, T> {
fn div_assign(&mut self, rhs: T) {
for v in self.0.iter_mut() {
*v = *v / rhs;
}
}
}
pub struct SlicePair<'a, T>(pub &'a [T], pub &'a [T]);
impl<'a, T: Transcendental> SlicePair<'a, T> {
#[inline(always)]
pub fn new(a: &'a [T], b: &'a [T]) -> Self {
Self(a, b)
}
#[inline(always)]
pub fn add_into<const N: usize, V: Vector<T, N>>(self, out: &mut [T]) {
add_slices::<T, N, V>(self.0, self.1, out)
}
#[inline(always)]
pub fn sub_into<const N: usize, V: Vector<T, N>>(self, out: &mut [T]) {
sub_slices::<T, N, V>(self.0, self.1, out)
}
#[inline(always)]
pub fn mul_into<const N: usize, V: Vector<T, N>>(self, out: &mut [T]) {
mul_slices::<T, N, V>(self.0, self.1, out)
}
#[inline(always)]
pub fn div_into<const N: usize, V: Vector<T, N>>(self, out: &mut [T]) {
div_slices::<T, N, V>(self.0, self.1, out)
}
pub fn rem_into<const N: usize, V: Vector<T, N>>(self, out: &mut [T]) {
for (o, (&a, &b)) in out.iter_mut().zip(self.0.iter().zip(self.1.iter())) {
*o = a % b;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
}