use crate::align::Alignment;
use crate::arch::SimdArch;
use crate::execution::ExecutionMode;
use crate::kernel::SimdKernel;
use crate::scalar::Scalar;
use crate::vec::AlignedVec;
use crate::view::{SimdError, SimdView};
impl<'a, T: 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode, Ref: 'a>
SimdView<'a, T, Arch, Align, Mode, Ref>
where
T: Scalar,
{
pub fn select<ORef>(
&self,
mask: &[bool],
other: &SimdView<'_, T, Arch, Align, Mode, ORef>,
) -> Result<AlignedVec<T, Align>, SimdError>
where
ORef: 'a,
{
super::check_lengths_equal(self.len(), other.len())?;
if mask.len() < self.len() {
return Err(SimdError::InsufficientOutputLength);
}
let a = self.as_slice();
let b = other.as_slice();
let len = a.len();
let mut out: AlignedVec<T, Align> = AlignedVec::with_capacity(len);
unsafe {
out.set_len(len);
}
let out_slice = out.as_mut_slice();
let lane_count = Arch::LANE_COUNT;
let mut i = 0;
unsafe {
while i + lane_count <= len {
let m = Arch::mask_from_bools(&mask[i..i + lane_count]);
let vb = if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::load_aligned(b.as_ptr().add(i))
} else {
Arch::load_unaligned(b.as_ptr().add(i))
};
let v_res = Arch::masked_load_unaligned(a.as_ptr().add(i), m, vb);
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::store_aligned(out_slice.as_mut_ptr().add(i), v_res);
} else {
Arch::store_unaligned(out_slice.as_mut_ptr().add(i), v_res);
}
i += lane_count;
}
}
for j in i..len {
out_slice[j] = if mask[j] { a[j] } else { b[j] };
}
Ok(out)
}
pub fn masked_negate(&self, mask: &[bool]) -> Result<AlignedVec<T, Align>, SimdError>
where
T: core::ops::Neg<Output = T>,
{
if mask.len() < self.len() {
return Err(SimdError::InsufficientOutputLength);
}
let data = self.as_slice();
let len = data.len();
let mut out: AlignedVec<T, Align> = AlignedVec::with_capacity(len);
unsafe {
out.set_len(len);
}
let out_slice = out.as_mut_slice();
let lane_count = Arch::LANE_COUNT;
let mut i = 0;
unsafe {
while i + lane_count <= len {
let v = if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::load_aligned(data.as_ptr().add(i))
} else {
Arch::load_unaligned(data.as_ptr().add(i))
};
let m = Arch::mask_from_bools(&mask[i..i + lane_count]);
let vmask = Arch::mask_to_vector(m);
let neg_v = Arch::neg(v);
let v_res = Arch::blend(vmask, neg_v, v);
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::store_aligned(out_slice.as_mut_ptr().add(i), v_res);
} else {
Arch::store_unaligned(out_slice.as_mut_ptr().add(i), v_res);
}
i += lane_count;
}
}
for j in i..len {
out_slice[j] = if mask[j] { -data[j] } else { data[j] };
}
Ok(out)
}
}