use super::odometer::{last_logical_cursor, odometer_step, odometer_step_back, MutableLayoutProof};
use crate::application::index::index_from_flat;
use crate::application::view::{ArrayView, ArrayViewMut};
use crate::domain::error::{LetoError, Result};
use crate::domain::layout::Layout;
pub struct IndexedIter<'a, T, const N: usize> {
data: &'a [T],
layout: Layout<N>,
shape: [usize; N],
front: usize,
back: usize,
front_index: [usize; N],
front_offset: usize,
back_index: [usize; N],
back_offset: usize,
}
impl<'a, T, const N: usize> IndexedIter<'a, T, N> {
#[inline]
pub(crate) fn new(view: &ArrayView<'a, T, N>) -> Self {
let layout = view.layout();
let back = view.size();
let (back_index, back_offset) = last_logical_cursor(&layout, back);
Self {
data: view.data(),
layout,
shape: layout.shape(),
front: 0,
back,
front_index: [0usize; N],
front_offset: layout.offset(),
back_index,
back_offset,
}
}
}
impl<'a, T, const N: usize> Iterator for IndexedIter<'a, T, N> {
type Item = ([usize; N], &'a T);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.front >= self.back {
return None;
}
let index = self.front_index;
let elem = &self.data[self.front_offset];
odometer_step(
&mut self.front_index,
&self.shape,
&self.layout.strides(),
&mut self.front_offset,
);
self.front += 1;
Some((index, elem))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.back - self.front;
(remaining, Some(remaining))
}
}
impl<'a, T, const N: usize> DoubleEndedIterator for IndexedIter<'a, T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.front >= self.back {
return None;
}
self.back -= 1;
let index = self.back_index;
let elem = &self.data[self.back_offset];
odometer_step_back(
&mut self.back_index,
&self.shape,
&self.layout.strides(),
&mut self.back_offset,
);
Some((index, elem))
}
}
impl<'a, T, const N: usize> ExactSizeIterator for IndexedIter<'a, T, N> {}
pub struct IndexedIterMut<'a, T, const N: usize> {
ptr: std::ptr::NonNull<T>,
layout: Layout<N>,
shape: [usize; N],
front: usize,
back: usize,
front_index: [usize; N],
front_offset: usize,
back_index: [usize; N],
back_offset: usize,
_marker: std::marker::PhantomData<&'a mut [T]>,
}
impl<'a, T, const N: usize> IndexedIterMut<'a, T, N> {
pub(crate) fn new(view: ArrayViewMut<'a, T, N>) -> Result<Self> {
let end = view.layout.size();
Self::new_range(view, 0, end)
}
pub(crate) fn new_range(
view: ArrayViewMut<'a, T, N>,
start: usize,
end: usize,
) -> Result<Self> {
Self::from_proof(
MutableLayoutProof::new(
view,
"indexed_iter_mut requires provably disjoint logical offsets",
)?,
start,
end,
)
}
pub(super) fn from_proof(
proof: MutableLayoutProof<'a, T, N>,
start: usize,
end: usize,
) -> Result<Self> {
let MutableLayoutProof {
ptr,
layout,
storage_len: _,
_marker: _,
} = proof;
let size = layout.size();
if start > end || end > size {
return Err(LetoError::OutOfBounds {
index: vec![start, end],
shape: vec![size],
});
}
let (front_index, front_offset, back_index, back_offset) = if start < end {
let front_index = index_from_flat(start, &layout.shape());
let back_index = index_from_flat(end - 1, &layout.shape());
let front_offset = layout
.offset_of(front_index)
.expect("invariant: range start is a valid logical index");
let back_offset = layout
.offset_of(back_index)
.expect("invariant: range end is a valid logical index");
(front_index, front_offset, back_index, back_offset)
} else {
([0usize; N], layout.offset(), [0usize; N], layout.offset())
};
Ok(Self {
ptr,
layout,
shape: layout.shape(),
front: 0,
back: end - start,
front_index,
front_offset,
back_index,
back_offset,
_marker: std::marker::PhantomData,
})
}
}
impl<'a, T, const N: usize> Iterator for IndexedIterMut<'a, T, N> {
type Item = ([usize; N], &'a mut T);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.front >= self.back {
return None;
}
let index = self.front_index;
let offset = self.front_offset;
odometer_step(
&mut self.front_index,
&self.shape,
&self.layout.strides(),
&mut self.front_offset,
);
self.front += 1;
let elem = unsafe { &mut *self.ptr.as_ptr().add(offset) };
Some((index, elem))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.back - self.front;
(remaining, Some(remaining))
}
}
impl<'a, T, const N: usize> DoubleEndedIterator for IndexedIterMut<'a, T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.front >= self.back {
return None;
}
self.back -= 1;
let index = self.back_index;
let offset = self.back_offset;
odometer_step_back(
&mut self.back_index,
&self.shape,
&self.layout.strides(),
&mut self.back_offset,
);
let elem = unsafe { &mut *self.ptr.as_ptr().add(offset) };
Some((index, elem))
}
}
impl<'a, T, const N: usize> ExactSizeIterator for IndexedIterMut<'a, T, N> {}
unsafe impl<T: Send, const N: usize> Send for IndexedIterMut<'_, T, N> {}