imgref_iter/iter/simd_windows/
ptr.rs

1use std::iter::FusedIterator;
2use std::ops::Range;
3use std::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut};
4use imgref::Img;
5use crate::iter::{IterPtr, IterPtrMut, SimdIterPtr, SimdIterPtrMut};
6use crate::{slice_ptr_len, slice_ptr_len_mut};
7
8#[derive(Clone, Eq, PartialEq, Debug)]
9pub struct SimdIterWindowsPtr<T, const LANES: usize>(*const [T], usize, usize, Range<usize>);
10
11unsafe impl<T: Sync, const LANES: usize> Send for SimdIterWindowsPtr<T, LANES> {}
12
13unsafe impl<T, const LANES: usize> Sync for SimdIterWindowsPtr<T, LANES> {}
14
15impl<T, const LANES: usize> SimdIterWindowsPtr<T, LANES> {
16	/// Creates a new [`SimdIterWindowsPtr`]:
17	///
18	/// - `slice` is the slice that will be returned by the first iteration;
19	/// - `slice_stride` is the stride of `slice`;
20	/// - `iter_stride` is how far the slice will move each iteration;
21	/// - `len` is how many iterations
22	///
23	/// For example, for an iterator over rows, this would be:
24	///
25	/// - the first row of the image;
26	/// - `1`;
27	/// - the stride of the image;
28	/// - the height of the image
29	///
30	/// For an iterator over cols:
31	///
32	/// - the first column of the image;
33	/// - the stride of the image;
34	/// - `1`;
35	/// - the width of the image
36	///
37	/// # Safety
38	///
39	/// The provided slice must be valid for the lifetime of the returned
40	/// [`SimdIterWindowsPtr`]. There must be at least `iter_stride` elements
41	/// available past the end of the provided slice.
42	///
43	/// # Panics
44	///
45	/// Panics if the slice does not start and end on an element.
46	#[inline]
47	pub unsafe fn new(slice: *const [T], slice_stride: usize, iter_stride: usize, len: usize) -> Self {
48		assert!(IterPtr::is_slice_perfect(slice_ptr_len(slice), slice_stride));
49		Self::new_unchecked(slice, slice_stride, iter_stride, len)
50	}
51
52	/// Same as `new`, but does not verify the slice length.
53	///
54	/// # Safety
55	///
56	/// All safety invariants of `new` must be upheld, and the slice must start
57	/// and end on an element.
58	#[inline]
59	pub unsafe fn new_unchecked(slice: *const [T], slice_stride: usize, iter_stride: usize, len: usize) -> Self {
60		Self(slice, slice_stride, iter_stride, 0..len)
61	}
62
63	/// Creates a new [`SimdIterWindowsPtr`] over the rows of an [`Img`].
64	///
65	/// # Safety
66	///
67	/// The buffer must be valid for the lifetime of the returned iterator.
68	///
69	/// # Panics
70	///
71	/// Panics if the provided buffer has a width and height too large to fit in
72	/// its backing store.
73	#[inline]
74	pub unsafe fn rows<S: AsRef<[T]>>(buf: &Img<S>) -> Self {
75		let (width, height, stride) = (buf.width(), buf.height(), buf.stride());
76		let buf = buf.buf().as_ref() as *const [T];
77		Self::rows_ptr(Img::new_stride(buf, width, height, stride))
78	}
79
80	/// Creates a new [`SimdIterWindowsPtr`] over the rows of an [`Img`].
81	///
82	/// # Safety
83	///
84	/// The buffer must be valid for the lifetime of the returned iterator.
85	///
86	/// # Panics
87	///
88	/// Panics if the provided buffer has a width and height too large to fit in
89	/// its backing store.
90	#[inline]
91	pub unsafe fn rows_ptr(buf: Img<*const [T]>) -> Self {
92		IterPtr::assert_slice_enough(buf);
93		let (width, height, stride) = (buf.width(), buf.height(), buf.stride());
94		let first_row = slice_from_raw_parts(buf.buf().cast::<T>(), width);
95		Self::new_unchecked(first_row, 1, stride, height)
96	}
97
98	/// Creates a new [`SimdIterWindowsPtr`] over the cols of an [`Img`].
99	///
100	/// # Safety
101	///
102	/// The buffer must be valid for the lifetime of the returned iterator.
103	///
104	/// # Panics
105	///
106	/// Panics if the provided buffer has a width and height too large to fit in
107	/// its backing store.
108	#[inline]
109	pub unsafe fn cols<S: AsRef<[T]>>(buf: &Img<S>) -> Self {
110		let (width, height, stride) = (buf.width(), buf.height(), buf.stride());
111		let buf = buf.buf().as_ref() as *const [T];
112		Self::cols_ptr(Img::new_stride(buf, width, height, stride))
113	}
114
115	/// Creates a new [`SimdIterWindowsPtr`] over the cols of an [`Img`].
116	///
117	/// # Safety
118	///
119	/// The buffer must be valid for the lifetime of the returned iterator.
120	///
121	/// # Panics
122	///
123	/// Panics if the provided buffer has a width and height too large to fit in
124	/// its backing store.
125	#[inline]
126	pub unsafe fn cols_ptr(buf: Img<*const [T]>) -> Self {
127		IterPtr::assert_slice_enough(buf);
128		let (width, height, stride) = (buf.width(), buf.height(), buf.stride());
129		let first_col = slice_from_raw_parts(buf.buf().cast::<T>(), stride * (height - 1) + 1);
130		Self::new_unchecked(first_col, buf.stride(), 1, width)
131	}
132
133	#[inline]
134	unsafe fn window(&self, offset: usize) -> *const [T] {
135		let data = self.0.cast::<T>().add(offset);
136		let len = slice_ptr_len(self.0);
137		slice_from_raw_parts(data, len)
138	}
139}
140
141#[derive(Copy, Clone, Eq, PartialEq, Debug)]
142pub enum SimdIterWindowPtr<T, const LANES: usize> {
143	Simd(SimdIterPtr<T, LANES>),
144	Single(IterPtr<T>)
145}
146
147impl<T, const LANES: usize> Iterator for SimdIterWindowsPtr<T, LANES> {
148	type Item = SimdIterWindowPtr<T, LANES>;
149
150	#[inline]
151	fn next(&mut self) -> Option<Self::Item> {
152		let (simd, index) = if self.3.len() >= LANES {
153			let index = self.3.next().unwrap();
154			for _ in 0..LANES - 1 { self.3.next().unwrap(); }
155			(true, index)
156		} else {
157			(false, self.3.next()?)
158		};
159
160		let iter = unsafe { IterPtr::new(self.window(index * self.2), self.1) };
161
162		Some(if simd {
163			SimdIterWindowPtr::Simd(unsafe { SimdIterPtr::new(iter, self.2) })
164		} else {
165			SimdIterWindowPtr::Single(iter)
166		})
167	}
168
169	#[inline]
170	fn size_hint(&self) -> (usize, Option<usize>) {
171		let len = self.len();
172		(len, Some(len))
173	}
174}
175
176impl<T, const LANES: usize> DoubleEndedIterator for SimdIterWindowsPtr<T, LANES> {
177	#[inline]
178	fn next_back(&mut self) -> Option<Self::Item> {
179		let (simd, index) = if self.3.len() >= LANES {
180			(true, self.3.nth_back(LANES - 1).unwrap())
181		} else {
182			(false, self.3.next_back()?)
183		};
184
185		let iter = unsafe { IterPtr::new(self.window(index * self.2), self.1) };
186
187		Some(if simd {
188			SimdIterWindowPtr::Simd(unsafe { SimdIterPtr::new(iter, self.2) })
189		} else {
190			SimdIterWindowPtr::Single(iter)
191		})
192	}
193}
194
195impl<T, const LANES: usize> ExactSizeIterator for SimdIterWindowsPtr<T, LANES> {
196	#[inline]
197	fn len(&self) -> usize {
198		self.3.len() / LANES + self.3.len() % LANES
199	}
200}
201
202impl<T, const LANES: usize> FusedIterator for SimdIterWindowsPtr<T, LANES> {}
203
204
205#[derive(Clone, Eq, PartialEq, Debug)]
206pub struct SimdIterWindowsPtrMut<T, const LANES: usize>(*mut [T], usize, usize, Range<usize>);
207
208unsafe impl<T: Sync, const LANES: usize> Send for SimdIterWindowsPtrMut<T, LANES> {}
209
210unsafe impl<T, const LANES: usize> Sync for SimdIterWindowsPtrMut<T, LANES> {}
211
212impl<T, const LANES: usize> SimdIterWindowsPtrMut<T, LANES> {
213	/// Creates a new [`SimdIterWindowsPtrMut`]:
214	///
215	/// - `slice` is the slice that will be returned by the first iteration;
216	/// - `slice_stride` is the stride of `slice`;
217	/// - `iter_stride` is how far the slice will move each iteration;
218	/// - `len` is how many iterations
219	///
220	/// For example, for an iterator over rows, this would be:
221	///
222	/// - the first row of the image;
223	/// - `1`;
224	/// - the stride of the image;
225	/// - the height of the image
226	///
227	/// For an iterator over cols:
228	///
229	/// - the first column of the image;
230	/// - the stride of the image;
231	/// - `1`;
232	/// - the width of the image
233	///
234	/// # Safety
235	///
236	/// The provided slice must be valid for the lifetime of the returned
237	/// [`SimdIterWindowsPtrMut`]. There must be at least `iter_stride` elements
238	/// available past the end of the provided slice.
239	///
240	/// # Panics
241	///
242	/// Panics if the slice does not start and end on an element.
243	#[inline]
244	pub unsafe fn new(slice: *mut [T], slice_stride: usize, iter_stride: usize, len: usize) -> Self {
245		assert!(IterPtr::is_slice_perfect(slice_ptr_len_mut(slice), slice_stride));
246		Self::new_unchecked(slice, slice_stride, iter_stride, len)
247	}
248
249	/// Same as `new`, but does not verify the slice length.
250	///
251	/// # Safety
252	///
253	/// All safety invariants of `new` must be upheld, and the slice must start
254	/// and end on an element.
255	#[inline]
256	pub unsafe fn new_unchecked(slice: *mut [T], slice_stride: usize, iter_stride: usize, len: usize) -> Self {
257		Self(slice, slice_stride, iter_stride, 0..len)
258	}
259
260	/// Creates a new [`SimdIterWindowsPtrMut`] over the rows of an [`Img`].
261	///
262	/// # Safety
263	///
264	/// The buffer must be valid for the lifetime of the returned iterator.
265	///
266	/// # Panics
267	///
268	/// Panics if the provided buffer has a width and height too large to fit in
269	/// its backing store.
270	#[inline]
271	pub unsafe fn rows<S: AsMut<[T]>>(buf: &mut Img<S>) -> Self {
272		let (width, height, stride) = (buf.width(), buf.height(), buf.stride());
273		let buf = buf.buf_mut().as_mut() as *mut [T];
274		Self::rows_ptr(Img::new_stride(buf, width, height, stride))
275	}
276
277	/// Creates a new [`SimdIterWindowsPtrMut`] over the rows of an [`Img`].
278	///
279	/// # Safety
280	///
281	/// The buffer must be valid for the lifetime of the returned iterator.
282	///
283	/// # Panics
284	///
285	/// Panics if the provided buffer has a width and height too large to fit in
286	/// its backing store.
287	#[inline]
288	pub unsafe fn rows_ptr(buf: Img<*mut [T]>) -> Self {
289		IterPtrMut::assert_slice_enough(buf);
290		let (width, height, stride) = (buf.width(), buf.height(), buf.stride());
291		let first_row = slice_from_raw_parts_mut(buf.buf().cast::<T>(), width);
292		Self::new_unchecked(first_row, 1, stride, height)
293	}
294
295	/// Creates a new [`SimdIterWindowsPtrMut`] over the cols of an [`Img`].
296	///
297	/// # Safety
298	///
299	/// The buffer must be valid for the lifetime of the returned iterator.
300	///
301	/// # Panics
302	///
303	/// Panics if the provided buffer has a width and height too large to fit in
304	/// its backing store.
305	#[inline]
306	pub unsafe fn cols<S: AsMut<[T]>>(buf: &mut Img<S>) -> Self {
307		let (width, height, stride) = (buf.width(), buf.height(), buf.stride());
308		let buf = buf.buf_mut().as_mut() as *mut [T];
309		Self::cols_ptr(Img::new_stride(buf, width, height, stride))
310	}
311
312	/// Creates a new [`SimdIterWindowsPtrMut`] over the cols of an [`Img`].
313	///
314	/// # Safety
315	///
316	/// The buffer must be valid for the lifetime of the returned iterator.
317	///
318	/// # Panics
319	///
320	/// Panics if the provided buffer has a width and height too large to fit in
321	/// its backing store.
322	#[inline]
323	pub unsafe fn cols_ptr(buf: Img<*mut [T]>) -> Self {
324		IterPtrMut::assert_slice_enough(buf);
325		let (width, height, stride) = (buf.width(), buf.height(), buf.stride());
326		let first_col = slice_from_raw_parts_mut(buf.buf().cast::<T>(), stride * (height - 1) + 1);
327		Self::new_unchecked(first_col, buf.stride(), 1, width)
328	}
329
330	#[inline]
331	unsafe fn window(&self, offset: usize) -> *mut [T] {
332		let data = self.0.cast::<T>().add(offset);
333		let len = slice_ptr_len_mut(self.0);
334		slice_from_raw_parts_mut(data, len)
335	}
336}
337
338#[derive(Copy, Clone, Eq, PartialEq, Debug)]
339pub enum SimdIterWindowPtrMut<T, const LANES: usize> {
340	Simd(SimdIterPtrMut<T, LANES>),
341	Single(IterPtrMut<T>)
342}
343
344impl<T, const LANES: usize> Iterator for SimdIterWindowsPtrMut<T, LANES> {
345	type Item = SimdIterWindowPtrMut<T, LANES>;
346
347	#[inline]
348	fn next(&mut self) -> Option<Self::Item> {
349		let (simd, index) = if self.3.len() >= LANES {
350			let index = self.3.next().unwrap();
351			for _ in 0..LANES - 1 { self.3.next().unwrap(); }
352			(true, index)
353		} else {
354			(false, self.3.next()?)
355		};
356
357		let iter = unsafe { IterPtrMut::new(self.window(index * self.2), self.1) };
358
359		Some(if simd {
360			SimdIterWindowPtrMut::Simd(unsafe { SimdIterPtrMut::new(iter, self.2) })
361		} else {
362			SimdIterWindowPtrMut::Single(iter)
363		})
364	}
365
366	#[inline]
367	fn size_hint(&self) -> (usize, Option<usize>) {
368		let len = self.len();
369		(len, Some(len))
370	}
371}
372
373impl<T, const LANES: usize> DoubleEndedIterator for SimdIterWindowsPtrMut<T, LANES> {
374	#[inline]
375	fn next_back(&mut self) -> Option<Self::Item> {
376		let (simd, index) = if self.3.len() >= LANES {
377			(true, self.3.nth_back(LANES - 1).unwrap())
378		} else {
379			(false, self.3.next_back()?)
380		};
381
382		let iter = unsafe { IterPtrMut::new(self.window(index * self.2), self.1) };
383
384		Some(if simd {
385			SimdIterWindowPtrMut::Simd(unsafe { SimdIterPtrMut::new(iter, self.2) })
386		} else {
387			SimdIterWindowPtrMut::Single(iter)
388		})
389	}
390}
391
392impl<T, const LANES: usize> ExactSizeIterator for SimdIterWindowsPtrMut<T, LANES> {
393	#[inline]
394	fn len(&self) -> usize {
395		self.3.len() / LANES + self.3.len() % LANES
396	}
397}
398
399impl<T, const LANES: usize> FusedIterator for SimdIterWindowsPtrMut<T, LANES> {}