nalgebra/base/
matrix_slice.rs

1use std::marker::PhantomData;
2use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
3use std::slice;
4
5use crate::base::allocator::Allocator;
6use crate::base::default_allocator::DefaultAllocator;
7use crate::base::dimension::{Const, Dim, DimName, Dynamic, IsNotStaticOne, U1};
8use crate::base::iter::MatrixIter;
9use crate::base::storage::{IsContiguous, Owned, RawStorage, RawStorageMut, Storage};
10use crate::base::{Matrix, Scalar};
11
12macro_rules! slice_storage_impl(
13    ($doc: expr; $Storage: ident as $SRef: ty; $T: ident.$get_addr: ident ($Ptr: ty as $Ref: ty)) => {
14        #[doc = $doc]
15        #[derive(Debug)]
16        pub struct $T<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> {
17            ptr:       $Ptr,
18            shape:     (R, C),
19            strides:   (RStride, CStride),
20            _phantoms: PhantomData<$Ref>,
21        }
22
23        unsafe impl<'a, T: Send, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Send
24            for $T<'a, T, R, C, RStride, CStride>
25        {}
26
27        unsafe impl<'a, T: Sync, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Sync
28            for $T<'a, T, R, C, RStride, CStride>
29        {}
30
31        impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> $T<'a, T, R, C, RStride, CStride> {
32            /// Create a new matrix slice without bound checking and from a raw pointer.
33            #[inline]
34            pub unsafe fn from_raw_parts(ptr:     $Ptr,
35                                         shape:   (R, C),
36                                         strides: (RStride, CStride))
37                                        -> Self
38                where RStride: Dim,
39                      CStride: Dim {
40
41                $T {
42                    ptr,
43                    shape,
44                    strides,
45                    _phantoms: PhantomData
46                }
47            }
48        }
49
50        // Dynamic is arbitrary. It's just to be able to call the constructors with `Slice::`
51        impl<'a, T, R: Dim, C: Dim> $T<'a, T, R, C, Dynamic, Dynamic> {
52            /// Create a new matrix slice without bound checking.
53            #[inline]
54            pub unsafe fn new_unchecked<RStor, CStor, S>(storage: $SRef, start: (usize, usize), shape: (R, C))
55                -> $T<'a, T, R, C, S::RStride, S::CStride>
56                where RStor: Dim,
57                      CStor: Dim,
58                      S:     $Storage<T, RStor, CStor> {
59
60                let strides = storage.strides();
61                $T::new_with_strides_unchecked(storage, start, shape, strides)
62            }
63
64            /// Create a new matrix slice without bound checking.
65            #[inline]
66            pub unsafe fn new_with_strides_unchecked<S, RStor, CStor, RStride, CStride>(storage: $SRef,
67                                                                                        start:   (usize, usize),
68                                                                                        shape:   (R, C),
69                                                                                        strides: (RStride, CStride))
70                -> $T<'a, T, R, C, RStride, CStride>
71                where RStor: Dim,
72                      CStor: Dim,
73                      S: $Storage<T, RStor, CStor>,
74                      RStride: Dim,
75                      CStride: Dim {
76                $T::from_raw_parts(storage.$get_addr(start.0, start.1), shape, strides)
77            }
78        }
79
80        impl <'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
81            $T<'a, T, R, C, RStride, CStride>
82        where
83            Self: RawStorage<T, R, C> + IsContiguous
84        {
85            /// Extracts the original slice from this storage
86            pub fn into_slice(self) -> &'a [T] {
87                let (nrows, ncols) = self.shape();
88                if nrows.value() != 0 && ncols.value() != 0 {
89                    let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1);
90                    unsafe { slice::from_raw_parts(self.ptr, sz + 1) }
91                } else {
92                    unsafe { slice::from_raw_parts(self.ptr, 0) }
93                }
94            }
95        }
96    }
97);
98
99slice_storage_impl!("A matrix data storage for a matrix slice. Only contains an internal reference \
100                     to another matrix data storage.";
101    RawStorage as &'a S; SliceStorage.get_address_unchecked(*const T as &'a T));
102
103slice_storage_impl!("A mutable matrix data storage for mutable matrix slice. Only contains an \
104                     internal mutable reference to another matrix data storage.";
105    RawStorageMut as &'a mut S; SliceStorageMut.get_address_unchecked_mut(*mut T as &'a mut T)
106);
107
108impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Copy
109    for SliceStorage<'a, T, R, C, RStride, CStride>
110{
111}
112
113impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone
114    for SliceStorage<'a, T, R, C, RStride, CStride>
115{
116    #[inline]
117    fn clone(&self) -> Self {
118        Self {
119            ptr: self.ptr,
120            shape: self.shape,
121            strides: self.strides,
122            _phantoms: PhantomData,
123        }
124    }
125}
126
127impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
128    SliceStorageMut<'a, T, R, C, RStride, CStride>
129where
130    Self: RawStorageMut<T, R, C> + IsContiguous,
131{
132    /// Extracts the original slice from this storage
133    pub fn into_slice_mut(self) -> &'a mut [T] {
134        let (nrows, ncols) = self.shape();
135        if nrows.value() != 0 && ncols.value() != 0 {
136            let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1);
137            unsafe { slice::from_raw_parts_mut(self.ptr, sz + 1) }
138        } else {
139            unsafe { slice::from_raw_parts_mut(self.ptr, 0) }
140        }
141    }
142}
143
144macro_rules! storage_impl(
145    ($($T: ident),* $(,)*) => {$(
146        unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorage<T, R, C>
147            for $T<'a, T, R, C, RStride, CStride> {
148
149            type RStride = RStride;
150            type CStride = CStride;
151
152            #[inline]
153            fn ptr(&self) -> *const T {
154                self.ptr
155            }
156
157            #[inline]
158            fn shape(&self) -> (R, C) {
159                self.shape
160            }
161
162            #[inline]
163            fn strides(&self) -> (Self::RStride, Self::CStride) {
164                self.strides
165            }
166
167            #[inline]
168            fn is_contiguous(&self) -> bool {
169                // Common cases that can be deduced at compile-time even if one of the dimensions
170                // is Dynamic.
171                if (RStride::is::<U1>() && C::is::<U1>()) || // Column vector.
172                   (CStride::is::<U1>() && R::is::<U1>()) {  // Row vector.
173                    true
174                }
175                else {
176                    let (nrows, _)     = self.shape();
177                    let (srows, scols) = self.strides();
178
179                    srows.value() == 1 && scols.value() == nrows.value()
180                }
181            }
182
183            #[inline]
184            unsafe fn as_slice_unchecked(&self) -> &[T] {
185                let (nrows, ncols) = self.shape();
186                if nrows.value() != 0 && ncols.value() != 0 {
187                    let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1);
188                    slice::from_raw_parts(self.ptr, sz + 1)
189                }
190                else {
191                    slice::from_raw_parts(self.ptr, 0)
192                }
193            }
194        }
195
196        unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage<T, R, C>
197            for $T<'a, T, R, C, RStride, CStride> {
198            #[inline]
199            fn into_owned(self) -> Owned<T, R, C>
200                where DefaultAllocator: Allocator<T, R, C> {
201                self.clone_owned()
202            }
203
204            #[inline]
205            fn clone_owned(&self) -> Owned<T, R, C>
206                where DefaultAllocator: Allocator<T, R, C> {
207                let (nrows, ncols) = self.shape();
208                let it = MatrixIter::new(self).cloned();
209                DefaultAllocator::allocate_from_iterator(nrows, ncols, it)
210            }
211        }
212    )*}
213);
214
215storage_impl!(SliceStorage, SliceStorageMut);
216
217unsafe impl<'a, T, R: Dim, C: Dim, RStride: Dim, CStride: Dim> RawStorageMut<T, R, C>
218    for SliceStorageMut<'a, T, R, C, RStride, CStride>
219{
220    #[inline]
221    fn ptr_mut(&mut self) -> *mut T {
222        self.ptr
223    }
224
225    #[inline]
226    unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] {
227        let (nrows, ncols) = self.shape();
228        if nrows.value() != 0 && ncols.value() != 0 {
229            let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1);
230            slice::from_raw_parts_mut(self.ptr, sz + 1)
231        } else {
232            slice::from_raw_parts_mut(self.ptr, 0)
233        }
234    }
235}
236
237unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous for SliceStorage<'a, T, R, U1, U1, CStride> {}
238unsafe impl<'a, T, R: Dim, CStride: Dim> IsContiguous
239    for SliceStorageMut<'a, T, R, U1, U1, CStride>
240{
241}
242
243unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
244    for SliceStorage<'a, T, R, C, U1, R>
245{
246}
247unsafe impl<'a, T, R: DimName, C: Dim + IsNotStaticOne> IsContiguous
248    for SliceStorageMut<'a, T, R, C, U1, R>
249{
250}
251
252impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
253    #[inline]
254    fn assert_slice_index(
255        &self,
256        start: (usize, usize),
257        shape: (usize, usize),
258        steps: (usize, usize),
259    ) {
260        let my_shape = self.shape();
261        // NOTE: we don't do any subtraction to avoid underflow for zero-sized matrices.
262        //
263        // Terms that would have been negative are moved to the other side of the inequality
264        // instead.
265        assert!(
266            start.0 + (steps.0 + 1) * shape.0 <= my_shape.0 + steps.0,
267            "Matrix slicing out of bounds."
268        );
269        assert!(
270            start.1 + (steps.1 + 1) * shape.1 <= my_shape.1 + steps.1,
271            "Matrix slicing out of bounds."
272        );
273    }
274}
275
276macro_rules! matrix_slice_impl(
277    ($me: ident: $Me: ty, $MatrixSlice: ident, $SliceStorage: ident, $Storage: ident.$get_addr: ident (), $data: expr;
278     $row: ident,
279     $row_part: ident,
280     $rows: ident,
281     $rows_with_step: ident,
282     $fixed_rows: ident,
283     $fixed_rows_with_step: ident,
284     $rows_generic: ident,
285     $rows_generic_with_step: ident,
286     $column: ident,
287     $column_part: ident,
288     $columns: ident,
289     $columns_with_step: ident,
290     $fixed_columns: ident,
291     $fixed_columns_with_step: ident,
292     $columns_generic: ident,
293     $columns_generic_with_step: ident,
294     $slice: ident,
295     $slice_with_steps: ident,
296     $fixed_slice: ident,
297     $fixed_slice_with_steps: ident,
298     $generic_slice: ident,
299     $generic_slice_with_steps: ident,
300     $rows_range_pair: ident,
301     $columns_range_pair: ident) => {
302        /*
303         *
304         * Row slicing.
305         *
306         */
307        /// Returns a slice containing the i-th row of this matrix.
308        #[inline]
309        pub fn $row($me: $Me, i: usize) -> $MatrixSlice<'_, T, U1, C, S::RStride, S::CStride> {
310            $me.$fixed_rows::<1>(i)
311        }
312
313        /// Returns a slice containing the `n` first elements of the i-th row of this matrix.
314        #[inline]
315        pub fn $row_part($me: $Me, i: usize, n: usize) -> $MatrixSlice<'_, T, U1, Dynamic, S::RStride, S::CStride> {
316            $me.$generic_slice((i, 0), (Const::<1>, Dynamic::new(n)))
317        }
318
319        /// Extracts from this matrix a set of consecutive rows.
320        #[inline]
321        pub fn $rows($me: $Me, first_row: usize, nrows: usize)
322            -> $MatrixSlice<'_, T, Dynamic, C, S::RStride, S::CStride> {
323
324            $me.$rows_generic(first_row, Dynamic::new(nrows))
325        }
326
327        /// Extracts from this matrix a set of consecutive rows regularly skipping `step` rows.
328        #[inline]
329        pub fn $rows_with_step($me: $Me, first_row: usize, nrows: usize, step: usize)
330            -> $MatrixSlice<'_, T, Dynamic, C, Dynamic, S::CStride> {
331
332            $me.$rows_generic_with_step(first_row, Dynamic::new(nrows), step)
333        }
334
335        /// Extracts a compile-time number of consecutive rows from this matrix.
336        #[inline]
337        pub fn $fixed_rows<const RSLICE: usize>($me: $Me, first_row: usize)
338            -> $MatrixSlice<'_, T, Const<RSLICE>, C, S::RStride, S::CStride> {
339
340            $me.$rows_generic(first_row, Const::<RSLICE>)
341        }
342
343        /// Extracts from this matrix a compile-time number of rows regularly skipping `step`
344        /// rows.
345        #[inline]
346        pub fn $fixed_rows_with_step<const RSLICE: usize>($me: $Me, first_row: usize, step: usize)
347            -> $MatrixSlice<'_, T, Const<RSLICE>, C, Dynamic, S::CStride> {
348
349            $me.$rows_generic_with_step(first_row, Const::<RSLICE>, step)
350        }
351
352        /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both
353        /// argument may or may not be values known at compile-time.
354        #[inline]
355        pub fn $rows_generic<RSlice: Dim>($me: $Me, row_start: usize, nrows: RSlice)
356            -> $MatrixSlice<'_, T, RSlice, C, S::RStride, S::CStride> {
357
358            let my_shape   = $me.shape_generic();
359            $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0));
360
361            let shape = (nrows, my_shape.1);
362
363            unsafe {
364                let data = $SliceStorage::new_unchecked($data, (row_start, 0), shape);
365                Matrix::from_data_statically_unchecked(data)
366            }
367        }
368
369        /// Extracts from this matrix `nrows` rows regularly skipping `step` rows. Both
370        /// argument may or may not be values known at compile-time.
371        #[inline]
372        pub fn $rows_generic_with_step<RSlice>($me: $Me, row_start: usize, nrows: RSlice, step: usize)
373            -> $MatrixSlice<'_, T, RSlice, C, Dynamic, S::CStride>
374            where RSlice: Dim {
375
376            let my_shape   = $me.shape_generic();
377            let my_strides = $me.data.strides();
378            $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0));
379
380            let strides = (Dynamic::new((step + 1) * my_strides.0.value()), my_strides.1);
381            let shape   = (nrows, my_shape.1);
382
383            unsafe {
384                let data = $SliceStorage::new_with_strides_unchecked($data, (row_start, 0), shape, strides);
385                Matrix::from_data_statically_unchecked(data)
386            }
387        }
388
389        /*
390         *
391         * Column slicing.
392         *
393         */
394        /// Returns a slice containing the i-th column of this matrix.
395        #[inline]
396        pub fn $column($me: $Me, i: usize) -> $MatrixSlice<'_, T, R, U1, S::RStride, S::CStride> {
397            $me.$fixed_columns::<1>(i)
398        }
399
400        /// Returns a slice containing the `n` first elements of the i-th column of this matrix.
401        #[inline]
402        pub fn $column_part($me: $Me, i: usize, n: usize) -> $MatrixSlice<'_, T, Dynamic, U1, S::RStride, S::CStride> {
403            $me.$generic_slice((0, i), (Dynamic::new(n), Const::<1>))
404        }
405
406        /// Extracts from this matrix a set of consecutive columns.
407        #[inline]
408        pub fn $columns($me: $Me, first_col: usize, ncols: usize)
409            -> $MatrixSlice<'_, T, R, Dynamic, S::RStride, S::CStride> {
410
411            $me.$columns_generic(first_col, Dynamic::new(ncols))
412        }
413
414        /// Extracts from this matrix a set of consecutive columns regularly skipping `step`
415        /// columns.
416        #[inline]
417        pub fn $columns_with_step($me: $Me, first_col: usize, ncols: usize, step: usize)
418            -> $MatrixSlice<'_, T, R, Dynamic, S::RStride, Dynamic> {
419
420            $me.$columns_generic_with_step(first_col, Dynamic::new(ncols), step)
421        }
422
423        /// Extracts a compile-time number of consecutive columns from this matrix.
424        #[inline]
425        pub fn $fixed_columns<const CSLICE: usize>($me: $Me, first_col: usize)
426            -> $MatrixSlice<'_, T, R, Const<CSLICE>, S::RStride, S::CStride> {
427
428            $me.$columns_generic(first_col, Const::<CSLICE>)
429        }
430
431        /// Extracts from this matrix a compile-time number of columns regularly skipping
432        /// `step` columns.
433        #[inline]
434        pub fn $fixed_columns_with_step<const CSLICE: usize>($me: $Me, first_col: usize, step: usize)
435            -> $MatrixSlice<'_, T, R, Const<CSLICE>, S::RStride, Dynamic> {
436
437            $me.$columns_generic_with_step(first_col, Const::<CSLICE>, step)
438        }
439
440        /// Extracts from this matrix `ncols` columns. The number of columns may or may not be
441        /// known at compile-time.
442        #[inline]
443        pub fn $columns_generic<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice)
444            -> $MatrixSlice<'_, T, R, CSlice, S::RStride, S::CStride> {
445
446            let my_shape = $me.shape_generic();
447            $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0));
448            let shape = (my_shape.0, ncols);
449
450            unsafe {
451                let data = $SliceStorage::new_unchecked($data, (0, first_col), shape);
452                Matrix::from_data_statically_unchecked(data)
453            }
454        }
455
456
457        /// Extracts from this matrix `ncols` columns skipping `step` columns. Both argument may
458        /// or may not be values known at compile-time.
459        #[inline]
460        pub fn $columns_generic_with_step<CSlice: Dim>($me: $Me, first_col: usize, ncols: CSlice, step: usize)
461            -> $MatrixSlice<'_, T, R, CSlice, S::RStride, Dynamic> {
462
463            let my_shape   = $me.shape_generic();
464            let my_strides = $me.data.strides();
465
466            $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step));
467
468            let strides = (my_strides.0, Dynamic::new((step + 1) * my_strides.1.value()));
469            let shape   = (my_shape.0, ncols);
470
471            unsafe {
472                let data = $SliceStorage::new_with_strides_unchecked($data, (0, first_col), shape, strides);
473                Matrix::from_data_statically_unchecked(data)
474            }
475        }
476
477        /*
478         *
479         * General slicing.
480         *
481         */
482        /// Slices this matrix starting at its component `(irow, icol)` and with `(nrows, ncols)`
483        /// consecutive elements.
484        #[inline]
485        pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize))
486            -> $MatrixSlice<'_, T, Dynamic, Dynamic, S::RStride, S::CStride> {
487
488            $me.assert_slice_index(start, shape, (0, 0));
489            let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1));
490
491            unsafe {
492                let data = $SliceStorage::new_unchecked($data, start, shape);
493                Matrix::from_data_statically_unchecked(data)
494            }
495        }
496
497
498        /// Slices this matrix starting at its component `(start.0, start.1)` and with
499        /// `(shape.0, shape.1)` components. Each row (resp. column) of the sliced matrix is
500        /// separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of the
501        /// original matrix.
502        #[inline]
503        pub fn $slice_with_steps($me: $Me, start: (usize, usize), shape: (usize, usize), steps: (usize, usize))
504            -> $MatrixSlice<'_, T, Dynamic, Dynamic, Dynamic, Dynamic> {
505            let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1));
506
507            $me.$generic_slice_with_steps(start, shape, steps)
508        }
509
510        /// Slices this matrix starting at its component `(irow, icol)` and with `(R::dim(),
511        /// CSlice::dim())` consecutive components.
512        #[inline]
513        pub fn $fixed_slice<const RSLICE: usize, const CSLICE: usize>($me: $Me, irow: usize, icol: usize)
514            -> $MatrixSlice<'_, T, Const<RSLICE>, Const<CSLICE>, S::RStride, S::CStride> {
515
516            $me.assert_slice_index((irow, icol), (RSLICE, CSLICE), (0, 0));
517            let shape = (Const::<RSLICE>, Const::<CSLICE>);
518
519            unsafe {
520                let data = $SliceStorage::new_unchecked($data, (irow, icol), shape);
521                Matrix::from_data_statically_unchecked(data)
522            }
523        }
524
525        /// Slices this matrix starting at its component `(start.0, start.1)` and with
526        /// `(RSLICE, CSLICE)` components. Each row (resp. column) of the sliced
527        /// matrix is separated by `steps.0` (resp. `steps.1`) ignored rows (resp. columns) of
528        /// the original matrix.
529        #[inline]
530        pub fn $fixed_slice_with_steps<const RSLICE: usize, const CSLICE: usize>($me: $Me, start: (usize, usize), steps: (usize, usize))
531            -> $MatrixSlice<'_, T, Const<RSLICE>, Const<CSLICE>, Dynamic, Dynamic> {
532            let shape = (Const::<RSLICE>, Const::<CSLICE>);
533            $me.$generic_slice_with_steps(start, shape, steps)
534        }
535
536        /// Creates a slice that may or may not have a fixed size and stride.
537        #[inline]
538        pub fn $generic_slice<RSlice, CSlice>($me: $Me, start: (usize, usize), shape: (RSlice, CSlice))
539            -> $MatrixSlice<'_, T, RSlice, CSlice, S::RStride, S::CStride>
540            where RSlice: Dim,
541                  CSlice: Dim {
542
543            $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0));
544
545            unsafe {
546                let data = $SliceStorage::new_unchecked($data, start, shape);
547                Matrix::from_data_statically_unchecked(data)
548            }
549        }
550
551        /// Creates a slice that may or may not have a fixed size and stride.
552        #[inline]
553        pub fn $generic_slice_with_steps<RSlice, CSlice>($me: $Me,
554                                                         start: (usize, usize),
555                                                         shape: (RSlice, CSlice),
556                                                         steps: (usize, usize))
557            -> $MatrixSlice<'_, T, RSlice, CSlice, Dynamic, Dynamic>
558            where RSlice: Dim,
559                  CSlice: Dim {
560
561            $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), steps);
562
563            let my_strides = $me.data.strides();
564            let strides    = (Dynamic::new((steps.0 + 1) * my_strides.0.value()),
565                              Dynamic::new((steps.1 + 1) * my_strides.1.value()));
566
567            unsafe {
568                let data = $SliceStorage::new_with_strides_unchecked($data, start, shape, strides);
569                Matrix::from_data_statically_unchecked(data)
570            }
571        }
572
573        /*
574         *
575         * Splitting.
576         *
577         */
578        /// Splits this `NxM` matrix into two parts delimited by two ranges.
579        ///
580        /// Panics if the ranges overlap or if the first range is empty.
581        #[inline]
582        pub fn $rows_range_pair<Range1: SliceRange<R>, Range2: SliceRange<R>>($me: $Me, r1: Range1, r2: Range2)
583            -> ($MatrixSlice<'_, T, Range1::Size, C, S::RStride, S::CStride>,
584                $MatrixSlice<'_, T, Range2::Size, C, S::RStride, S::CStride>) {
585
586            let (nrows, ncols) = $me.shape_generic();
587            let strides        = $me.data.strides();
588
589            let start1 = r1.begin(nrows);
590            let start2 = r2.begin(nrows);
591
592            let end1 = r1.end(nrows);
593            let end2 = r2.end(nrows);
594
595            let nrows1 = r1.size(nrows);
596            let nrows2 = r2.size(nrows);
597
598            assert!(start2 >= end1 || start1 >= end2, "Rows range pair: the slice ranges must not overlap.");
599            assert!(end2 <= nrows.value(), "Rows range pair: index out of range.");
600
601            unsafe {
602                let ptr1 = $data.$get_addr(start1, 0);
603                let ptr2 = $data.$get_addr(start2, 0);
604
605                let data1  = $SliceStorage::from_raw_parts(ptr1, (nrows1, ncols), strides);
606                let data2  = $SliceStorage::from_raw_parts(ptr2, (nrows2, ncols), strides);
607                let slice1 = Matrix::from_data_statically_unchecked(data1);
608                let slice2 = Matrix::from_data_statically_unchecked(data2);
609
610                (slice1, slice2)
611            }
612        }
613
614        /// Splits this `NxM` matrix into two parts delimited by two ranges.
615        ///
616        /// Panics if the ranges overlap or if the first range is empty.
617        #[inline]
618        pub fn $columns_range_pair<Range1: SliceRange<C>, Range2: SliceRange<C>>($me: $Me, r1: Range1, r2: Range2)
619            -> ($MatrixSlice<'_, T, R, Range1::Size, S::RStride, S::CStride>,
620                $MatrixSlice<'_, T, R, Range2::Size, S::RStride, S::CStride>) {
621
622            let (nrows, ncols) = $me.shape_generic();
623            let strides        = $me.data.strides();
624
625            let start1 = r1.begin(ncols);
626            let start2 = r2.begin(ncols);
627
628            let end1 = r1.end(ncols);
629            let end2 = r2.end(ncols);
630
631            let ncols1 = r1.size(ncols);
632            let ncols2 = r2.size(ncols);
633
634            assert!(start2 >= end1 || start1 >= end2, "Columns range pair: the slice ranges must not overlap.");
635            assert!(end2 <= ncols.value(), "Columns range pair: index out of range.");
636
637            unsafe {
638                let ptr1 = $data.$get_addr(0, start1);
639                let ptr2 = $data.$get_addr(0, start2);
640
641                let data1  = $SliceStorage::from_raw_parts(ptr1, (nrows, ncols1), strides);
642                let data2  = $SliceStorage::from_raw_parts(ptr2, (nrows, ncols2), strides);
643                let slice1 = Matrix::from_data_statically_unchecked(data1);
644                let slice2 = Matrix::from_data_statically_unchecked(data2);
645
646                (slice1, slice2)
647            }
648        }
649    }
650);
651
652/// A matrix slice.
653pub type MatrixSlice<'a, T, R, C, RStride = U1, CStride = R> =
654    Matrix<T, R, C, SliceStorage<'a, T, R, C, RStride, CStride>>;
655/// A mutable matrix slice.
656pub type MatrixSliceMut<'a, T, R, C, RStride = U1, CStride = R> =
657    Matrix<T, R, C, SliceStorageMut<'a, T, R, C, RStride, CStride>>;
658
659/// # Slicing based on index and length
660impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
661    matrix_slice_impl!(
662     self: &Self, MatrixSlice, SliceStorage, RawStorage.get_address_unchecked(), &self.data;
663     row,
664     row_part,
665     rows,
666     rows_with_step,
667     fixed_rows,
668     fixed_rows_with_step,
669     rows_generic,
670     rows_generic_with_step,
671     column,
672     column_part,
673     columns,
674     columns_with_step,
675     fixed_columns,
676     fixed_columns_with_step,
677     columns_generic,
678     columns_generic_with_step,
679     slice,
680     slice_with_steps,
681     fixed_slice,
682     fixed_slice_with_steps,
683     generic_slice,
684     generic_slice_with_steps,
685     rows_range_pair,
686     columns_range_pair);
687}
688
689/// # Mutable slicing based on index and length
690impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
691    matrix_slice_impl!(
692     self: &mut Self, MatrixSliceMut, SliceStorageMut, RawStorageMut.get_address_unchecked_mut(), &mut self.data;
693     row_mut,
694     row_part_mut,
695     rows_mut,
696     rows_with_step_mut,
697     fixed_rows_mut,
698     fixed_rows_with_step_mut,
699     rows_generic_mut,
700     rows_generic_with_step_mut,
701     column_mut,
702     column_part_mut,
703     columns_mut,
704     columns_with_step_mut,
705     fixed_columns_mut,
706     fixed_columns_with_step_mut,
707     columns_generic_mut,
708     columns_generic_with_step_mut,
709     slice_mut,
710     slice_with_steps_mut,
711     fixed_slice_mut,
712     fixed_slice_with_steps_mut,
713     generic_slice_mut,
714     generic_slice_with_steps_mut,
715     rows_range_pair_mut,
716     columns_range_pair_mut);
717}
718
719/// A range with a size that may be known at compile-time.
720///
721/// This may be:
722/// * A single `usize` index, e.g., `4`
723/// * A left-open range `std::ops::RangeTo`, e.g., `.. 4`
724/// * A right-open range `std::ops::RangeFrom`, e.g., `4 ..`
725/// * A full range `std::ops::RangeFull`, e.g., `..`
726pub trait SliceRange<D: Dim> {
727    /// Type of the range size. May be a type-level integer.
728    type Size: Dim;
729
730    /// The start index of the range.
731    fn begin(&self, shape: D) -> usize;
732    // NOTE: this is the index immediately after the last index.
733    /// The index immediately after the last index inside of the range.
734    fn end(&self, shape: D) -> usize;
735    /// The number of elements of the range, i.e., `self.end - self.begin`.
736    fn size(&self, shape: D) -> Self::Size;
737}
738
739impl<D: Dim> SliceRange<D> for usize {
740    type Size = U1;
741
742    #[inline(always)]
743    fn begin(&self, _: D) -> usize {
744        *self
745    }
746
747    #[inline(always)]
748    fn end(&self, _: D) -> usize {
749        *self + 1
750    }
751
752    #[inline(always)]
753    fn size(&self, _: D) -> Self::Size {
754        Const::<1>
755    }
756}
757
758impl<D: Dim> SliceRange<D> for Range<usize> {
759    type Size = Dynamic;
760
761    #[inline(always)]
762    fn begin(&self, _: D) -> usize {
763        self.start
764    }
765
766    #[inline(always)]
767    fn end(&self, _: D) -> usize {
768        self.end
769    }
770
771    #[inline(always)]
772    fn size(&self, _: D) -> Self::Size {
773        Dynamic::new(self.end - self.start)
774    }
775}
776
777impl<D: Dim> SliceRange<D> for RangeFrom<usize> {
778    type Size = Dynamic;
779
780    #[inline(always)]
781    fn begin(&self, _: D) -> usize {
782        self.start
783    }
784
785    #[inline(always)]
786    fn end(&self, dim: D) -> usize {
787        dim.value()
788    }
789
790    #[inline(always)]
791    fn size(&self, dim: D) -> Self::Size {
792        Dynamic::new(dim.value() - self.start)
793    }
794}
795
796impl<D: Dim> SliceRange<D> for RangeTo<usize> {
797    type Size = Dynamic;
798
799    #[inline(always)]
800    fn begin(&self, _: D) -> usize {
801        0
802    }
803
804    #[inline(always)]
805    fn end(&self, _: D) -> usize {
806        self.end
807    }
808
809    #[inline(always)]
810    fn size(&self, _: D) -> Self::Size {
811        Dynamic::new(self.end)
812    }
813}
814
815impl<D: Dim> SliceRange<D> for RangeFull {
816    type Size = D;
817
818    #[inline(always)]
819    fn begin(&self, _: D) -> usize {
820        0
821    }
822
823    #[inline(always)]
824    fn end(&self, dim: D) -> usize {
825        dim.value()
826    }
827
828    #[inline(always)]
829    fn size(&self, dim: D) -> Self::Size {
830        dim
831    }
832}
833
834impl<D: Dim> SliceRange<D> for RangeInclusive<usize> {
835    type Size = Dynamic;
836
837    #[inline(always)]
838    fn begin(&self, _: D) -> usize {
839        *self.start()
840    }
841
842    #[inline(always)]
843    fn end(&self, _: D) -> usize {
844        *self.end() + 1
845    }
846
847    #[inline(always)]
848    fn size(&self, _: D) -> Self::Size {
849        Dynamic::new(*self.end() + 1 - *self.start())
850    }
851}
852
853// TODO: see how much of this overlaps with the general indexing
854// methods from indexing.rs.
855impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Matrix<T, R, C, S> {
856    /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed
857    /// by the range `cols`.
858    #[inline]
859    #[must_use]
860    pub fn slice_range<RowRange, ColRange>(
861        &self,
862        rows: RowRange,
863        cols: ColRange,
864    ) -> MatrixSlice<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride>
865    where
866        RowRange: SliceRange<R>,
867        ColRange: SliceRange<C>,
868    {
869        let (nrows, ncols) = self.shape_generic();
870        self.generic_slice(
871            (rows.begin(nrows), cols.begin(ncols)),
872            (rows.size(nrows), cols.size(ncols)),
873        )
874    }
875
876    /// Slice containing all the rows indexed by the range `rows`.
877    #[inline]
878    #[must_use]
879    pub fn rows_range<RowRange: SliceRange<R>>(
880        &self,
881        rows: RowRange,
882    ) -> MatrixSlice<'_, T, RowRange::Size, C, S::RStride, S::CStride> {
883        self.slice_range(rows, ..)
884    }
885
886    /// Slice containing all the columns indexed by the range `rows`.
887    #[inline]
888    #[must_use]
889    pub fn columns_range<ColRange: SliceRange<C>>(
890        &self,
891        cols: ColRange,
892    ) -> MatrixSlice<'_, T, R, ColRange::Size, S::RStride, S::CStride> {
893        self.slice_range(.., cols)
894    }
895}
896
897// TODO: see how much of this overlaps with the general indexing
898// methods from indexing.rs.
899impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> Matrix<T, R, C, S> {
900    /// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns
901    /// indexed by the range `cols`.
902    pub fn slice_range_mut<RowRange, ColRange>(
903        &mut self,
904        rows: RowRange,
905        cols: ColRange,
906    ) -> MatrixSliceMut<'_, T, RowRange::Size, ColRange::Size, S::RStride, S::CStride>
907    where
908        RowRange: SliceRange<R>,
909        ColRange: SliceRange<C>,
910    {
911        let (nrows, ncols) = self.shape_generic();
912        self.generic_slice_mut(
913            (rows.begin(nrows), cols.begin(ncols)),
914            (rows.size(nrows), cols.size(ncols)),
915        )
916    }
917
918    /// Slice containing all the rows indexed by the range `rows`.
919    #[inline]
920    pub fn rows_range_mut<RowRange: SliceRange<R>>(
921        &mut self,
922        rows: RowRange,
923    ) -> MatrixSliceMut<'_, T, RowRange::Size, C, S::RStride, S::CStride> {
924        self.slice_range_mut(rows, ..)
925    }
926
927    /// Slice containing all the columns indexed by the range `cols`.
928    #[inline]
929    pub fn columns_range_mut<ColRange: SliceRange<C>>(
930        &mut self,
931        cols: ColRange,
932    ) -> MatrixSliceMut<'_, T, R, ColRange::Size, S::RStride, S::CStride> {
933        self.slice_range_mut(.., cols)
934    }
935}
936
937impl<'a, T, R, C, RStride, CStride> From<MatrixSliceMut<'a, T, R, C, RStride, CStride>>
938    for MatrixSlice<'a, T, R, C, RStride, CStride>
939where
940    R: Dim,
941    C: Dim,
942    RStride: Dim,
943    CStride: Dim,
944{
945    fn from(slice_mut: MatrixSliceMut<'a, T, R, C, RStride, CStride>) -> Self {
946        let data = SliceStorage {
947            ptr: slice_mut.data.ptr,
948            shape: slice_mut.data.shape,
949            strides: slice_mut.data.strides,
950            _phantoms: PhantomData,
951        };
952
953        unsafe { Matrix::from_data_statically_unchecked(data) }
954    }
955}