1use std::{
4 marker::PhantomData,
5 ops::{Index, IndexMut, Range},
6 slice,
7};
8
9use crate::rayon::prelude::*;
10
11#[derive(Debug, thiserror::Error)]
12pub enum Error {
13 #[error("dimensions do not match data size")]
14 DimensionMismatch,
15}
16
17#[derive(Debug)]
20pub struct StridedArray2DViewMut<'a, T> {
21 data: *mut T,
22 data_width: usize,
23 height: usize,
24 cols: Range<usize>,
25 _marker: PhantomData<&'a mut [T]>,
26}
27
28unsafe impl<T: Send> Send for StridedArray2DViewMut<'_, T> {}
30unsafe impl<T: Sync> Sync for StridedArray2DViewMut<'_, T> {}
32
33impl<'a, T> StridedArray2DViewMut<'a, T> {
34 pub const fn without_stride(
36 data: &'a mut [T],
37 height: usize,
38 width: usize,
39 ) -> Result<Self, Error> {
40 if width * height != data.len() {
41 return Err(Error::DimensionMismatch);
42 }
43 Ok(Self {
44 data: data.as_mut_ptr(),
45 data_width: width,
46 height,
47 cols: 0..width,
48 _marker: PhantomData,
49 })
50 }
51
52 pub unsafe fn get_unchecked_ref(&self, i: usize, j: usize) -> &T {
56 debug_assert!(i < self.height);
57 debug_assert!(j < self.width());
58 unsafe { &*self.data.add(i * self.data_width + j + self.cols.start) }
65 }
66
67 pub unsafe fn get_unchecked_mut(&mut self, i: usize, j: usize) -> &mut T {
71 debug_assert!(i < self.height);
72 debug_assert!(j < self.width());
73 unsafe { &mut *self.data.add(i * self.data_width + j + self.cols.start) }
80 }
81
82 pub fn row(&self, i: usize) -> &[T] {
88 assert!(i < self.height);
89 let start = i * self.data_width + self.cols.start;
90 unsafe { slice::from_raw_parts(self.data.add(start), self.width()) }
96 }
97
98 pub fn rows_mut<const M: usize, const S: usize>(
105 &mut self,
106 mut_rows: [usize; M],
107 shared_rows: [usize; S],
108 ) -> ([&mut [T]; M], [&[T]; S]) {
109 for &shared in &shared_rows {
110 assert!(shared < self.height);
111 }
112 for (k, &row) in mut_rows.iter().enumerate() {
113 assert!(row < self.height);
114 assert!(!mut_rows[..k].contains(&row), "a mutable row repeats");
115 assert!(!shared_rows.contains(&row), "a mutable row is also a shared row");
116 }
117
118 let (data_width, start, width) = (self.data_width, self.cols.start, self.width());
119 let base = self.data;
120 unsafe {
127 (
128 mut_rows
129 .map(|i| slice::from_raw_parts_mut(base.add(i * data_width + start), width)),
130 shared_rows.map(|i| slice::from_raw_parts(base.add(i * data_width + start), width)),
131 )
132 }
133 }
134
135 pub const fn height(&self) -> usize {
136 self.height
137 }
138
139 pub const fn width(&self) -> usize {
140 self.cols.end - self.cols.start
141 }
142
143 pub fn iter_column_mut(&mut self, col: usize) -> impl Iterator<Item = &mut T> + '_ {
145 assert!(col < self.width());
146 let start = col + self.cols.start;
147 let data = self.data;
148 (0..self.height).map(move |i|
149 unsafe { &mut *data.add(i * self.data_width + start) })
154 }
155
156 pub fn into_strides(self, stride: usize) -> impl Iterator<Item = Self> + 'a {
158 let Self {
159 data,
160 data_width,
161 height,
162 cols,
163 ..
164 } = self;
165
166 cols.clone().step_by(stride).map(move |start| {
167 let end = (start + stride).min(cols.end);
168 Self {
169 data,
170 data_width,
171 height,
172 cols: start..end,
173 _marker: PhantomData,
174 }
175 })
176 }
177
178 pub fn into_par_strides(self, stride: usize) -> impl IndexedParallelIterator<Item = Self> + 'a
180 where
181 T: Send + Sync,
182 {
183 let Self {
184 data,
185 data_width,
186 height,
187 cols,
188 ..
189 } = self;
190 let data = SendPtr(data);
191
192 cols.clone()
193 .into_par_iter()
194 .step_by(stride)
195 .map(move |start| {
196 let end = (start + stride).min(cols.end);
197 Self {
198 data: data.as_ptr(),
199 data_width,
200 height,
201 cols: start..end,
202 _marker: PhantomData,
203 }
204 })
205 }
206
207 pub fn iter_cols(&mut self) -> impl Iterator<Item = StridedArray2DColMut<'_, T>> + '_ {
209 let data = self.data;
210 self.cols.clone().map(move |col| StridedArray2DColMut {
211 data,
212 data_width: self.data_width,
213 height: self.height,
214 col,
215 _marker: PhantomData,
216 })
217 }
218
219 pub fn par_iter_cols(
221 &mut self,
222 ) -> impl IndexedParallelIterator<Item = StridedArray2DColMut<'_, T>> + '_
223 where
224 T: Send + Sync,
225 {
226 let data = SendPtr(self.data);
227 let data_width = self.data_width;
228 let height = self.height;
229 self.cols
230 .clone()
231 .into_par_iter()
232 .map(move |col| StridedArray2DColMut {
233 data: data.as_ptr(),
234 data_width,
235 height,
236 col,
237 _marker: PhantomData,
238 })
239 }
240}
241
242#[derive(Debug)]
244pub struct StridedArray2DColMut<'a, T> {
245 data: *mut T,
246 data_width: usize,
247 height: usize,
248 col: usize,
249 _marker: PhantomData<&'a mut [T]>,
250}
251
252unsafe impl<T: Send> Send for StridedArray2DColMut<'_, T> {}
254unsafe impl<T: Sync> Sync for StridedArray2DColMut<'_, T> {}
256
257impl<'a, T> StridedArray2DColMut<'a, T> {
258 pub const fn height(&self) -> usize {
259 self.height
260 }
261
262 pub unsafe fn get_unchecked_ref(&self, i: usize) -> &T {
266 debug_assert!(i < self.height);
267 unsafe { &*self.data.add(i * self.data_width + self.col) }
274 }
275
276 pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut T {
280 debug_assert!(i < self.height);
281 unsafe { &mut *self.data.add(i * self.data_width + self.col) }
288 }
289}
290
291impl<T> Index<usize> for StridedArray2DColMut<'_, T> {
292 type Output = T;
293
294 fn index(&self, i: usize) -> &T {
295 assert!(i < self.height());
296 unsafe { self.get_unchecked_ref(i) }
297 }
298}
299
300impl<T> IndexMut<usize> for StridedArray2DColMut<'_, T> {
301 fn index_mut(&mut self, i: usize) -> &mut Self::Output {
302 assert!(i < self.height());
303 unsafe { self.get_unchecked_mut(i) }
304 }
305}
306
307impl<T> Index<(usize, usize)> for StridedArray2DViewMut<'_, T> {
308 type Output = T;
309
310 fn index(&self, (i, j): (usize, usize)) -> &T {
311 assert!(i < self.height());
312 assert!(j < self.width());
313 unsafe { self.get_unchecked_ref(i, j) }
314 }
315}
316
317impl<T> IndexMut<(usize, usize)> for StridedArray2DViewMut<'_, T> {
318 fn index_mut(&mut self, (i, j): (usize, usize)) -> &mut Self::Output {
319 assert!(i < self.height());
320 assert!(j < self.width());
321 unsafe { self.get_unchecked_mut(i, j) }
322 }
323}
324
325struct SendPtr<T>(*mut T);
331
332impl<T> SendPtr<T> {
333 const fn as_ptr(self) -> *mut T {
334 self.0
335 }
336}
337
338impl<T> Clone for SendPtr<T> {
339 fn clone(&self) -> Self {
340 *self
341 }
342}
343
344impl<T> Copy for SendPtr<T> {}
345
346unsafe impl<T: Send> Send for SendPtr<T> {}
348unsafe impl<T: Sync> Sync for SendPtr<T> {}
349
350#[cfg(test)]
351mod tests {
352 use std::array;
353
354 use super::*;
355
356 #[test]
357 fn test_indexing() {
358 let mut data = array::from_fn::<_, 12, _>(|i| i);
359 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
360 assert_eq!(arr[(3, 1)], 10);
361 arr[(2, 2)] = 88;
362 assert_eq!(data[8], 88);
363 }
364
365 #[test]
366 fn test_strides() {
367 let mut data = array::from_fn::<_, 12, _>(|i| i);
368 let arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
369
370 {
371 let mut strides = arr.into_strides(2);
372 let mut stride0 = strides.next().unwrap();
373 let mut stride1 = strides.next().unwrap();
374 assert!(strides.next().is_none());
375
376 assert_eq!(stride0.width(), 2);
377 assert_eq!(stride1.width(), 1);
378
379 stride0[(0, 0)] = 88;
380 stride1[(1, 0)] = 99;
381 }
382
383 assert_eq!(data[0], 88);
384 assert_eq!(data[5], 99);
385 }
386
387 #[test]
388 fn test_parallel_strides() {
389 let mut data = array::from_fn::<_, 12, _>(|i| i);
390 let arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
391
392 {
393 let mut strides: Vec<_> = arr.into_par_strides(2).collect();
394 assert_eq!(strides.len(), 2);
395 assert_eq!(strides[0].width(), 2);
396 assert_eq!(strides[1].width(), 1);
397
398 strides[0][(0, 0)] = 88;
399 strides[1][(1, 0)] = 99;
400 }
401
402 assert_eq!(data[0], 88);
403 assert_eq!(data[5], 99);
404 }
405
406 #[test]
407 fn a_row_covers_only_the_columns_the_view_holds() {
408 let mut data = array::from_fn::<_, 12, _>(|i| i);
409 let arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
410
411 assert_eq!(arr.row(1), &[3, 4, 5]);
413
414 let stride = arr.into_strides(2).nth(1).unwrap();
416 assert_eq!(stride.row(1), &[5]);
417 }
418
419 #[test]
420 fn split_rows_alias_nothing_and_write_through() {
421 let mut data = array::from_fn::<_, 12, _>(|i| i);
422 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
423
424 let ([sum, diff], [x, y]) = arr.rows_mut([0, 1], [2, 3]);
425 assert_eq!(x, &[6, 7, 8]);
426 assert_eq!(y, &[9, 10, 11]);
427 for i in 0..3 {
428 sum[i] = x[i] + y[i];
429 diff[i] = y[i] - x[i];
430 }
431
432 assert_eq!(&data[0..3], &[15, 17, 19]);
433 assert_eq!(&data[3..6], &[3, 3, 3]);
434 }
435
436 #[test]
437 #[should_panic(expected = "a mutable row is also a shared row")]
438 fn a_mutable_row_may_not_be_a_shared_row() {
439 let mut data = array::from_fn::<_, 12, _>(|i| i);
440 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
441 arr.rows_mut([1], [0, 1]);
442 }
443
444 #[test]
445 #[should_panic(expected = "a mutable row repeats")]
446 fn two_mutable_rows_may_not_name_one_row() {
447 let mut data = array::from_fn::<_, 12, _>(|i| i);
448 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
449 arr.rows_mut([2, 2], [0]);
450 }
451
452 #[test]
453 fn test_iter_column_mut() {
454 let mut data = array::from_fn::<_, 12, _>(|i| i);
455 let data_clone = data;
456 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
457
458 let mut col_iter = arr.iter_column_mut(1);
459 assert_eq!(col_iter.next().copied(), Some(data_clone[1]));
460 assert_eq!(col_iter.next().copied(), Some(data_clone[4]));
461 assert_eq!(col_iter.next().copied(), Some(data_clone[7]));
462 assert_eq!(col_iter.next().copied(), Some(data_clone[10]));
463 assert_eq!(col_iter.next(), None);
464 }
465
466 #[test]
467 fn test_col_mut_indexing() {
468 let mut data = array::from_fn::<_, 12, _>(|i| i);
469 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
470
471 let mut cols: Vec<_> = arr.iter_cols().collect();
472 assert_eq!(cols.len(), 3);
473
474 assert_eq!(cols[1][0], 1);
476 assert_eq!(cols[1][1], 4);
477 assert_eq!(cols[1][2], 7);
478 assert_eq!(cols[1][3], 10);
479
480 cols[0][2] = 88;
482 cols[2][1] = 99;
483
484 assert_eq!(data[6], 88); assert_eq!(data[5], 99); }
487
488 #[test]
489 fn test_iter_cols() {
490 let mut data = array::from_fn::<_, 12, _>(|i| i);
491 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
492
493 {
494 let mut cols = arr.iter_cols();
495 let mut col0 = cols.next().unwrap();
496 let mut col1 = cols.next().unwrap();
497 let mut col2 = cols.next().unwrap();
498 assert!(cols.next().is_none());
499
500 assert_eq!(col0.height(), 4);
501 assert_eq!(col1.height(), 4);
502 assert_eq!(col2.height(), 4);
503
504 col0[0] = 88;
505 col1[1] = 99;
506 col2[3] = 77;
507 }
508
509 assert_eq!(data[0], 88); assert_eq!(data[4], 99); assert_eq!(data[11], 77); }
513
514 #[test]
515 fn test_views_are_send_and_sync() {
516 fn assert_send_sync<T: Send + Sync>() {}
517 assert_send_sync::<StridedArray2DViewMut<'_, usize>>();
518 assert_send_sync::<StridedArray2DColMut<'_, usize>>();
519 }
520
521 #[test]
522 fn test_par_iter_cols() {
523 let mut data = array::from_fn::<_, 12, _>(|i| i);
524 let mut arr = StridedArray2DViewMut::without_stride(&mut data, 4, 3).unwrap();
525
526 {
527 let mut cols: Vec<_> = arr.par_iter_cols().collect();
528 assert_eq!(cols.len(), 3);
529
530 cols[0][0] = 88;
531 cols[1][1] = 99;
532 cols[2][3] = 77;
533 }
534
535 assert_eq!(data[0], 88); assert_eq!(data[4], 99); assert_eq!(data[11], 77); }
539}