nalgebra/base/storage.rs
1//! Abstract definition of a matrix data storage.
2
3use std::ptr;
4
5use crate::base::Scalar;
6use crate::base::allocator::{Allocator, SameShapeC, SameShapeR};
7use crate::base::default_allocator::DefaultAllocator;
8use crate::base::dimension::{Dim, U1};
9
10/*
11 * Aliases for allocation results.
12 */
13/// The data storage for the sum of two matrices with dimensions `(R1, C1)` and `(R2, C2)`.
14pub type SameShapeStorage<T, R1, C1, R2, C2> =
15 <DefaultAllocator as Allocator<SameShapeR<R1, R2>, SameShapeC<C1, C2>>>::Buffer<T>;
16
17// TODO: better name than Owned ?
18/// The owned data storage that can be allocated from `S`.
19pub type Owned<T, R, C = U1> = <DefaultAllocator as Allocator<R, C>>::Buffer<T>;
20
21/// The owned data storage that can be allocated from `S`.
22pub type OwnedUninit<T, R, C = U1> = <DefaultAllocator as Allocator<R, C>>::BufferUninit<T>;
23
24/// The row-stride of the owned data storage for a buffer of dimension `(R, C)`.
25pub type RStride<T, R, C = U1> =
26 <<DefaultAllocator as Allocator<R, C>>::Buffer<T> as RawStorage<T, R, C>>::RStride;
27
28/// The column-stride of the owned data storage for a buffer of dimension `(R, C)`.
29pub type CStride<T, R, C = U1> =
30 <<DefaultAllocator as Allocator<R, C>>::Buffer<T> as RawStorage<T, R, C>>::CStride;
31
32/// The trait shared by all matrix data storage.
33///
34/// TODO: doc
35/// # Safety
36///
37/// In generic code, it is recommended use the `Storage` trait bound instead. The `RawStorage`
38/// trait bound is generally used by code that needs to work with storages that contains
39/// `MaybeUninit<T>` elements.
40///
41/// Note that `Self` must always have a number of elements compatible with the matrix length (given
42/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait
43/// should **not** allow the user to modify the size of the underlying buffer with safe methods
44/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the
45/// vector's size so that it no longer contains enough elements: this will lead to UB.
46pub unsafe trait RawStorage<T, R: Dim, C: Dim = U1>: Sized {
47 /// The static stride of this storage's rows.
48 type RStride: Dim;
49
50 /// The static stride of this storage's columns.
51 type CStride: Dim;
52
53 /// The matrix data pointer.
54 fn ptr(&self) -> *const T;
55
56 /// The dimension of the matrix at run-time. Arr length of zero indicates the additive identity
57 /// element of any dimension. Must be equal to `Self::dimension()` if it is not `None`.
58 fn shape(&self) -> (R, C);
59
60 /// The relative offset in the underlying storage corresponding to a change in position by one row or column respectively.
61 ///
62 /// For example this returns `(1, 5)` for a column-major matrix with 5 columns.
63 fn strides(&self) -> (Self::RStride, Self::CStride);
64
65 /// Compute the index corresponding to the irow-th row and icol-th column of this matrix. The
66 /// index must be such that the following holds:
67 ///
68 /// ```ignore
69 /// let lindex = self.linear_index(irow, icol);
70 /// assert!(*self.get_unchecked(irow, icol) == *self.get_unchecked_linear(lindex))
71 /// ```
72 #[inline]
73 fn linear_index(&self, irow: usize, icol: usize) -> usize {
74 let (rstride, cstride) = self.strides();
75
76 irow * rstride.value() + icol * cstride.value()
77 }
78
79 /// Gets the address of the i-th matrix component without performing bound-checking.
80 ///
81 /// # Safety
82 /// If the index is out of bounds, dereferencing the result will cause undefined behavior.
83 #[inline]
84 fn get_address_unchecked_linear(&self, i: usize) -> *const T {
85 self.ptr().wrapping_add(i)
86 }
87
88 /// Gets the address of the i-th matrix component without performing bound-checking.
89 ///
90 /// # Safety
91 /// If the index is out of bounds, dereferencing the result will cause undefined behavior.
92 #[inline]
93 fn get_address_unchecked(&self, irow: usize, icol: usize) -> *const T {
94 self.get_address_unchecked_linear(self.linear_index(irow, icol))
95 }
96
97 /// Retrieves a reference to the i-th element without bound-checking.
98 ///
99 /// # Safety
100 /// If the index is out of bounds, the method will cause undefined behavior.
101 #[inline]
102 unsafe fn get_unchecked_linear(&self, i: usize) -> &T {
103 unsafe { &*self.get_address_unchecked_linear(i) }
104 }
105
106 /// Retrieves a reference to the i-th element without bound-checking.
107 ///
108 /// # Safety
109 /// If the index is out of bounds, the method will cause undefined behavior.
110 #[inline]
111 unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &T {
112 unsafe { self.get_unchecked_linear(self.linear_index(irow, icol)) }
113 }
114
115 /// Indicates whether this data buffer stores its elements contiguously.
116 ///
117 /// # Safety
118 /// This function must not return `true` if the underlying storage is not contiguous,
119 /// or undefined behaviour will occur.
120 fn is_contiguous(&self) -> bool;
121
122 /// Retrieves the data buffer as a contiguous slice.
123 ///
124 /// # Safety
125 /// The matrix components may not be stored in a contiguous way, depending on the strides.
126 /// This method is unsafe because this can yield to invalid aliasing when called on some pairs
127 /// of matrix views originating from the same matrix with strides.
128 ///
129 /// Call the safe alternative `matrix.as_slice()` instead.
130 unsafe fn as_slice_unchecked(&self) -> &[T];
131}
132
133/// Trait shared by all matrix data storage that don’t contain any uninitialized elements.
134///
135/// # Safety
136///
137/// Note that `Self` must always have a number of elements compatible with the matrix length (given
138/// by `R` and `C` if they are known at compile-time). For example, implementors of this trait
139/// should **not** allow the user to modify the size of the underlying buffer with safe methods
140/// (for example the `VecStorage::data_mut` method is unsafe because the user could change the
141/// vector's size so that it no longer contains enough elements: this will lead to UB.
142pub unsafe trait Storage<T: Scalar, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
143 /// Builds a matrix data storage that does not contain any reference.
144 fn into_owned(self) -> Owned<T, R, C>
145 where
146 DefaultAllocator: Allocator<R, C>;
147
148 /// Clones this data storage to one that does not contain any reference.
149 fn clone_owned(&self) -> Owned<T, R, C>
150 where
151 DefaultAllocator: Allocator<R, C>;
152
153 /// Drops the storage without calling the destructors on the contained elements.
154 fn forget_elements(self);
155}
156
157/// Trait implemented by matrix data storage that can provide a mutable access to its elements.
158///
159/// # Safety
160///
161/// In generic code, it is recommended use the `StorageMut` trait bound instead. The
162/// `RawStorageMut` trait bound is generally used by code that needs to work with storages that
163/// contains `MaybeUninit<T>` elements.
164///
165/// Note that a mutable access does not mean that the matrix owns its data. For example, a mutable
166/// matrix view can provide mutable access to its elements even if it does not own its data (it
167/// contains only an internal reference to them).
168pub unsafe trait RawStorageMut<T, R: Dim, C: Dim = U1>: RawStorage<T, R, C> {
169 /// The matrix mutable data pointer.
170 fn ptr_mut(&mut self) -> *mut T;
171
172 /// Gets the mutable address of the i-th matrix component without performing bound-checking.
173 ///
174 /// # Safety
175 /// If the index is out of bounds, dereferencing the result will cause undefined behavior.
176 #[inline]
177 fn get_address_unchecked_linear_mut(&mut self, i: usize) -> *mut T {
178 self.ptr_mut().wrapping_add(i)
179 }
180
181 /// Gets the mutable address of the i-th matrix component without performing bound-checking.
182 ///
183 /// # Safety
184 /// If the index is out of bounds, dereferencing the result will cause undefined behavior.
185 #[inline]
186 fn get_address_unchecked_mut(&mut self, irow: usize, icol: usize) -> *mut T {
187 let lid = self.linear_index(irow, icol);
188 self.get_address_unchecked_linear_mut(lid)
189 }
190
191 /// Retrieves a mutable reference to the i-th element without bound-checking.
192 ///
193 /// # Safety
194 /// If the index is out of bounds, the method will cause undefined behavior.
195 unsafe fn get_unchecked_linear_mut(&mut self, i: usize) -> &mut T {
196 unsafe { &mut *self.get_address_unchecked_linear_mut(i) }
197 }
198
199 /// Retrieves a mutable reference to the element at `(irow, icol)` without bound-checking.
200 ///
201 /// # Safety
202 /// If the index is out of bounds, the method will cause undefined behavior.
203 #[inline]
204 unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut T {
205 unsafe { &mut *self.get_address_unchecked_mut(irow, icol) }
206 }
207
208 /// Swaps two elements using their linear index without bound-checking.
209 ///
210 /// # Safety
211 /// If the indices are out of bounds, the method will cause undefined behavior.
212 ///
213 /// # Validity
214 /// The default implementation of this trait function is only guaranteed to be
215 /// sound if invocations of `self.ptr_mut()` and `self.get_address_unchecked_linear_mut()`
216 /// result in stable references. If any of the data pointed to by these trait methods
217 /// moves as a consequence of invoking either of these methods then this default
218 /// trait implementation may be invalid or unsound and should be overridden.
219 #[inline]
220 unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) {
221 unsafe {
222 // we can't just use the pointers returned from `get_address_unchecked_linear_mut` because calling a
223 // method taking self mutably invalidates any existing (mutable) pointers. since `get_address_unchecked_linear_mut` can
224 // also be overridden by a custom implementation, we can't just use `wrapping_add` assuming that's what the method does.
225 // instead, we use `offset_from` to compute the re-calculate the pointers from the base pointer.
226 // this is sound as long as this trait matches the Validity preconditions
227 // (and it's the caller's responsibility to ensure the indices are in-bounds).
228 let base = self.ptr_mut();
229 let offset1 = self.get_address_unchecked_linear_mut(i1).offset_from(base);
230 let offset2 = self.get_address_unchecked_linear_mut(i2).offset_from(base);
231
232 let base = self.ptr_mut();
233 let a = base.offset(offset1);
234 let b = base.offset(offset2);
235
236 ptr::swap(a, b);
237 }
238 }
239
240 /// Swaps two elements without bound-checking.
241 ///
242 /// # Safety
243 /// If the indices are out of bounds, the method will cause undefined behavior.
244 #[inline]
245 unsafe fn swap_unchecked(&mut self, row_col1: (usize, usize), row_col2: (usize, usize)) {
246 unsafe {
247 let lid1 = self.linear_index(row_col1.0, row_col1.1);
248 let lid2 = self.linear_index(row_col2.0, row_col2.1);
249
250 self.swap_unchecked_linear(lid1, lid2)
251 }
252 }
253
254 /// Retrieves the mutable data buffer as a contiguous slice.
255 ///
256 /// Matrix components may not be contiguous, depending on its strides.
257 ///
258 /// # Safety
259 /// The matrix components may not be stored in a contiguous way, depending on the strides.
260 /// This method is unsafe because this can yield to invalid aliasing when called on some pairs
261 /// of matrix slices originating from the same matrix with strides.
262 unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T];
263}
264
265/// Trait shared by all mutable matrix data storage that don’t contain any uninitialized elements.
266///
267/// # Safety
268///
269/// See safety note for `Storage`, `RawStorageMut`.
270pub unsafe trait StorageMut<T: Scalar, R: Dim, C: Dim = U1>:
271 Storage<T, R, C> + RawStorageMut<T, R, C>
272{
273}
274
275unsafe impl<S, T: Scalar, R, C> StorageMut<T, R, C> for S
276where
277 R: Dim,
278 C: Dim,
279 S: Storage<T, R, C> + RawStorageMut<T, R, C>,
280{
281}
282
283/// Marker trait indicating that a storage is stored contiguously in memory.
284///
285/// # Safety
286///
287/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value
288/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
289/// failing to comply to this may cause Undefined Behaviors.
290pub unsafe trait IsContiguous {}
291
292/// A matrix storage that can be reshaped in-place.
293pub trait ReshapableStorage<T, R1, C1, R2, C2>: RawStorage<T, R1, C1>
294where
295 T: Scalar,
296 R1: Dim,
297 C1: Dim,
298 R2: Dim,
299 C2: Dim,
300{
301 /// The reshaped storage type.
302 type Output: RawStorage<T, R2, C2>;
303
304 /// Reshapes the storage into the output storage type.
305 fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output;
306}