imgref_iter/iter/simd/
ptr.rs

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