nalgebra/base/
storage.rs

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