use super::types::SimdCow;
use crate::align::Alignment;
use crate::arch::SimdArch;
use crate::kernel::SimdKernel;
use crate::scalar::Scalar;
use crate::vec::AlignedVec;
use crate::view::SimdError;
impl<'a, T: 'a, Arch, Align> SimdCow<'a, T, Arch, Align>
where
T: Scalar,
Arch: SimdArch + SimdKernel<T>,
Align: Alignment,
{
#[inline]
pub fn map_unary<Op: crate::ops::UnaryOp<T>>(
&self,
op: Op,
) -> SimdCow<'static, T, Arch, Align> {
self.map_cow(op)
}
#[inline]
pub fn map_unary_in_place<Op: crate::ops::UnaryOp<T>>(&mut self, op: Op) {
self.view_mut().map_unary_in_place(op);
}
#[inline]
pub fn scale_in_place(&mut self, scalar: T) {
let len = self.len();
if len == 0 {
return;
}
let lane_count = Arch::LANE_COUNT;
let simd_len = (len / lane_count) * lane_count;
let vec = self.to_mut();
let ptr = vec.as_mut_ptr();
unsafe {
let vsplat = Arch::splat(scalar);
let load = |p: *const T| -> Arch::Vector {
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::load_aligned(p)
} else {
Arch::load_unaligned(p)
}
};
let store = |p: *mut T, v: Arch::Vector| {
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::store_aligned(p, v);
} else {
Arch::store_unaligned(p, v);
}
};
let mut i = 0usize;
while i < simd_len {
let p = ptr.add(i);
let v = load(p);
store(p, Arch::mul(v, vsplat));
i += lane_count;
}
}
let slice = vec.as_mut_slice();
for i in simd_len..len {
slice[i] = slice[i] * scalar;
}
}
#[inline]
pub fn scale(&self, scalar: T) -> SimdCow<'static, T, Arch, Align> {
self.mul_scalar_cow(scalar)
}
#[inline]
pub fn splat_fill(value: T, len: usize) -> SimdCow<'static, T, Arch, Align> {
let mut out: AlignedVec<T, Align> = AlignedVec::with_capacity(len);
let lane_count = Arch::LANE_COUNT;
let simd_len = (len / lane_count) * lane_count;
let ptr = out.as_mut_ptr();
unsafe {
let vsplat = Arch::splat(value);
let mut i = 0usize;
while i < simd_len {
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::store_aligned(ptr.add(i), vsplat);
} else {
Arch::store_unaligned(ptr.add(i), vsplat);
}
i += lane_count;
}
for i in simd_len..len {
core::ptr::write(ptr.add(i), value);
}
out.set_len(len);
}
SimdCow::Owned(out)
}
#[inline]
pub fn zeros(len: usize) -> SimdCow<'static, T, Arch, Align> {
Self::splat_fill(T::ZERO, len)
}
#[inline]
pub fn ones(len: usize) -> SimdCow<'static, T, Arch, Align> {
Self::splat_fill(T::ONE, len)
}
#[inline]
pub fn argmin(&self) -> Option<(usize, T)>
where
T: crate::scalar::NumericElement,
{
self.view().argmin()
}
#[inline]
pub fn argmax(&self) -> Option<(usize, T)>
where
T: crate::scalar::NumericElement,
{
self.view().argmax()
}
#[inline]
pub fn gather(&self, indices: &[i32]) -> Result<SimdCow<'static, T, Arch, Align>, SimdError> {
let len = indices.len();
let mut out = AlignedVec::with_capacity(len);
self.view()
.gather_into_uninit(indices, out.spare_capacity_mut())?;
unsafe { out.set_len(len) };
Ok(SimdCow::Owned(out))
}
#[inline]
pub fn prefix_scan<Op, SMode>(
&self,
op: Op,
mode: SMode,
) -> Result<SimdCow<'static, T, Arch, Align>, SimdError>
where
Op: crate::ops::ScanOp<T>,
SMode: crate::ops::ScanMode,
{
let len = self.len();
let mut out = AlignedVec::with_capacity(len);
self.view()
.prefix_scan_into_uninit(out.spare_capacity_mut(), op, mode)?;
unsafe { out.set_len(len) };
Ok(SimdCow::Owned(out))
}
#[inline]
pub fn prefix_scan_in_place<Op, SMode>(&mut self, op: Op, mode: SMode) -> Result<(), SimdError>
where
Op: crate::ops::ScanOp<T>,
SMode: crate::ops::ScanMode,
{
self.view_mut().prefix_scan_in_place(op, mode);
Ok(())
}
}