#[doc = crate::_tags!(iterator)]
#[doc = crate::_doc_location!("data/access/iter")]
#[macro_export]
#[cfg_attr(cargo_primary_package, doc(hidden))]
macro_rules! iter_strided {
(
$(#[$attr:meta])* $vis:vis struct $name:ident : mut ($P:ty)
) => {
$crate::iter_strided!(%mut $(#[$attr])* $vis $name, $P, $crate::NonZero<$P>);
};
(
$(#[$attr:meta])* $vis:vis struct $name:ident : ref ($P:ty)
) => {
$crate::iter_strided!(%ref $(#[$attr])* $vis $name, $P, $crate::NonZero<$P>);
};
($(#[$attr:meta])* $vis:vis struct $name:ident $(:)? ($P:ty)) => {
compile_error!(concat!(
"iter_strided! requires either a `mut` or `ref` specifier before the index type.\n",
"E.g.: `iter_strided![", stringify!($vis), " struct ", stringify!($name),
" : ref (", stringify!($P), ")]`",));
};
(%guard_allowed_type $P:ty) => {
const __GUARD_ALLOWED_TYPE: () = {
const fn __allowed_types<P: $crate::PrimIndex>() {}
__allowed_types::<$P>();
};
};
(%mut $(#[$attr:meta])* $vis:vis $name:ident, $P:ty, $NZ:ty) => {
$(#[$attr])*
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
$vis struct $name<'a, T> {
slice: &'a mut [T],
front: $P,
back: $P,
stride: $NZ,
}
impl<'a, T> $name<'a, T> {
$crate::iter_strided!(%guard_allowed_type $P);
$crate::iter_strided!(%common_indexing $P, $NZ);
pub const fn from_count(
slice: &'a mut [T],
start: $P,
remaining: $P,
stride: $P,
) -> Self {
$crate::unwrap![some_map_into_expect <$NZ>::new(stride),
|v| Self::from_count_nz(slice, start, remaining, v), "stride must be > 0"]
}
pub const fn from_count_nz(
slice: &'a mut [T],
start: $P,
remaining: $P,
stride: $NZ,
) -> Self {
if remaining == 0 { return $crate::iter_strided!(%empty slice, stride) }
let off = stride.get().checked_mul(remaining - 1)
.expect("overflow in stride multiplication");
let back = start.checked_add(off).expect("overflow in back computation");
Self { slice, front: start, back, stride }
}
pub const fn from_bounds(slice: &'a mut [T], front: $P, back: $P, stride: $P) -> Self {
$crate::unwrap![some_map_into_expect <$NZ>::new(stride),
|v| Self::from_parts(slice, front, back, v), "stride must be > 0"]
}
pub const fn from_parts(slice: &'a mut [T], front: $P, back: $P, stride: $NZ) -> Self {
if front <= back {
assert!((back - front) % stride.get() == 0, "bounds must be stride-aligned");
assert!((back as usize) < slice.len(), "index out of bounds");
}
Self { slice, front, back, stride }
}
#[doc = concat!("- Any argument can't fit in a `", stringify!($P), "`.")]
pub const fn from_parts_usize(
slice: &'a mut [T],
front: usize,
back: usize,
stride: $crate::NonZero<usize>,
) -> Self {
let front_p = $crate::cast![checked_expect front => $P,
concat!("back doesn't fit in", stringify!($P))];
let back_p = $crate::cast![checked_expect back => $P,
concat!("back doesn't fit in", stringify!($P))];
let s_p = $crate::cast![checked_expect stride.get() => $P,
concat!("stride doesn't fit in", stringify!($P))];
let stride_p = $crate::unwrap![some_guaranteed_or_ub <$NZ>::new(s_p)];
Self::from_parts(slice, front_p, back_p, stride_p)
}
pub const fn into_parts(self) -> (&'a mut [T], $P, $P, $NZ) {
(self.slice, self.front, self.back, self.stride)
}
pub const fn into_parts_usize(self)
-> (&'a mut [T], usize, usize, $crate::NonZeroUsize) {
let s = self.stride.get() as usize;
let stride = $crate::unwrap![some_guaranteed_or_ub $crate::NonZeroUsize::new(s)];
(self.slice, self.front as usize, self.back as usize, stride)
}
pub const fn len(&self) -> $P {
if self.front > self.back { 0 }
else { ((self.back - self.front) / self.stride.get()) + 1 }
}
pub const fn len_usize(&self) -> usize { self.len() as usize }
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn next(&mut self) -> Option<&mut T> {
Some(&mut self.slice[$crate::unwrap!(some? self._next_front_index())])
}
pub const fn peek(&mut self) -> Option<&mut T> {
Some(&mut self.slice[$crate::unwrap!(some? self._peek_next_front_index())])
}
pub const fn next_back(&mut self) -> Option<&mut T> {
Some(&mut self.slice[$crate::unwrap!(some? self._next_back_index())])
}
pub const fn peek_back(&mut self) -> Option<&mut T> {
Some(&mut self.slice[$crate::unwrap!(some? self._peek_next_back_index())])
}
}
impl<'a, T> $crate::IteratorLending for $name<'a, T> {
type Item<'b> = &'b mut T where Self: 'b;
fn next<'b>(&'b mut self) -> Option<Self::Item<'b>> { self.next() }
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len_usize();
(len, Some(len))
}
}
impl<'a, T> $crate::IteratorLendingExactSize for $name<'a, T> {
fn len(&self) -> usize { self.len_usize() }
}
impl<'a, T> $crate::IteratorLendingPeek for $name<'a, T> {
fn peek<'b>(&'b mut self) -> Option<Self::Item<'b>> { self.peek() }
}
impl<'a, T> $crate::IteratorLendingDoubleEnded for $name<'a, T> {
fn next_back<'b>(&'b mut self) -> Option<Self::Item<'b>> {
Some(&mut self.slice[self._next_back_index()?])
}
}
impl<'a, T> $crate::IteratorLendingPeekDoubleEnded for $name<'a, T> {
fn peek_back<'b>(&'b mut self) -> Option<Self::Item<'b>> { self.peek_back() }
}
};
(%ref $(#[$attr:meta])* $vis:vis $name:ident, $P:ty, $NZ:ty) => {
$(#[$attr])*
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
$vis struct $name<'a, T> {
slice: &'a [T],
front: $P,
back: $P,
stride: $NZ,
}
impl<'a, T> $name<'a, T> {
$crate::iter_strided!(%guard_allowed_type $P);
$crate::iter_strided!(%common_indexing $P, $NZ);
pub const fn from_count(
slice: &'a [T],
start: $P,
remaining: $P,
stride: $P,
) -> Self {
$crate::unwrap![some_map_into_expect <$NZ>::new(stride),
|v| Self::from_count_nz(slice, start, remaining, v), "stride must be > 0"]
}
pub const fn from_count_nz(
slice: &'a [T],
start: $P,
remaining: $P,
stride: $NZ,
) -> Self {
if remaining == 0 { return $crate::iter_strided!(%empty slice, stride) }
let off = stride.get().checked_mul(remaining - 1)
.expect("overflow in stride multiplication");
let back = start.checked_add(off).expect("overflow in back computation");
Self { slice, front: start, back, stride }
}
pub const fn from_bounds(slice: &'a [T], front: $P, back: $P, stride: $P) -> Self {
$crate::unwrap![some_map_into_expect <$NZ>::new(stride),
|v| Self::from_parts(slice, front, back, v), "stride must be > 0"]
}
pub const fn from_parts(
slice: &'a [T],
front: $P,
back: $P,
stride: $NZ,
) -> Self {
if front <= back {
assert!((back - front) % stride.get() == 0, "bounds must be stride-aligned");
assert!((back as usize) < slice.len(), "index out of bounds");
}
Self { slice, front, back, stride }
}
#[doc = concat!("- Any argument can't fit in `", stringify!($P), "`.")]
pub const fn from_parts_usize(
slice: &'a [T],
front: usize,
back: usize,
stride: $crate::NonZero<usize>,
) -> Self {
let front_p = $crate::cast![checked_expect front => $P,
concat!("front doesn't fit in ", stringify!($P))];
let back_p = $crate::cast![checked_expect back => $P,
concat!("back doesn't fit in ", stringify!($P))];
let s_p = $crate::cast![checked_expect stride.get() => $P,
concat!("stride doesn't fit in ", stringify!($P))];
let stride_p = $crate::unwrap![some_guaranteed_or_ub <$NZ>::new(s_p)];
Self::from_parts(slice, front_p, back_p, stride_p)
}
pub const fn into_parts(self) -> (&'a [T], $P, $P, $NZ) {
(self.slice, self.front, self.back, self.stride)
}
pub const fn into_parts_usize(self)
-> (&'a [T], usize, usize, $crate::NonZeroUsize) {
let s = self.stride.get() as usize;
let stride = $crate::unwrap![some_guaranteed_or_ub $crate::NonZeroUsize::new(s)];
(self.slice, self.front as usize, self.back as usize, stride)
}
pub const fn len(&self) -> $P {
if self.front > self.back { 0 }
else { ((self.back - self.front) / self.stride.get()) + 1 }
}
pub const fn len_usize(&self) -> usize { self.len() as usize }
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn next(&mut self) -> Option<&T> {
Some(&self.slice[$crate::unwrap!(some? self._next_front_index())])
}
pub const fn peek(&self) -> Option<&T> {
Some(&self.slice[$crate::unwrap!(some? self._peek_next_front_index())])
}
pub const fn next_back(&mut self) -> Option<&T> {
Some(&self.slice[$crate::unwrap!(some? self._next_back_index())])
}
pub const fn peek_back(&self) -> Option<&T> {
Some(&self.slice[$crate::unwrap!(some? self._peek_next_back_index())])
}
}
impl<'a, T> $crate::Iterator for $name<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
Some(&self.slice[self._next_front_index()?])
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len_usize();
(len, Some(len))
}
}
impl<'a, T> $crate::IteratorDoubleEnded for $name<'a, T> {
fn next_back(&mut self) -> Option<Self::Item> {
Some(&self.slice[self._next_back_index()?])
}
}
impl<T> $crate::IteratorExactSize for $name<'_, T> {
fn len(&self) -> usize { self.len_usize() }
}
impl<'a, T> $crate::IteratorLending for $name<'a, T> {
type Item<'b> = &'b T where Self: 'b;
fn next<'b>(&'b mut self) -> Option<Self::Item<'b>> { self.next() }
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len_usize();
(len, Some(len))
}
}
impl<'a, T> $crate::IteratorLendingExactSize for $name<'a, T> {
fn len(&self) -> usize { self.len_usize() }
}
impl<'a, T> $crate::IteratorLendingPeek for $name<'a, T> {
fn peek<'b>(&'b mut self) -> Option<Self::Item<'b>> { Self::peek(self) }
}
impl<'a, T> $crate::IteratorLendingDoubleEnded for $name<'a, T> {
fn next_back<'b>(&'b mut self) -> Option<Self::Item<'b>> {
Some(&self.slice[self._next_back_index()?])
}
}
impl<'a, T> $crate::IteratorLendingPeekDoubleEnded for $name<'a, T> {
fn peek_back<'b>(&'b mut self) -> Option<Self::Item<'b>> { Self::peek_back(self) }
}
};
(%common_indexing $P:ty, $NZ:ty) => {
const fn _next_front_index(&mut self) -> Option<usize> {
if self.front > self.back {
None
} else {
let idx = self.front;
if self.front == self.back {
self.front = 1;
self.back = 0;
} else {
self.front += self.stride.get();
}
Some(idx as usize)
}
}
const fn _next_back_index(&mut self) -> Option<usize> {
if self.front > self.back {
None
} else {
let idx = self.back;
if self.front == self.back {
self.front = 1;
self.back = 0;
} else {
self.back -= self.stride.get();
}
Some(idx as usize)
}
}
const fn _peek_next_front_index(&self) -> Option<usize> {
if self.front > self.back { None } else { Some(self.front as usize) }
}
const fn _peek_next_back_index(&self) -> Option<usize> {
if self.front > self.back { None } else { Some(self.back as usize) }
}
};
(%empty $slice:expr, $stride:expr) => {
Self { slice: $slice, front: 1, back: 0, stride: $stride }
};
}
#[doc(inline)]
pub use crate::iter_strided;