nalgebra/base/construction_slice.rs
1use crate::base::dimension::{Const, Dim, DimName, Dynamic};
2use crate::base::matrix_slice::{SliceStorage, SliceStorageMut};
3use crate::base::{MatrixSlice, MatrixSliceMutMN, Scalar};
4
5use num_rational::Ratio;
6
7/// # Creating matrix slices from `&[T]`
8impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
9 MatrixSlice<'a, T, R, C, RStride, CStride>
10{
11 /// Creates, without bound-checking, a matrix slice 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 `Dynamic::new()`.
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 = SliceStorage::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 slice 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 `Dynamic::new()`.
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 slice: input data buffer to 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> MatrixSlice<'a, T, R, C> {
61 /// Creates, without bound-checking, a matrix slice 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 `Dynamic::new()`.
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 slice 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 `Dynamic::new()`.
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),*> MatrixSlice<'a, T, $($Dims),*> {
91 /// Creates a new matrix slice 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 slice from the given data array.
100 #[inline]
101 pub unsafe fn from_slice_unchecked(data: &'a [T], start: usize, $($args: usize),*) -> Self {
102 Self::from_slice_generic_unchecked(data, start, $($gargs),*)
103 }
104 }
105
106 impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixSlice<'a, T, $($Dims,)* Dynamic, Dynamic> {
107 /// Creates a new matrix slice with the specified strides from the given data array.
108 ///
109 /// Panics if `data` does not contain enough elements.
110 #[inline]
111 pub fn from_slice_with_strides(data: &'a [T], $($args: usize,)* rstride: usize, cstride: usize) -> Self {
112 Self::from_slice_with_strides_generic(data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
113 }
114
115 /// Creates, without bound checking, a new matrix slice with the specified strides from the given data array.
116 #[inline]
117 pub unsafe fn from_slice_with_strides_unchecked(data: &'a [T], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self {
118 Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
119 }
120 }
121 }
122);
123
124// TODO: this is not very pretty. We could find a better call syntax.
125impl_constructors!(R, C; // Arguments for Matrix<T, ..., S>
126=> R: DimName, => C: DimName; // Type parameters for impl<T, ..., S>
127R::name(), C::name(); // Arguments for `_generic` constructors.
128); // Arguments for non-generic constructors.
129
130impl_constructors!(R, Dynamic;
131 => R: DimName;
132 R::name(), Dynamic::new(ncols);
133 ncols);
134
135impl_constructors!(Dynamic, C;
136 => C: DimName;
137 Dynamic::new(nrows), C::name();
138 nrows);
139
140impl_constructors!(Dynamic, Dynamic;
141 ;
142 Dynamic::new(nrows), Dynamic::new(ncols);
143 nrows, ncols);
144
145/// # Creating mutable matrix slices from `&mut [T]`
146impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
147 MatrixSliceMutMN<'a, T, R, C, RStride, CStride>
148{
149 /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
150 ///
151 /// # Safety
152 /// This method is unsafe because the input data array is not checked to contain enough elements.
153 /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
154 #[inline]
155 pub unsafe fn from_slice_with_strides_generic_unchecked(
156 data: &'a mut [T],
157 start: usize,
158 nrows: R,
159 ncols: C,
160 rstride: RStride,
161 cstride: CStride,
162 ) -> Self {
163 let data = SliceStorageMut::from_raw_parts(
164 data.as_mut_ptr().add(start),
165 (nrows, ncols),
166 (rstride, cstride),
167 );
168 Self::from_data(data)
169 }
170
171 /// Creates a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
172 ///
173 /// Panics if the input data array dose not contain enough elements.
174 /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
175 #[inline]
176 pub fn from_slice_with_strides_generic(
177 data: &'a mut [T],
178 nrows: R,
179 ncols: C,
180 rstride: RStride,
181 cstride: CStride,
182 ) -> Self {
183 // NOTE: The assertion implements the following formula, but without subtractions to avoid
184 // underflow panics:
185 // len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1
186 assert!(
187 data.len() + cstride.value() + rstride.value()
188 >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1,
189 "Matrix slice: input data buffer to small."
190 );
191
192 assert!(
193 {
194 let nrows = nrows.value();
195 let ncols = ncols.value();
196 let rstride = rstride.value();
197 let cstride = cstride.value();
198
199 nrows * ncols <= 1
200 || match (rstride, cstride) {
201 (0, 0) => false, // otherwise: matrix[(0, 0)] == index[(nrows - 1, ncols - 1)],
202 (0, _) => nrows <= 1, // otherwise: matrix[(0, 0)] == index[(nrows - 1, 0)],
203 (_, 0) => ncols <= 1, // otherwise: matrix[(0, 0)] == index[(0, ncols - 1)],
204 (_, _) => {
205 // otherwise: matrix[(0, numer)] == index[(denom, 0)]
206 let ratio = Ratio::new(rstride, cstride);
207 nrows <= *ratio.denom() || ncols <= *ratio.numer()
208 }
209 }
210 },
211 "Matrix slice: dimensions and strides result in aliased indices."
212 );
213
214 unsafe {
215 Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride)
216 }
217 }
218}
219
220impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> {
221 /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances.
222 ///
223 /// # Safety
224 /// This method is unsafe because the input data array is not checked to contain enough elements.
225 /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
226 #[inline]
227 pub unsafe fn from_slice_generic_unchecked(
228 data: &'a mut [T],
229 start: usize,
230 nrows: R,
231 ncols: C,
232 ) -> Self {
233 Self::from_slice_with_strides_generic_unchecked(
234 data, start, nrows, ncols, Const::<1>, nrows,
235 )
236 }
237
238 /// Creates a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
239 ///
240 /// Panics if the input data array dose not contain enough elements.
241 /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
242 #[inline]
243 pub fn from_slice_generic(data: &'a mut [T], nrows: R, ncols: C) -> Self {
244 Self::from_slice_with_strides_generic(data, nrows, ncols, Const::<1>, nrows)
245 }
246}
247
248macro_rules! impl_constructors_mut(
249 ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
250 impl<'a, T: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, T, $($Dims),*> {
251 /// Creates a new mutable matrix slice from the given data array.
252 ///
253 /// Panics if `data` does not contain enough elements.
254 #[inline]
255 pub fn from_slice(data: &'a mut [T], $($args: usize),*) -> Self {
256 Self::from_slice_generic(data, $($gargs),*)
257 }
258
259 /// Creates, without bound checking, a new mutable matrix slice from the given data array.
260 #[inline]
261 pub unsafe fn from_slice_unchecked(data: &'a mut [T], start: usize, $($args: usize),*) -> Self {
262 Self::from_slice_generic_unchecked(data, start, $($gargs),*)
263 }
264 }
265
266 impl<'a, T: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMutMN<'a, T, $($Dims,)* Dynamic, Dynamic> {
267 /// Creates a new mutable matrix slice with the specified strides from the given data array.
268 ///
269 /// Panics if `data` does not contain enough elements.
270 #[inline]
271 pub fn from_slice_with_strides_mut(data: &'a mut [T], $($args: usize,)* rstride: usize, cstride: usize) -> Self {
272 Self::from_slice_with_strides_generic(
273 data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
274 }
275
276 /// Creates, without bound checking, a new mutable matrix slice with the specified strides from the given data array.
277 #[inline]
278 pub unsafe fn from_slice_with_strides_unchecked(data: &'a mut [T], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self {
279 Self::from_slice_with_strides_generic_unchecked(
280 data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
281 }
282 }
283 }
284);
285
286// TODO: this is not very pretty. We could find a better call syntax.
287impl_constructors_mut!(R, C; // Arguments for Matrix<T, ..., S>
288=> R: DimName, => C: DimName; // Type parameters for impl<T, ..., S>
289R::name(), C::name(); // Arguments for `_generic` constructors.
290); // Arguments for non-generic constructors.
291
292impl_constructors_mut!(R, Dynamic;
293 => R: DimName;
294 R::name(), Dynamic::new(ncols);
295 ncols);
296
297impl_constructors_mut!(Dynamic, C;
298 => C: DimName;
299 Dynamic::new(nrows), C::name();
300 nrows);
301
302impl_constructors_mut!(Dynamic, Dynamic;
303 ;
304 Dynamic::new(nrows), Dynamic::new(ncols);
305 nrows, ncols);