use crate::align::Alignment;
use crate::arch::SimdArch;
use crate::execution::ExecutionMode;
use crate::kernel::SimdKernel;
use crate::scalar::Scalar;
use crate::view::SimdView;
use core::marker::PhantomData;
pub struct SimdChunks<'a, T: 'a, Arch: SimdArch, Align: Alignment, Mode: ExecutionMode> {
base: *const T,
pos: usize,
total: usize,
simd_end: usize,
_marker: PhantomData<(&'a T, Arch, Align, Mode)>,
}
unsafe impl<
'a,
T: Send,
Arch: SimdArch + crate::kernel::SimdKernel<T>,
Align: Alignment,
Mode: ExecutionMode,
> Send for SimdChunks<'a, T, Arch, Align, Mode>
where
T: crate::scalar::Scalar,
{
}
unsafe impl<
'a,
T: Sync,
Arch: SimdArch + crate::kernel::SimdKernel<T>,
Align: Alignment,
Mode: ExecutionMode,
> Sync for SimdChunks<'a, T, Arch, Align, Mode>
where
T: crate::scalar::Scalar,
{
}
impl<
'a,
T: 'a,
Arch: SimdArch + crate::kernel::SimdKernel<T>,
Align: Alignment,
Mode: ExecutionMode,
> SimdChunks<'a, T, Arch, Align, Mode>
where
T: crate::scalar::Scalar,
{
#[inline]
pub(crate) unsafe fn from_raw_parts(base: *const T, total: usize, lane_count: usize) -> Self {
let simd_end = (total / lane_count) * lane_count;
Self {
base,
pos: 0,
total,
simd_end,
_marker: PhantomData,
}
}
#[inline(always)]
pub fn remainder(&self) -> &'a [T] {
unsafe {
core::slice::from_raw_parts(self.base.add(self.simd_end), self.total - self.simd_end)
}
}
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
SimdChunks<'a, T, Arch, Align, Mode>
{
#[inline(always)]
pub fn chunks_remaining(&self) -> usize {
if self.simd_end > self.pos {
(self.simd_end - self.pos) / Arch::LANE_COUNT
} else {
0
}
}
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
Iterator for SimdChunks<'a, T, Arch, Align, Mode>
{
type Item = SimdView<'a, T, Arch, Align, Mode, &'a [T]>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.simd_end {
return None;
}
let chunk_slice =
unsafe { core::slice::from_raw_parts(self.base.add(self.pos), Arch::LANE_COUNT) };
self.pos += Arch::LANE_COUNT;
Some(SimdView::new(chunk_slice).expect("chunk alignment invariant violated"))
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.chunks_remaining();
(remaining, Some(remaining))
}
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
ExactSizeIterator for SimdChunks<'a, T, Arch, Align, Mode>
{
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
DoubleEndedIterator for SimdChunks<'a, T, Arch, Align, Mode>
{
#[inline(always)]
fn next_back(&mut self) -> Option<Self::Item> {
if self.pos >= self.simd_end {
return None;
}
self.simd_end -= Arch::LANE_COUNT;
let chunk_slice =
unsafe { core::slice::from_raw_parts(self.base.add(self.simd_end), Arch::LANE_COUNT) };
Some(SimdView::new(chunk_slice).expect("chunk alignment invariant violated"))
}
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
core::iter::FusedIterator for SimdChunks<'a, T, Arch, Align, Mode>
{
}
pub struct SimdChunksMut<'a, T: 'a, Arch: SimdArch, Align: Alignment, Mode: ExecutionMode> {
base: *mut T,
pos: usize,
total: usize,
simd_end: usize,
_marker: PhantomData<(&'a mut T, Arch, Align, Mode)>,
}
unsafe impl<
'a,
T: Send,
Arch: SimdArch + crate::kernel::SimdKernel<T>,
Align: Alignment,
Mode: ExecutionMode,
> Send for SimdChunksMut<'a, T, Arch, Align, Mode>
where
T: crate::scalar::Scalar,
{
}
unsafe impl<
'a,
T: Sync,
Arch: SimdArch + crate::kernel::SimdKernel<T>,
Align: Alignment,
Mode: ExecutionMode,
> Sync for SimdChunksMut<'a, T, Arch, Align, Mode>
where
T: crate::scalar::Scalar,
{
}
impl<
'a,
T: 'a,
Arch: SimdArch + crate::kernel::SimdKernel<T>,
Align: Alignment,
Mode: ExecutionMode,
> SimdChunksMut<'a, T, Arch, Align, Mode>
where
T: crate::scalar::Scalar,
{
#[inline]
pub(crate) unsafe fn from_raw_parts(base: *mut T, total: usize, lane_count: usize) -> Self {
let simd_end = (total / lane_count) * lane_count;
Self {
base,
pos: 0,
total,
simd_end,
_marker: PhantomData,
}
}
#[inline(always)]
pub fn into_remainder(self) -> &'a mut [T] {
unsafe {
core::slice::from_raw_parts_mut(
self.base.add(self.simd_end),
self.total - self.simd_end,
)
}
}
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
SimdChunksMut<'a, T, Arch, Align, Mode>
{
#[inline(always)]
pub fn chunks_remaining(&self) -> usize {
if self.simd_end > self.pos {
(self.simd_end - self.pos) / Arch::LANE_COUNT
} else {
0
}
}
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
Iterator for SimdChunksMut<'a, T, Arch, Align, Mode>
{
type Item = SimdView<'a, T, Arch, Align, Mode, &'a mut [T]>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
if self.pos >= self.simd_end {
return None;
}
let chunk_slice =
unsafe { core::slice::from_raw_parts_mut(self.base.add(self.pos), Arch::LANE_COUNT) };
self.pos += Arch::LANE_COUNT;
Some(SimdView::new_mut(chunk_slice).expect("chunk alignment invariant violated"))
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.chunks_remaining();
(remaining, Some(remaining))
}
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
ExactSizeIterator for SimdChunksMut<'a, T, Arch, Align, Mode>
{
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
DoubleEndedIterator for SimdChunksMut<'a, T, Arch, Align, Mode>
{
#[inline(always)]
fn next_back(&mut self) -> Option<Self::Item> {
if self.pos >= self.simd_end {
return None;
}
self.simd_end -= Arch::LANE_COUNT;
let chunk_slice = unsafe {
core::slice::from_raw_parts_mut(self.base.add(self.simd_end), Arch::LANE_COUNT)
};
Some(SimdView::new_mut(chunk_slice).expect("chunk alignment invariant violated"))
}
}
impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
core::iter::FusedIterator for SimdChunksMut<'a, T, Arch, Align, Mode>
{
}