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