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);