1use crate::align::Alignment;
19use crate::arch::SimdArch;
20use crate::execution::ExecutionMode;
21use crate::kernel::SimdKernel;
22use crate::scalar::Scalar;
23use crate::view::SimdView;
24use core::marker::PhantomData;
25
26pub struct SimdChunks<'a, T: 'a, Arch: SimdArch, Align: Alignment, Mode: ExecutionMode> {
35 base: *const T,
37 pos: usize,
39 total: usize,
41 simd_end: usize,
43 _marker: PhantomData<(&'a T, Arch, Align, Mode)>,
44}
45
46unsafe impl<
49 'a,
50 T: Send,
51 Arch: SimdArch + crate::kernel::SimdKernel<T>,
52 Align: Alignment,
53 Mode: ExecutionMode,
54 > Send for SimdChunks<'a, T, Arch, Align, Mode>
55where
56 T: crate::scalar::Scalar,
57{
58}
59unsafe impl<
60 'a,
61 T: Sync,
62 Arch: SimdArch + crate::kernel::SimdKernel<T>,
63 Align: Alignment,
64 Mode: ExecutionMode,
65 > Sync for SimdChunks<'a, T, Arch, Align, Mode>
66where
67 T: crate::scalar::Scalar,
68{
69}
70
71impl<
72 'a,
73 T: 'a,
74 Arch: SimdArch + crate::kernel::SimdKernel<T>,
75 Align: Alignment,
76 Mode: ExecutionMode,
77 > SimdChunks<'a, T, Arch, Align, Mode>
78where
79 T: crate::scalar::Scalar,
80{
81 #[inline]
86 pub(crate) unsafe fn from_raw_parts(base: *const T, total: usize, lane_count: usize) -> Self {
87 let simd_end = (total / lane_count) * lane_count;
88 Self {
89 base,
90 pos: 0,
91 total,
92 simd_end,
93 _marker: PhantomData,
94 }
95 }
96
97 #[inline(always)]
110 pub fn remainder(&self) -> &'a [T] {
111 unsafe {
114 core::slice::from_raw_parts(self.base.add(self.simd_end), self.total - self.simd_end)
115 }
116 }
117}
118
119impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
120 SimdChunks<'a, T, Arch, Align, Mode>
121{
122 #[inline(always)]
126 pub fn chunks_remaining(&self) -> usize {
127 if self.simd_end > self.pos {
128 (self.simd_end - self.pos) / Arch::LANE_COUNT
129 } else {
130 0
131 }
132 }
133}
134
135impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
136 Iterator for SimdChunks<'a, T, Arch, Align, Mode>
137{
138 type Item = SimdView<'a, T, Arch, Align, Mode, &'a [T]>;
139
140 #[inline(always)]
141 fn next(&mut self) -> Option<Self::Item> {
142 if self.pos >= self.simd_end {
143 return None;
144 }
145 let chunk_slice =
152 unsafe { core::slice::from_raw_parts(self.base.add(self.pos), Arch::LANE_COUNT) };
153 self.pos += Arch::LANE_COUNT;
154 Some(SimdView::new(chunk_slice).expect("chunk alignment invariant violated"))
157 }
158
159 #[inline(always)]
160 fn size_hint(&self) -> (usize, Option<usize>) {
161 let remaining = self.chunks_remaining();
162 (remaining, Some(remaining))
163 }
164}
165
166impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
167 ExactSizeIterator for SimdChunks<'a, T, Arch, Align, Mode>
168{
169}
170
171impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
172 DoubleEndedIterator for SimdChunks<'a, T, Arch, Align, Mode>
173{
174 #[inline(always)]
175 fn next_back(&mut self) -> Option<Self::Item> {
176 if self.pos >= self.simd_end {
177 return None;
178 }
179 self.simd_end -= Arch::LANE_COUNT;
180 let chunk_slice =
182 unsafe { core::slice::from_raw_parts(self.base.add(self.simd_end), Arch::LANE_COUNT) };
183 Some(SimdView::new(chunk_slice).expect("chunk alignment invariant violated"))
184 }
185}
186
187impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
188 core::iter::FusedIterator for SimdChunks<'a, T, Arch, Align, Mode>
189{
190}
191
192pub struct SimdChunksMut<'a, T: 'a, Arch: SimdArch, Align: Alignment, Mode: ExecutionMode> {
201 base: *mut T,
203 pos: usize,
205 total: usize,
207 simd_end: usize,
209 _marker: PhantomData<(&'a mut T, Arch, Align, Mode)>,
210}
211
212unsafe impl<
215 'a,
216 T: Send,
217 Arch: SimdArch + crate::kernel::SimdKernel<T>,
218 Align: Alignment,
219 Mode: ExecutionMode,
220 > Send for SimdChunksMut<'a, T, Arch, Align, Mode>
221where
222 T: crate::scalar::Scalar,
223{
224}
225unsafe impl<
226 'a,
227 T: Sync,
228 Arch: SimdArch + crate::kernel::SimdKernel<T>,
229 Align: Alignment,
230 Mode: ExecutionMode,
231 > Sync for SimdChunksMut<'a, T, Arch, Align, Mode>
232where
233 T: crate::scalar::Scalar,
234{
235}
236
237impl<
238 'a,
239 T: 'a,
240 Arch: SimdArch + crate::kernel::SimdKernel<T>,
241 Align: Alignment,
242 Mode: ExecutionMode,
243 > SimdChunksMut<'a, T, Arch, Align, Mode>
244where
245 T: crate::scalar::Scalar,
246{
247 #[inline]
252 pub(crate) unsafe fn from_raw_parts(base: *mut T, total: usize, lane_count: usize) -> Self {
253 let simd_end = (total / lane_count) * lane_count;
254 Self {
255 base,
256 pos: 0,
257 total,
258 simd_end,
259 _marker: PhantomData,
260 }
261 }
262
263 #[inline(always)]
267 pub fn into_remainder(self) -> &'a mut [T] {
268 unsafe {
271 core::slice::from_raw_parts_mut(
272 self.base.add(self.simd_end),
273 self.total - self.simd_end,
274 )
275 }
276 }
277}
278
279impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
280 SimdChunksMut<'a, T, Arch, Align, Mode>
281{
282 #[inline(always)]
284 pub fn chunks_remaining(&self) -> usize {
285 if self.simd_end > self.pos {
286 (self.simd_end - self.pos) / Arch::LANE_COUNT
287 } else {
288 0
289 }
290 }
291}
292
293impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
294 Iterator for SimdChunksMut<'a, T, Arch, Align, Mode>
295{
296 type Item = SimdView<'a, T, Arch, Align, Mode, &'a mut [T]>;
297
298 #[inline(always)]
299 fn next(&mut self) -> Option<Self::Item> {
300 if self.pos >= self.simd_end {
301 return None;
302 }
303 let chunk_slice =
308 unsafe { core::slice::from_raw_parts_mut(self.base.add(self.pos), Arch::LANE_COUNT) };
309 self.pos += Arch::LANE_COUNT;
310 Some(SimdView::new_mut(chunk_slice).expect("chunk alignment invariant violated"))
313 }
314
315 #[inline(always)]
316 fn size_hint(&self) -> (usize, Option<usize>) {
317 let remaining = self.chunks_remaining();
318 (remaining, Some(remaining))
319 }
320}
321
322impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
323 ExactSizeIterator for SimdChunksMut<'a, T, Arch, Align, Mode>
324{
325}
326
327impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
328 DoubleEndedIterator for SimdChunksMut<'a, T, Arch, Align, Mode>
329{
330 #[inline(always)]
331 fn next_back(&mut self) -> Option<Self::Item> {
332 if self.pos >= self.simd_end {
333 return None;
334 }
335 self.simd_end -= Arch::LANE_COUNT;
336 let chunk_slice = unsafe {
338 core::slice::from_raw_parts_mut(self.base.add(self.simd_end), Arch::LANE_COUNT)
339 };
340 Some(SimdView::new_mut(chunk_slice).expect("chunk alignment invariant violated"))
341 }
342}
343
344impl<'a, T: Scalar + 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
345 core::iter::FusedIterator for SimdChunksMut<'a, T, Arch, Align, Mode>
346{
347}