1use core::slice;
4use std::ops::{Index, IndexMut, Range};
5
6use crate::rayon::prelude::*;
7
8#[derive(Debug, thiserror::Error)]
9pub enum Error {
10 #[error("dimensions do not match data size")]
11 DimensionMismatch,
12}
13
14#[derive(Debug)]
17pub struct StridedArray2DViewMut<'a, T> {
18 data: &'a mut [T],
19 data_width: usize,
20 height: usize,
21 cols: Range<usize>,
22}
23
24impl<'a, T> StridedArray2DViewMut<'a, T> {
25 pub const fn without_stride(
27 data: &'a mut [T],
28 height: usize,
29 width: usize,
30 ) -> Result<Self, Error> {
31 if width * height != data.len() {
32 return Err(Error::DimensionMismatch);
33 }
34 Ok(Self {
35 data,
36 data_width: width,
37 height,
38 cols: 0..width,
39 })
40 }
41
42 pub unsafe fn get_unchecked_ref(&self, i: usize, j: usize) -> &T {
46 debug_assert!(i < self.height);
47 debug_assert!(j < self.width());
48 unsafe {
49 self.data
50 .get_unchecked(i * self.data_width + j + self.cols.start)
51 }
52 }
53
54 pub unsafe fn get_unchecked_mut(&mut self, i: usize, j: usize) -> &mut T {
58 debug_assert!(i < self.height);
59 debug_assert!(j < self.width());
60 unsafe {
61 self.data
62 .get_unchecked_mut(i * self.data_width + j + self.cols.start)
63 }
64 }
65
66 pub const fn height(&self) -> usize {
67 self.height
68 }
69
70 pub const fn width(&self) -> usize {
71 self.cols.end - self.cols.start
72 }
73
74 pub fn iter_column_mut(&mut self, col: usize) -> impl Iterator<Item = &mut T> + '_ {
76 assert!(col < self.width());
77 let start = col + self.cols.start;
78 let data_ptr = self.data.as_mut_ptr();
79 (0..self.height).map(move |i|
80 unsafe { &mut *data_ptr.add(i * self.data_width + start) })
85 }
86
87 pub fn into_strides(self, stride: usize) -> impl Iterator<Item = Self> + 'a {
89 let Self {
90 data,
91 data_width,
92 height,
93 cols,
94 } = self;
95
96 cols.clone().step_by(stride).map(move |start| {
97 let end = (start + stride).min(cols.end);
98 Self {
99 data: unsafe { slice::from_raw_parts_mut(data.as_mut_ptr(), data.len()) },
102 data_width,
103 height,
104 cols: start..end,
105 }
106 })
107 }
108
109 pub fn into_par_strides(self, stride: usize) -> impl IndexedParallelIterator<Item = Self> + 'a
111 where
112 T: Send + Sync,
113 {
114 self.cols
115 .clone()
116 .into_par_iter()
117 .step_by(stride)
118 .map(move |start| {
119 let end = (start + stride).min(self.cols.end);
120 Self {
122 data: unsafe {
125 slice::from_raw_parts_mut(self.data.as_ptr() as *mut T, self.data.len())
126 },
127 data_width: self.data_width,
128 height: self.height,
129 cols: start..end,
130 }
131 })
132 }
133
134 pub fn iter_cols(&mut self) -> impl Iterator<Item = StridedArray2DColMut<'_, T>> + '_ {
136 let data_ptr = self.data.as_mut_ptr();
137 let data_len = self.data.len();
138 self.cols.clone().map(move |col| StridedArray2DColMut {
139 data: unsafe { slice::from_raw_parts_mut(data_ptr, data_len) },
142 data_width: self.data_width,
143 height: self.height,
144 col,
145 })
146 }
147
148 pub fn par_iter_cols(
150 &mut self,
151 ) -> impl IndexedParallelIterator<Item = StridedArray2DColMut<'_, T>> + '_
152 where
153 T: Send + Sync,
154 {
155 let data_ptr = SendPtr(self.data.as_mut_ptr());
156 let data_len = self.data.len();
157 let data_width = self.data_width;
158 let height = self.height;
159 self.cols.clone().into_par_iter().map(move |col| {
160 StridedArray2DColMut {
161 data: unsafe { slice::from_raw_parts_mut(data_ptr.as_ptr(), data_len) },
164 data_width,
165 height,
166 col,
167 }
168 })
169 }
170}
171
172#[derive(Debug)]
174pub struct StridedArray2DColMut<'a, T> {
175 data: &'a mut [T],
176 data_width: usize,
177 height: usize,
178 col: usize,
179}
180
181impl<'a, T> StridedArray2DColMut<'a, T> {
182 pub const fn height(&self) -> usize {
183 self.height
184 }
185
186 pub unsafe fn get_unchecked_ref(&self, i: usize) -> &T {
190 debug_assert!(i < self.height);
191 unsafe { self.data.get_unchecked(i * self.data_width + self.col) }
192 }
193
194 pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut T {
198 debug_assert!(i < self.height);
199 unsafe { self.data.get_unchecked_mut(i * self.data_width + self.col) }
200 }
201}
202
203impl<T> Index<usize> for StridedArray2DColMut<'_, T> {
204 type Output = T;
205
206 fn index(&self, i: usize) -> &T {
207 assert!(i < self.height());
208 unsafe { self.get_unchecked_ref(i) }
209 }
210}
211
212impl<T> IndexMut<usize> for StridedArray2DColMut<'_, T> {
213 fn index_mut(&mut self, i: usize) -> &mut Self::Output {
214 assert!(i < self.height());
215 unsafe { self.get_unchecked_mut(i) }
216 }
217}
218
219impl<T> Index<(usize, usize)> for StridedArray2DViewMut<'_, T> {
220 type Output = T;
221
222 fn index(&self, (i, j): (usize, usize)) -> &T {
223 assert!(i < self.height());
224 assert!(j < self.width());
225 unsafe { self.get_unchecked_ref(i, j) }
226 }
227}
228
229impl<T> IndexMut<(usize, usize)> for StridedArray2DViewMut<'_, T> {
230 fn index_mut(&mut self, (i, j): (usize, usize)) -> &mut Self::Output {
231 assert!(i < self.height());
232 assert!(j < self.width());
233 unsafe { self.get_unchecked_mut(i, j) }
234 }
235}
236
237struct SendPtr<T>(*mut T);
243
244impl<T> SendPtr<T> {
245 const fn as_ptr(self) -> *mut T {
246 self.0
247 }
248}
249
250impl<T> Clone for SendPtr<T> {
251 fn clone(&self) -> Self {
252 *self
253 }
254}
255
256impl<T> Copy for SendPtr<T> {}
257
258unsafe impl<T: Send> Send for SendPtr<T> {}
260unsafe impl<T: Sync> Sync for SendPtr<T> {}
261
262#[cfg(test)]
263mod tests {
264 use std::array;
265
266 use super::*;
267
268 #[test]
269 fn test_indexing() {
270 let mut data = array::from_fn::<_, 12, _>(|i| i);
271 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
272 assert_eq!(arr[(3, 1)], 10);
273 arr[(2, 2)] = 88;
274 assert_eq!(data[8], 88);
275 }
276
277 #[test]
278 fn test_strides() {
279 let mut data = array::from_fn::<_, 12, _>(|i| i);
280 let arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
281
282 {
283 let mut strides = arr.into_strides(2);
284 let mut stride0 = strides.next().unwrap();
285 let mut stride1 = strides.next().unwrap();
286 assert!(strides.next().is_none());
287
288 assert_eq!(stride0.width(), 2);
289 assert_eq!(stride1.width(), 1);
290
291 stride0[(0, 0)] = 88;
292 stride1[(1, 0)] = 99;
293 }
294
295 assert_eq!(data[0], 88);
296 assert_eq!(data[5], 99);
297 }
298
299 #[test]
300 fn test_parallel_strides() {
301 let mut data = array::from_fn::<_, 12, _>(|i| i);
302 let arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
303
304 {
305 let mut strides: Vec<_> = arr.into_par_strides(2).collect();
306 assert_eq!(strides.len(), 2);
307 assert_eq!(strides[0].width(), 2);
308 assert_eq!(strides[1].width(), 1);
309
310 strides[0][(0, 0)] = 88;
311 strides[1][(1, 0)] = 99;
312 }
313
314 assert_eq!(data[0], 88);
315 assert_eq!(data[5], 99);
316 }
317
318 #[test]
319 fn test_iter_column_mut() {
320 let mut data = array::from_fn::<_, 12, _>(|i| i);
321 let data_clone = data;
322 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
323
324 let mut col_iter = arr.iter_column_mut(1);
325 assert_eq!(col_iter.next().copied(), Some(data_clone[1]));
326 assert_eq!(col_iter.next().copied(), Some(data_clone[4]));
327 assert_eq!(col_iter.next().copied(), Some(data_clone[7]));
328 assert_eq!(col_iter.next().copied(), Some(data_clone[10]));
329 assert_eq!(col_iter.next(), None);
330 }
331
332 #[test]
333 fn test_col_mut_indexing() {
334 let mut data = array::from_fn::<_, 12, _>(|i| i);
335 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
336
337 let mut cols: Vec<_> = arr.iter_cols().collect();
338 assert_eq!(cols.len(), 3);
339
340 assert_eq!(cols[1][0], 1);
342 assert_eq!(cols[1][1], 4);
343 assert_eq!(cols[1][2], 7);
344 assert_eq!(cols[1][3], 10);
345
346 cols[0][2] = 88;
348 cols[2][1] = 99;
349
350 assert_eq!(data[6], 88); assert_eq!(data[5], 99); }
353
354 #[test]
355 fn test_iter_cols() {
356 let mut data = array::from_fn::<_, 12, _>(|i| i);
357 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
358
359 {
360 let mut cols = arr.iter_cols();
361 let mut col0 = cols.next().unwrap();
362 let mut col1 = cols.next().unwrap();
363 let mut col2 = cols.next().unwrap();
364 assert!(cols.next().is_none());
365
366 assert_eq!(col0.height(), 4);
367 assert_eq!(col1.height(), 4);
368 assert_eq!(col2.height(), 4);
369
370 col0[0] = 88;
371 col1[1] = 99;
372 col2[3] = 77;
373 }
374
375 assert_eq!(data[0], 88); assert_eq!(data[4], 99); assert_eq!(data[11], 77); }
379
380 #[test]
381 fn test_par_iter_cols() {
382 let mut data = array::from_fn::<_, 12, _>(|i| i);
383 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
384
385 {
386 let mut cols: Vec<_> = arr.par_iter_cols().collect();
387 assert_eq!(cols.len(), 3);
388
389 cols[0][0] = 88;
390 cols[1][1] = 99;
391 cols[2][3] = 77;
392 }
393
394 assert_eq!(data[0], 88); assert_eq!(data[4], 99); assert_eq!(data[11], 77); }
398}