imgref_iter/iter/simd/
mod.rs

1use std::iter::FusedIterator;
2use std::marker::PhantomData;
3use imgref::Img;
4use crate::iter::{Iter, IterMut, IterPtr, IterPtrMut};
5
6mod ptr;
7
8pub use ptr::*;
9
10#[repr(transparent)]
11#[derive(Copy, Clone, Eq, PartialEq, Debug)]
12pub struct SimdIter<'a, T, const LANES: usize>(SimdIterPtr<T, LANES>, PhantomData<&'a [T]>);
13
14#[allow(clippy::missing_safety_doc)]
15impl<'a, T, const LANES: usize> SimdIter<'a, T, LANES> {
16	/// Wraps a [`SimdIterPtr`] in a [`SimdIter`].
17	///
18	/// # Safety
19	///
20	/// The [`SimdIterPtr`] must be valid for reads and shared references.
21	#[inline]
22	pub unsafe fn wrap(ptr: SimdIterPtr<T, LANES>) -> Self {
23		Self(ptr, PhantomData)
24	}
25
26	/// Creates a new [`SimdIter`] from the given [`Iter`] and gap.
27	///
28	/// The gap is the distance between successive items in the returned arrays.
29	/// For example if the iterator is over a row and the gap is the stride,
30	/// then this iterator will yield items from multiple rows at a time.
31	///
32	/// # Safety
33	///
34	/// The given gap must be valid.
35	#[inline]
36	pub unsafe fn new(iter: Iter<'a, T>, gap: usize) -> Self {
37		Self::wrap(SimdIterPtr::new(iter.into_inner(), gap))
38	}
39
40	/// Creates a new [`SimdIter`] from the given [`IterPtr`] and gap.
41	///
42	/// The gap is the distance between successive items in the returned arrays.
43	/// For example if the iterator is over a row and the gap is the stride,
44	/// then this iterator will yield items from multiple rows at a time.
45	///
46	/// # Safety
47	///
48	/// The given iterator must be valid and the gap must be valid.
49	#[inline]
50	pub unsafe fn new_ptr(iter: IterPtr<T>, gap: usize) -> Self {
51		Self::wrap(SimdIterPtr::new(iter, gap))
52	}
53
54	/// Creates a new [`SimdIter`] across `LANES` rows.
55	///
56	/// # Panics
57	///
58	/// Panics if the given `row + LANES > buf.height()`.
59	#[inline]
60	pub fn rows<S: AsRef<[T]>>(buf: &Img<S>, row: usize) -> Self {
61		unsafe { Self::wrap(SimdIterPtr::rows(buf, row)) }
62	}
63
64	/// Creates a new [`SimdIter`] across `LANES` rows.
65	///
66	/// # Safety
67	///
68	/// The provided buffer must be valid for the lifetime of the returned
69	/// [`SimdIter`].
70	///
71	/// # Panics
72	///
73	/// Panics if the given `row + LANES > buf.height()`.
74	#[inline]
75	pub unsafe fn rows_ptr(buf: Img<*const [T]>, row: usize) -> Self {
76		Self::wrap(SimdIterPtr::rows_ptr(buf, row))
77	}
78
79	/// Creates a new [`SimdIter`] across `LANES` rows.
80	///
81	/// # Safety
82	///
83	/// The provided buffer must be valid for the lifetime of the returned
84	/// [`SimdIter`].
85	///
86	/// The caller must ensure that `row + LANES > buf.height()`.
87	#[inline]
88	pub unsafe fn rows_ptr_unchecked(buf: Img<*const [T]>, row: usize) -> Self {
89		Self::wrap(SimdIterPtr::rows_ptr_unchecked(buf, row))
90	}
91
92	/// Creates a new [`SimdIter`] across `LANES` cols.
93	///
94	/// # Panics
95	///
96	/// Panics if the given `col + LANES > buf.width()`.
97	#[inline]
98	pub fn cols<S: AsRef<[T]>>(buf: &Img<S>, col: usize) -> Self {
99		unsafe { Self::wrap(SimdIterPtr::cols(buf, col)) }
100	}
101
102	/// Creates a new [`SimdIter`] across `LANES` cols.
103	///
104	/// # Safety
105	///
106	/// The provided buffer must be valid for the lifetime of the returned
107	/// [`SimdIter`].
108	///
109	/// # Panics
110	///
111	/// Panics if the given `col + LANES > buf.width()`.
112	#[inline]
113	pub unsafe fn cols_ptr(buf: Img<*const [T]>, col: usize) -> Self {
114		Self::wrap(SimdIterPtr::cols_ptr(buf, col))
115	}
116
117	/// Creates a new [`SimdIter`] across `LANES` cols.
118	///
119	/// # Safety
120	///
121	/// The provided buffer must be valid for the lifetime of the returned
122	/// [`SimdIter`].
123	///
124	/// The caller must ensure that `col + LANES > buf.width()`.
125	#[inline]
126	pub unsafe fn cols_ptr_unchecked(buf: Img<*const [T]>, col: usize) -> Self {
127		Self::wrap(SimdIterPtr::cols_ptr_unchecked(buf, col))
128	}
129
130	/// Converts this [`SimdIter`] into its inner [`SimdIterPtr`].
131	#[inline]
132	pub fn into_inner(self) -> SimdIterPtr<T, LANES> {
133		self.0
134	}
135}
136
137impl<'a, T, const LANES: usize> Iterator for SimdIter<'a, T, LANES> {
138	type Item = [&'a T; LANES];
139
140	#[inline]
141	fn next(&mut self) -> Option<Self::Item> {
142		self.0.next().map(|arr| arr.map(|ptr| unsafe { &*ptr }))
143	}
144
145	#[inline]
146	fn size_hint(&self) -> (usize, Option<usize>) {
147		self.0.size_hint()
148	}
149}
150
151impl<'a, T, const LANES: usize> DoubleEndedIterator for SimdIter<'a, T, LANES> {
152	#[inline]
153	fn next_back(&mut self) -> Option<Self::Item> {
154		self.0.next_back().map(|arr| arr.map(|ptr| unsafe { &*ptr }))
155	}
156}
157
158impl<'a, T, const LANES: usize> ExactSizeIterator for SimdIter<'a, T, LANES> {
159	#[inline]
160	fn len(&self) -> usize {
161		self.0.len()
162	}
163}
164
165impl<'a, T, const LANES: usize> FusedIterator for SimdIter<'a, T, LANES> {}
166
167#[repr(transparent)]
168#[derive(Eq, PartialEq, Debug)]
169pub struct SimdIterMut<'a, T, const LANES: usize>(SimdIterPtrMut<T, LANES>, PhantomData<&'a mut [T]>);
170
171#[allow(clippy::missing_safety_doc)]
172impl<'a, T, const LANES: usize> SimdIterMut<'a, T, LANES> {
173	/// Wraps a [`SimdIterPtrMut`] in a [`SimdIterMut`].
174	///
175	/// # Safety
176	///
177	/// The [`SimdIterPtrMut`] must be valid for reads and writes.
178	#[inline]
179	pub unsafe fn wrap(ptr: SimdIterPtrMut<T, LANES>) -> Self {
180		Self(ptr, PhantomData)
181	}
182
183	/// Creates a new [`SimdIterMut`] from the given [`Iter`] and gap.
184	///
185	/// The gap is the distance between successive items in the returned arrays.
186	/// For example if the iterator is over a row and the gap is the stride,
187	/// then this iterator will yield items from multiple rows at a time.
188	///
189	/// # Safety
190	///
191	/// The given gap must be valid.
192	#[inline]
193	pub unsafe fn new(iter: IterMut<'a, T>, gap: usize) -> Self {
194		Self::wrap(SimdIterPtrMut::new(iter.into_inner(), gap))
195	}
196
197	/// Creates a new [`SimdIterMut`] from the given [`IterPtr`] and gap.
198	///
199	/// The gap is the distance between successive items in the returned arrays.
200	/// For example if the iterator is over a row and the gap is the stride,
201	/// then this iterator will yield items from multiple rows at a time.
202	///
203	/// # Safety
204	///
205	/// The given iterator must be valid and the gap must be valid.
206	#[inline]
207	pub unsafe fn new_ptr(iter: IterPtrMut<T>, gap: usize) -> Self {
208		Self::wrap(SimdIterPtrMut::new(iter, gap))
209	}
210
211	/// Creates a new [`SimdIterMut`] across `LANES` rows.
212	///
213	/// # Panics
214	///
215	/// Panics if the given `row + LANES > buf.height()`.
216	#[inline]
217	pub fn rows<S: AsMut<[T]>>(buf: &mut Img<S>, row: usize) -> Self {
218		unsafe { Self::wrap(SimdIterPtrMut::rows(buf, row)) }
219	}
220
221	/// Creates a new [`SimdIterMut`] across `LANES` rows.
222	///
223	/// # Safety
224	///
225	/// The provided buffer must be valid for the lifetime of the returned
226	/// [`SimdIterMut`].
227	///
228	/// # Panics
229	///
230	/// Panics if the given `row + LANES > buf.height()`.
231	#[inline]
232	pub unsafe fn rows_ptr(buf: Img<*mut [T]>, row: usize) -> Self {
233		Self::wrap(SimdIterPtrMut::rows_ptr(buf, row))
234	}
235
236	/// Creates a new [`SimdIterMut`] across `LANES` rows.
237	///
238	/// # Safety
239	///
240	/// The provided buffer must be valid for the lifetime of the returned
241	/// [`SimdIterMut`].
242	///
243	/// The caller must ensure that `row + LANES > buf.height()`.
244	#[inline]
245	pub unsafe fn rows_ptr_unchecked(buf: Img<*mut [T]>, row: usize) -> Self {
246		Self::wrap(SimdIterPtrMut::rows_ptr_unchecked(buf, row))
247	}
248
249	/// Creates a new [`SimdIterMut`] across `LANES` cols.
250	///
251	/// # Panics
252	///
253	/// Panics if the given `col + LANES > buf.width()`.
254	#[inline]
255	pub fn cols<S: AsMut<[T]>>(buf: &mut Img<S>, col: usize) -> Self {
256		unsafe { Self::wrap(SimdIterPtrMut::cols(buf, col)) }
257	}
258
259	/// Creates a new [`SimdIterMut`] across `LANES` cols.
260	///
261	/// # Safety
262	///
263	/// The provided buffer must be valid for the lifetime of the returned
264	/// [`SimdIterMut`].
265	///
266	/// # Panics
267	///
268	/// Panics if the given `col + LANES > buf.width()`.
269	#[inline]
270	pub unsafe fn cols_ptr(buf: Img<*mut [T]>, col: usize) -> Self {
271		Self::wrap(SimdIterPtrMut::cols_ptr(buf, col))
272	}
273
274	/// Creates a new [`SimdIterMut`] across `LANES` cols.
275	///
276	/// # Safety
277	///
278	/// The provided buffer must be valid for the lifetime of the returned
279	/// [`SimdIterMut`].
280	///
281	/// The caller must ensure that `col + LANES > buf.width()`.
282	#[inline]
283	pub unsafe fn cols_ptr_unchecked(buf: Img<*mut [T]>, col: usize) -> Self {
284		Self::wrap(SimdIterPtrMut::cols_ptr_unchecked(buf, col))
285	}
286
287	/// Converts this [`SimdIterMut`] into its inner [`SimdIterPtrMut`].
288	#[inline]
289	pub fn into_inner(self) -> SimdIterPtrMut<T, LANES> {
290		self.0
291	}
292}
293
294impl<'a, T, const LANES: usize> Iterator for SimdIterMut<'a, T, LANES> {
295	type Item = [&'a mut T; LANES];
296
297	#[inline]
298	fn next(&mut self) -> Option<Self::Item> {
299		self.0.next().map(|arr| arr.map(|ptr| unsafe { &mut *ptr }))
300	}
301
302	#[inline]
303	fn size_hint(&self) -> (usize, Option<usize>) {
304		self.0.size_hint()
305	}
306}
307
308impl<'a, T, const LANES: usize> DoubleEndedIterator for SimdIterMut<'a, T, LANES> {
309	#[inline]
310	fn next_back(&mut self) -> Option<Self::Item> {
311		self.0.next_back().map(|arr| arr.map(|ptr| unsafe { &mut *ptr }))
312	}
313}
314
315impl<'a, T, const LANES: usize> ExactSizeIterator for SimdIterMut<'a, T, LANES> {
316	#[inline]
317	fn len(&self) -> usize {
318		self.0.len()
319	}
320}
321
322impl<'a, T, const LANES: usize> FusedIterator for SimdIterMut<'a, T, LANES> {}