1use crate::align::Alignment;
18use crate::arch::SimdArch;
19use crate::execution::ExecutionMode;
20use crate::kernel::SimdKernel;
21use crate::scalar::Scalar;
22use crate::view::SimdView;
23
24pub struct ZipChunks<'a, 'b, T, Arch: SimdArch, Align: Alignment, Mode: ExecutionMode> {
38 base_a: *const T,
39 base_b: *const T,
40 pos: usize,
41 simd_end: usize,
42 total_a: usize,
43 total_b: usize,
44 _marker: core::marker::PhantomData<(&'a T, &'b T, Arch, Align, Mode)>,
45}
46
47unsafe impl<'a, 'b, T: Send, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
49 Send for ZipChunks<'a, 'b, T, Arch, Align, Mode>
50where
51 T: Scalar,
52{
53}
54unsafe impl<'a, 'b, T: Sync, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
55 Sync for ZipChunks<'a, 'b, T, Arch, Align, Mode>
56where
57 T: Scalar,
58{
59}
60
61impl<'a, 'b, T: Scalar, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
62 ZipChunks<'a, 'b, T, Arch, Align, Mode>
63{
64 #[inline]
70 pub(crate) unsafe fn from_raw_parts(
71 base_a: *const T,
72 total_a: usize,
73 base_b: *const T,
74 total_b: usize,
75 ) -> Self {
76 let lane_count = Arch::LANE_COUNT;
77 let min_total = total_a.min(total_b);
78 let simd_end = (min_total / lane_count) * lane_count;
79 Self {
80 base_a,
81 base_b,
82 pos: 0,
83 simd_end,
84 total_a,
85 total_b,
86 _marker: core::marker::PhantomData,
87 }
88 }
89
90 #[inline(always)]
92 pub fn remainder(&self) -> (&'a [T], &'b [T]) {
93 unsafe {
95 (
96 core::slice::from_raw_parts(
97 self.base_a.add(self.simd_end),
98 self.total_a - self.simd_end,
99 ),
100 core::slice::from_raw_parts(
101 self.base_b.add(self.simd_end),
102 self.total_b - self.simd_end,
103 ),
104 )
105 }
106 }
107
108 #[inline(always)]
110 pub fn chunks_remaining(&self) -> usize {
111 if self.simd_end > self.pos {
112 (self.simd_end - self.pos) / Arch::LANE_COUNT
113 } else {
114 0
115 }
116 }
117}
118
119impl<'a, 'b, T: Scalar, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
120 Iterator for ZipChunks<'a, 'b, T, Arch, Align, Mode>
121{
122 type Item = (
123 SimdView<'a, T, Arch, Align, Mode, &'a [T]>,
124 SimdView<'b, T, Arch, Align, Mode, &'b [T]>,
125 );
126
127 #[inline(always)]
128 fn next(&mut self) -> Option<Self::Item> {
129 if self.pos >= self.simd_end {
130 return None;
131 }
132 let (chunk_a, chunk_b) = unsafe {
134 (
135 core::slice::from_raw_parts(self.base_a.add(self.pos), Arch::LANE_COUNT),
136 core::slice::from_raw_parts(self.base_b.add(self.pos), Arch::LANE_COUNT),
137 )
138 };
139 self.pos += Arch::LANE_COUNT;
140 Some((
141 SimdView::new(chunk_a).expect("zip chunk_a alignment invariant violated"),
142 SimdView::new(chunk_b).expect("zip chunk_b alignment invariant violated"),
143 ))
144 }
145
146 #[inline(always)]
147 fn size_hint(&self) -> (usize, Option<usize>) {
148 let r = self.chunks_remaining();
149 (r, Some(r))
150 }
151}
152
153impl<'a, 'b, T: Scalar, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
154 ExactSizeIterator for ZipChunks<'a, 'b, T, Arch, Align, Mode>
155{
156}
157
158impl<'a, 'b, T: Scalar, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
159 core::iter::FusedIterator for ZipChunks<'a, 'b, T, Arch, Align, Mode>
160{
161}
162
163pub struct ZipChunksMut<'a, 'b, T: 'a + 'b, Arch: SimdArch, Align: Alignment, Mode: ExecutionMode> {
186 ptr_a: *mut T,
188 ptr_b: *const T,
190 pos: usize,
192 total: usize,
194 simd_end: usize,
196 _marker: core::marker::PhantomData<(&'a mut T, &'b T, Arch, Align, Mode)>,
197}
198
199unsafe impl<'a, 'b, T, Arch, Align, Mode> Send for ZipChunksMut<'a, 'b, T, Arch, Align, Mode>
202where
203 T: Scalar + Send + Sync,
204 Arch: SimdArch + SimdKernel<T>,
205 Align: Alignment,
206 Mode: ExecutionMode,
207{
208}
209unsafe impl<'a, 'b, T, Arch, Align, Mode> Sync for ZipChunksMut<'a, 'b, T, Arch, Align, Mode>
210where
211 T: Scalar + Send + Sync,
212 Arch: SimdArch + SimdKernel<T>,
213 Align: Alignment,
214 Mode: ExecutionMode,
215{
216}
217
218impl<'a, 'b, T: 'a + 'b, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
219 ZipChunksMut<'a, 'b, T, Arch, Align, Mode>
220where
221 T: Scalar,
222{
223 #[inline]
230 pub(crate) unsafe fn from_raw_parts(
231 ptr_a: *mut T,
232 total_a: usize,
233 ptr_b: *const T,
234 total_b: usize,
235 ) -> Self {
236 let lane_count = Arch::LANE_COUNT;
237 let total = total_a.min(total_b);
238 let simd_end = (total / lane_count) * lane_count;
239 Self {
240 ptr_a,
241 ptr_b,
242 pos: 0,
243 total,
244 simd_end,
245 _marker: core::marker::PhantomData,
246 }
247 }
248
249 #[inline(always)]
253 pub fn into_remainder(self) -> (&'a mut [T], &'b [T]) {
254 let len = self.total - self.simd_end;
255 unsafe {
258 (
259 core::slice::from_raw_parts_mut(self.ptr_a.add(self.simd_end), len),
260 core::slice::from_raw_parts(self.ptr_b.add(self.simd_end), len),
261 )
262 }
263 }
264
265 #[inline(always)]
267 pub fn chunks_remaining(&self) -> usize {
268 if self.simd_end > self.pos {
269 (self.simd_end - self.pos) / Arch::LANE_COUNT
270 } else {
271 0
272 }
273 }
274}
275
276impl<'a, 'b, T: Scalar, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
277 Iterator for ZipChunksMut<'a, 'b, T, Arch, Align, Mode>
278{
279 type Item = (
281 SimdView<'a, T, Arch, Align, Mode, &'a mut [T]>,
282 SimdView<'b, T, Arch, Align, Mode, &'b [T]>,
283 );
284
285 #[inline(always)]
286 fn next(&mut self) -> Option<Self::Item> {
287 if self.pos >= self.simd_end {
288 return None;
289 }
290 let lane = Arch::LANE_COUNT;
291 let (chunk_a, chunk_b) = unsafe {
294 (
295 core::slice::from_raw_parts_mut(self.ptr_a.add(self.pos), lane),
296 core::slice::from_raw_parts(self.ptr_b.add(self.pos), lane),
297 )
298 };
299 self.pos += lane;
300 Some((
301 SimdView::new_mut(chunk_a).expect("ZipChunksMut chunk_a alignment violated"),
302 SimdView::new(chunk_b).expect("ZipChunksMut chunk_b alignment violated"),
303 ))
304 }
305
306 #[inline(always)]
307 fn size_hint(&self) -> (usize, Option<usize>) {
308 let r = self.chunks_remaining();
309 (r, Some(r))
310 }
311}
312
313impl<'a, 'b, T: Scalar, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
314 ExactSizeIterator for ZipChunksMut<'a, 'b, T, Arch, Align, Mode>
315{
316}
317
318impl<'a, 'b, T: Scalar, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
319 core::iter::FusedIterator for ZipChunksMut<'a, 'b, T, Arch, Align, Mode>
320{
321}