nalgebra/base/
construction_view.rs

1use crate::base::dimension::{Const, Dim, DimName, Dyn};
2use crate::base::matrix_view::{ViewStorage, ViewStorageMut};
3use crate::base::{MatrixView, MatrixViewMut, Scalar};
4
5use num_rational::Ratio;
6
7/// # Creating matrix views from `&[T]`
8impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
9    MatrixView<'a, T, R, C, RStride, CStride>
10{
11    /// Creates, without bounds checking, a matrix view from an array and with dimensions and strides specified by generic types instances.
12    ///
13    /// # Safety
14    /// This method is unsafe because the input data array is not checked to contain enough elements.
15    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`.
16    #[inline]
17    pub const unsafe fn from_slice_with_strides_generic_unchecked(
18        data: &'a [T],
19        start: usize,
20        nrows: R,
21        ncols: C,
22        rstride: RStride,
23        cstride: CStride,
24    ) -> Self {
25        unsafe {
26            let data = ViewStorage::from_raw_parts(
27                data.as_ptr().add(start),
28                (nrows, ncols),
29                (rstride, cstride),
30            );
31            Self::from_data(data)
32        }
33    }
34
35    /// Creates a matrix view from an array and with dimensions and strides specified by generic types instances.
36    ///
37    /// Panics if the input data array dose not contain enough elements.
38    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`.
39    #[inline]
40    pub fn from_slice_with_strides_generic(
41        data: &'a [T],
42        nrows: R,
43        ncols: C,
44        rstride: RStride,
45        cstride: CStride,
46    ) -> Self {
47        // NOTE: The assertion implements the following formula, but without subtractions to avoid
48        // underflow panics:
49        //      len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1
50        assert!(
51            data.len() + cstride.value() + rstride.value()
52                >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1,
53            "Matrix view: input data buffer too small."
54        );
55
56        unsafe {
57            Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride)
58        }
59    }
60}
61
62impl<'a, T: Scalar, R: Dim, C: Dim> MatrixView<'a, T, R, C> {
63    /// Creates, without bound-checking, a matrix view from an array and with dimensions specified by generic types instances.
64    ///
65    /// # Safety
66    /// This method is unsafe because the input data array is not checked to contain enough elements.
67    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`.
68    #[inline]
69    pub unsafe fn from_slice_generic_unchecked(
70        data: &'a [T],
71        start: usize,
72        nrows: R,
73        ncols: C,
74    ) -> Self {
75        unsafe {
76            Self::from_slice_with_strides_generic_unchecked(
77                data, start, nrows, ncols, Const::<1>, nrows,
78            )
79        }
80    }
81
82    /// Creates a matrix view from an array and with dimensions and strides specified by generic types instances.
83    ///
84    /// Panics if the input data array dose not contain enough elements.
85    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`.
86    #[inline]
87    pub fn from_slice_generic(data: &'a [T], nrows: R, ncols: C) -> Self {
88        Self::from_slice_with_strides_generic(data, nrows, ncols, Const::<1>, nrows)
89    }
90}
91
92macro_rules! impl_constructors(
93    ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr_2021),*; $($args: ident),*) => {
94        impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixView<'a, T, $($Dims),*> {
95            /// Creates a new matrix view from the given data array.
96            ///
97            /// Panics if `data` does not contain enough elements.
98            #[inline]
99            pub fn from_slice(data: &'a [T], $($args: usize),*) -> Self {
100                Self::from_slice_generic(data, $($gargs),*)
101            }
102
103            /// Creates, without bound checking, a new matrix view from the given data array.
104            /// # Safety
105            /// `data[start..start+rstride * cstride]` must be within bounds.
106            #[inline]
107            pub unsafe fn from_slice_unchecked(data: &'a [T], start: usize, $($args: usize),*) -> Self { unsafe {
108                Self::from_slice_generic_unchecked(data, start, $($gargs),*)
109            }}
110        }
111
112        impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixView<'a, T, $($Dims,)* Dyn, Dyn> {
113            /// Creates a new matrix view with the specified strides from the given data array.
114            ///
115            /// Panics if `data` does not contain enough elements.
116            #[inline]
117            pub fn from_slice_with_strides(data: &'a [T], $($args: usize,)* rstride: usize, cstride: usize) -> Self {
118                Self::from_slice_with_strides_generic(data, $($gargs,)* Dyn(rstride), Dyn(cstride))
119            }
120
121            /// Creates, without bound checking, a new matrix view with the specified strides from the given data array.
122            ///
123            /// # Safety
124            ///
125            /// `start`, `rstride`, and `cstride`, with the given matrix size will not index
126            /// outside of `data`.
127            #[inline]
128            pub unsafe fn from_slice_with_strides_unchecked(data: &'a [T], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self { unsafe {
129                Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dyn(rstride), Dyn(cstride))
130            }}
131        }
132    }
133);
134
135// TODO: this is not very pretty. We could find a better call syntax.
136impl_constructors!(R, C;                         // Arguments for Matrix<T, ..., S>
137=> R: DimName, => C: DimName; // Type parameters for impl<T, ..., S>
138R::name(), C::name();         // Arguments for `_generic` constructors.
139); // Arguments for non-generic constructors.
140
141impl_constructors!(R, Dyn;
142                   => R: DimName;
143                   R::name(), Dyn(ncols);
144                   ncols);
145
146impl_constructors!(Dyn, C;
147                   => C: DimName;
148                   Dyn(nrows), C::name();
149                   nrows);
150
151impl_constructors!(Dyn, Dyn;
152                   ;
153                   Dyn(nrows), Dyn(ncols);
154                   nrows, ncols);
155
156/// # Creating mutable matrix views from `&mut [T]`
157impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
158    MatrixViewMut<'a, T, R, C, RStride, CStride>
159{
160    /// Creates, without bound-checking, a mutable matrix view from an array and with dimensions and strides specified by generic types instances.
161    ///
162    /// # Safety
163    /// This method is unsafe because the input data array is not checked to contain enough elements.
164    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`.
165    #[inline]
166    pub const unsafe fn from_slice_with_strides_generic_unchecked(
167        data: &'a mut [T],
168        start: usize,
169        nrows: R,
170        ncols: C,
171        rstride: RStride,
172        cstride: CStride,
173    ) -> Self {
174        unsafe {
175            let data = ViewStorageMut::from_raw_parts(
176                data.as_mut_ptr().add(start),
177                (nrows, ncols),
178                (rstride, cstride),
179            );
180            Self::from_data(data)
181        }
182    }
183
184    /// Creates a mutable matrix view from an array and with dimensions and strides specified by generic types instances.
185    ///
186    /// Panics if the input data array dose not contain enough elements.
187    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dyn()`.
188    #[inline]
189    pub fn from_slice_with_strides_generic(
190        data: &'a mut [T],
191        nrows: R,
192        ncols: C,
193        rstride: RStride,
194        cstride: CStride,
195    ) -> Self {
196        // NOTE: The assertion implements the following formula, but without subtractions to avoid
197        // underflow panics:
198        //      len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1
199        assert!(
200            data.len() + cstride.value() + rstride.value()
201                >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1,
202            "Matrix view: input data buffer too small."
203        );
204
205        assert!(
206            {
207                let nrows = nrows.value();
208                let ncols = ncols.value();
209                let rstride = rstride.value();
210                let cstride = cstride.value();
211
212                nrows * ncols <= 1
213                    || match (rstride, cstride) {
214                        (0, 0) => false,      // otherwise: matrix[(0, 0)] == index[(nrows - 1, ncols - 1)],
215                        (0, _) => nrows <= 1, // otherwise: matrix[(0, 0)] == index[(nrows - 1, 0)],
216                        (_, 0) => ncols <= 1, // otherwise: matrix[(0, 0)] == index[(0, ncols - 1)],
217                        (_, _) => {
218                            // otherwise: matrix[(0, numer)] == index[(denom, 0)]
219                            let ratio = Ratio::new(rstride, cstride);
220                            nrows <= *ratio.denom() || ncols <= *ratio.numer()
221                        }
222                    }
223            },
224            "Matrix view: dimensions and strides result in aliased indices."
225        );
226
227        unsafe {
228            Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride)
229        }
230    }
231}
232
233impl<'a, T: Scalar, R: Dim, C: Dim> MatrixViewMut<'a, T, R, C> {
234    /// Creates, without bound-checking, a mutable matrix view from an array and with dimensions specified by generic types instances.
235    ///
236    /// # Safety
237    /// This method is unsafe because the input data array is not checked to contain enough elements.
238    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`.
239    #[inline]
240    pub unsafe fn from_slice_generic_unchecked(
241        data: &'a mut [T],
242        start: usize,
243        nrows: R,
244        ncols: C,
245    ) -> Self {
246        unsafe {
247            Self::from_slice_with_strides_generic_unchecked(
248                data, start, nrows, ncols, Const::<1>, nrows,
249            )
250        }
251    }
252
253    /// Creates a mutable matrix view from an array and with dimensions and strides specified by generic types instances.
254    ///
255    /// Panics if the input data array dose not contain enough elements.
256    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dyn()`.
257    #[inline]
258    pub fn from_slice_generic(data: &'a mut [T], nrows: R, ncols: C) -> Self {
259        Self::from_slice_with_strides_generic(data, nrows, ncols, Const::<1>, nrows)
260    }
261}
262
263macro_rules! impl_constructors_mut(
264    ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr_2021),*; $($args: ident),*) => {
265        impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixViewMut<'a, T, $($Dims),*> {
266            /// Creates a new mutable matrix view from the given data array.
267            ///
268            /// Panics if `data` does not contain enough elements.
269            #[inline]
270            pub fn from_slice(data: &'a mut [T], $($args: usize),*) -> Self {
271                Self::from_slice_generic(data, $($gargs),*)
272            }
273
274            /// Creates, without bound checking, a new mutable matrix view from the given data array.
275            ///
276            /// # Safety
277            ///
278            /// `data[start..start+(R * C)]` must be within bounds.
279            #[inline]
280            pub unsafe fn from_slice_unchecked(data: &'a mut [T], start: usize, $($args: usize),*) -> Self { unsafe {
281                Self::from_slice_generic_unchecked(data, start, $($gargs),*)
282            }}
283        }
284
285        impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixViewMut<'a, T, $($Dims,)* Dyn, Dyn> {
286            /// Creates a new mutable matrix view with the specified strides from the given data array.
287            ///
288            /// Panics if `data` does not contain enough elements.
289            #[inline]
290            pub fn from_slice_with_strides_mut(data: &'a mut [T], $($args: usize,)* rstride: usize, cstride: usize) -> Self {
291                Self::from_slice_with_strides_generic(
292                    data, $($gargs,)* Dyn(rstride), Dyn(cstride))
293            }
294
295            /// Creates, without bound checking, a new mutable matrix view with the specified strides from the given data array.
296            /// # Safety
297            /// `data[start..start+rstride * cstride]` must be within bounds.
298            #[inline]
299            pub unsafe fn from_slice_with_strides_unchecked(data: &'a mut [T], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self { unsafe {
300                Self::from_slice_with_strides_generic_unchecked(
301                    data, start, $($gargs,)* Dyn(rstride), Dyn(cstride))
302            }}
303        }
304    }
305);
306
307// TODO: this is not very pretty. We could find a better call syntax.
308impl_constructors_mut!(R, C;                         // Arguments for Matrix<T, ..., S>
309=> R: DimName, => C: DimName; // Type parameters for impl<T, ..., S>
310R::name(), C::name();         // Arguments for `_generic` constructors.
311); // Arguments for non-generic constructors.
312
313impl_constructors_mut!(R, Dyn;
314                       => R: DimName;
315                       R::name(), Dyn(ncols);
316                       ncols);
317
318impl_constructors_mut!(Dyn, C;
319                       => C: DimName;
320                       Dyn(nrows), C::name();
321                       nrows);
322
323impl_constructors_mut!(Dyn, Dyn;
324                       ;
325                       Dyn(nrows), Dyn(ncols);
326                       nrows, ncols);