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