use crate::math::vector::scalar::ScalarVector4;
use crate::math::vector::traits::Vector;
#[macro_export]
macro_rules! vec_map {
($input:expr, $output:expr, |$x:ident| $($body:tt)*) => {{
use $crate::math::vector::traits::Vector;
use $crate::math::vector::scalar::ScalarVector4;
const N: usize = 4;
let input: &[_] = $input;
let output: &mut [_] = $output;
assert_eq!(input.len(), output.len(), "input and output slices must have equal length");
if input.is_empty() {
return;
}
let closure = |$x: ScalarVector4<_>| -> ScalarVector4<_> { $($body)* };
let chunks = input.len() / N;
let remainder = input.len() % N;
#[allow(clippy::needless_range_loop)]
for i in 0..chunks {
let start = i * N;
let x = <ScalarVector4<_>>::load(&input[start..start + N]);
let y = closure(x);
y.store(&mut output[start..start + N]);
}
if remainder > 0 {
let start = chunks * N;
let mut temp_input = [Default::default(); 4];
#[allow(clippy::needless_range_loop)]
for i in 0..remainder {
temp_input[i] = input[start + i];
}
let x = <ScalarVector4<_>>::load(&temp_input[0..4]);
let y = closure(x);
#[allow(clippy::needless_range_loop)]
for i in 0..remainder {
output[start + i] = y.extract(i);
}
}
}};
}
pub use crate::vec_map;
#[cfg(test)]
mod tests {
use super::*;
use crate::math::vector::scalar::ScalarVector4;
#[test]
fn test_vec_map_f32() {
let input = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
let mut output = [0.0f32; 8];
vec_map!(&input, &mut output, |x| x * 2.0 + 1.0);
assert_eq!(output[0], 3.0); assert_eq!(output[1], 5.0); assert_eq!(output[2], 7.0);
assert_eq!(output[3], 9.0);
assert_eq!(output[4], 11.0);
assert_eq!(output[5], 13.0);
assert_eq!(output[6], 15.0);
assert_eq!(output[7], 17.0);
}
#[test]
fn test_vec_map_f64() {
let input = [1.0f64, 2.0, 3.0, 4.0];
let mut output = [0.0f64; 4];
vec_map!(&input, &mut output, |x| x * 3.0 - 1.0);
assert_eq!(output[0], 2.0); assert_eq!(output[1], 5.0); assert_eq!(output[2], 8.0);
assert_eq!(output[3], 11.0);
}
#[test]
fn test_vec_map_empty() {
let input: [f32; 0] = [];
let mut output: [f32; 0] = [];
vec_map!(&input, &mut output, |x| x * 2.0); }
#[test]
fn test_vec_map_remainder() {
let input = [1.0f32, 2.0, 3.0]; let mut output = [0.0f32; 3];
vec_map!(&input, &mut output, |x| x + 10.0);
assert_eq!(output[0], 11.0);
assert_eq!(output[1], 12.0);
assert_eq!(output[2], 13.0);
}
}