nalgebra/base/
default_allocator.rs

1//! The default matrix data storage allocator.
2//!
3//! This will use stack-allocated buffers for matrices with dimensions known at compile-time, and
4//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.
5
6use std::cmp;
7use std::ptr;
8
9#[cfg(all(feature = "alloc", not(feature = "std")))]
10use alloc::vec::Vec;
11
12use super::Const;
13use crate::base::allocator::{Allocator, Reallocator};
14use crate::base::array_storage::ArrayStorage;
15use crate::base::dimension::Dim;
16#[cfg(any(feature = "alloc", feature = "std"))]
17use crate::base::dimension::{DimName, Dyn};
18use crate::base::storage::{RawStorage, RawStorageMut, Storage};
19#[cfg(any(feature = "std", feature = "alloc"))]
20use crate::base::vec_storage::VecStorage;
21use crate::base::Scalar;
22#[cfg(any(feature = "std", feature = "alloc"))]
23use std::mem::ManuallyDrop;
24use std::mem::MaybeUninit;
25
26/*
27 *
28 * Allocator.
29 *
30 */
31/// An allocator based on [`ArrayStorage`] and [`VecStorage`] for statically-sized and dynamically-sized
32/// matrices respectively.
33#[derive(Copy, Clone, Debug)]
34pub struct DefaultAllocator;
35
36// Static - Static
37impl<const R: usize, const C: usize> Allocator<Const<R>, Const<C>> for DefaultAllocator {
38    type Buffer<T: Scalar> = ArrayStorage<T, R, C>;
39    type BufferUninit<T: Scalar> = ArrayStorage<MaybeUninit<T>, R, C>;
40
41    #[inline(always)]
42    fn allocate_uninit<T: Scalar>(_: Const<R>, _: Const<C>) -> ArrayStorage<MaybeUninit<T>, R, C> {
43        // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid.
44        let array: [[MaybeUninit<T>; R]; C] = unsafe { MaybeUninit::uninit().assume_init() };
45        ArrayStorage(array)
46    }
47
48    #[inline(always)]
49    unsafe fn assume_init<T: Scalar>(
50        uninit: ArrayStorage<MaybeUninit<T>, R, C>,
51    ) -> ArrayStorage<T, R, C> {
52        // Safety:
53        // * The caller guarantees that all elements of the array are initialized
54        // * `MaybeUninit<T>` and T are guaranteed to have the same layout
55        // * `MaybeUninit` does not drop, so there are no double-frees
56        // And thus the conversion is safe
57        ArrayStorage((&uninit as *const _ as *const [_; C]).read())
58    }
59
60    #[inline]
61    fn allocate_from_iterator<T: Scalar, I: IntoIterator<Item = T>>(
62        nrows: Const<R>,
63        ncols: Const<C>,
64        iter: I,
65    ) -> Self::Buffer<T> {
66        let mut res = Self::allocate_uninit(nrows, ncols);
67        let mut count = 0;
68
69        // Safety: conversion to a slice is OK because the Buffer is known to be contiguous.
70        let res_slice = unsafe { res.as_mut_slice_unchecked() };
71        for (res, e) in res_slice.iter_mut().zip(iter.into_iter()) {
72            *res = MaybeUninit::new(e);
73            count += 1;
74        }
75
76        assert!(
77            count == nrows.value() * ncols.value(),
78            "Matrix init. from iterator: iterator not long enough."
79        );
80
81        // Safety: the assertion above made sure that the iterator
82        //         yielded enough elements to initialize our matrix.
83        unsafe { <Self as Allocator<Const<R>, Const<C>>>::assume_init(res) }
84    }
85}
86
87// Dyn - Static
88// Dyn - Dyn
89#[cfg(any(feature = "std", feature = "alloc"))]
90impl<C: Dim> Allocator<Dyn, C> for DefaultAllocator {
91    type Buffer<T: Scalar> = VecStorage<T, Dyn, C>;
92    type BufferUninit<T: Scalar> = VecStorage<MaybeUninit<T>, Dyn, C>;
93
94    #[inline]
95    fn allocate_uninit<T: Scalar>(nrows: Dyn, ncols: C) -> VecStorage<MaybeUninit<T>, Dyn, C> {
96        let mut data = Vec::new();
97        let length = nrows.value() * ncols.value();
98        data.reserve_exact(length);
99        data.resize_with(length, MaybeUninit::uninit);
100        VecStorage::new(nrows, ncols, data)
101    }
102
103    #[inline]
104    unsafe fn assume_init<T: Scalar>(
105        uninit: VecStorage<MaybeUninit<T>, Dyn, C>,
106    ) -> VecStorage<T, Dyn, C> {
107        // Avoids a double-drop.
108        let (nrows, ncols) = uninit.shape();
109        let vec: Vec<_> = uninit.into();
110        let mut md = ManuallyDrop::new(vec);
111
112        // Safety:
113        // - MaybeUninit<T> has the same alignment and layout as T.
114        // - The length and capacity come from a valid vector.
115        let new_data = Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity());
116
117        VecStorage::new(nrows, ncols, new_data)
118    }
119
120    #[inline]
121    fn allocate_from_iterator<T: Scalar, I: IntoIterator<Item = T>>(
122        nrows: Dyn,
123        ncols: C,
124        iter: I,
125    ) -> Self::Buffer<T> {
126        let it = iter.into_iter();
127        let res: Vec<T> = it.collect();
128        assert!(res.len() == nrows.value() * ncols.value(),
129                "Allocation from iterator error: the iterator did not yield the correct number of elements.");
130
131        VecStorage::new(nrows, ncols, res)
132    }
133}
134
135// Static - Dyn
136#[cfg(any(feature = "std", feature = "alloc"))]
137impl<R: DimName> Allocator<R, Dyn> for DefaultAllocator {
138    type Buffer<T: Scalar> = VecStorage<T, R, Dyn>;
139    type BufferUninit<T: Scalar> = VecStorage<MaybeUninit<T>, R, Dyn>;
140
141    #[inline]
142    fn allocate_uninit<T: Scalar>(nrows: R, ncols: Dyn) -> VecStorage<MaybeUninit<T>, R, Dyn> {
143        let mut data = Vec::new();
144        let length = nrows.value() * ncols.value();
145        data.reserve_exact(length);
146        data.resize_with(length, MaybeUninit::uninit);
147
148        VecStorage::new(nrows, ncols, data)
149    }
150
151    #[inline]
152    unsafe fn assume_init<T: Scalar>(
153        uninit: VecStorage<MaybeUninit<T>, R, Dyn>,
154    ) -> VecStorage<T, R, Dyn> {
155        // Avoids a double-drop.
156        let (nrows, ncols) = uninit.shape();
157        let vec: Vec<_> = uninit.into();
158        let mut md = ManuallyDrop::new(vec);
159
160        // Safety:
161        // - MaybeUninit<T> has the same alignment and layout as T.
162        // - The length and capacity come from a valid vector.
163        let new_data = Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity());
164
165        VecStorage::new(nrows, ncols, new_data)
166    }
167
168    #[inline]
169    fn allocate_from_iterator<T: Scalar, I: IntoIterator<Item = T>>(
170        nrows: R,
171        ncols: Dyn,
172        iter: I,
173    ) -> Self::Buffer<T> {
174        let it = iter.into_iter();
175        let res: Vec<T> = it.collect();
176        assert!(res.len() == nrows.value() * ncols.value(),
177                "Allocation from iterator error: the iterator did not yield the correct number of elements.");
178
179        VecStorage::new(nrows, ncols, res)
180    }
181}
182
183/*
184 *
185 * Reallocator.
186 *
187 */
188// Anything -> Static × Static
189impl<T: Scalar, RFrom, CFrom, const RTO: usize, const CTO: usize>
190    Reallocator<T, RFrom, CFrom, Const<RTO>, Const<CTO>> for DefaultAllocator
191where
192    RFrom: Dim,
193    CFrom: Dim,
194    Self: Allocator<RFrom, CFrom>,
195{
196    #[inline]
197    unsafe fn reallocate_copy(
198        rto: Const<RTO>,
199        cto: Const<CTO>,
200        buf: <Self as Allocator<RFrom, CFrom>>::Buffer<T>,
201    ) -> ArrayStorage<MaybeUninit<T>, RTO, CTO> {
202        let mut res = <Self as Allocator<Const<RTO>, Const<CTO>>>::allocate_uninit(rto, cto);
203
204        let (rfrom, cfrom) = buf.shape();
205
206        let len_from = rfrom.value() * cfrom.value();
207        let len_to = rto.value() * cto.value();
208        let len_copied = cmp::min(len_from, len_to);
209        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied);
210
211        // Safety:
212        // - We don’t care about dropping elements because the caller is responsible for dropping things.
213        // - We forget `buf` so that we don’t drop the other elements, but ensure the buffer itself is cleaned up.
214        buf.forget_elements();
215
216        res
217    }
218}
219
220// Static × Static -> Dyn × Any
221#[cfg(any(feature = "std", feature = "alloc"))]
222impl<T: Scalar, CTo, const RFROM: usize, const CFROM: usize>
223    Reallocator<T, Const<RFROM>, Const<CFROM>, Dyn, CTo> for DefaultAllocator
224where
225    CTo: Dim,
226{
227    #[inline]
228    unsafe fn reallocate_copy(
229        rto: Dyn,
230        cto: CTo,
231        buf: ArrayStorage<T, RFROM, CFROM>,
232    ) -> VecStorage<MaybeUninit<T>, Dyn, CTo> {
233        let mut res = <Self as Allocator<Dyn, CTo>>::allocate_uninit(rto, cto);
234
235        let (rfrom, cfrom) = buf.shape();
236
237        let len_from = rfrom.value() * cfrom.value();
238        let len_to = rto.value() * cto.value();
239        let len_copied = cmp::min(len_from, len_to);
240        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied);
241
242        // Safety:
243        // - We don’t care about dropping elements because the caller is responsible for dropping things.
244        // - We forget `buf` so that we don’t drop the other elements, but ensure the buffer itself is cleaned up.
245        buf.forget_elements();
246
247        res
248    }
249}
250
251// Static × Static -> Static × Dyn
252#[cfg(any(feature = "std", feature = "alloc"))]
253impl<T: Scalar, RTo, const RFROM: usize, const CFROM: usize>
254    Reallocator<T, Const<RFROM>, Const<CFROM>, RTo, Dyn> for DefaultAllocator
255where
256    RTo: DimName,
257{
258    #[inline]
259    unsafe fn reallocate_copy(
260        rto: RTo,
261        cto: Dyn,
262        buf: ArrayStorage<T, RFROM, CFROM>,
263    ) -> VecStorage<MaybeUninit<T>, RTo, Dyn> {
264        let mut res = <Self as Allocator<RTo, Dyn>>::allocate_uninit(rto, cto);
265
266        let (rfrom, cfrom) = buf.shape();
267
268        let len_from = rfrom.value() * cfrom.value();
269        let len_to = rto.value() * cto.value();
270        let len_copied = cmp::min(len_from, len_to);
271        ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut() as *mut T, len_copied);
272
273        // Safety:
274        // - We don’t care about dropping elements because the caller is responsible for dropping things.
275        // - We forget `buf` so that we don’t drop the other elements, but ensure the buffer itself is cleaned up.
276        buf.forget_elements();
277
278        res
279    }
280}
281
282// All conversion from a dynamic buffer to a dynamic buffer.
283#[cfg(any(feature = "std", feature = "alloc"))]
284impl<T: Scalar, CFrom: Dim, CTo: Dim> Reallocator<T, Dyn, CFrom, Dyn, CTo> for DefaultAllocator {
285    #[inline]
286    unsafe fn reallocate_copy(
287        rto: Dyn,
288        cto: CTo,
289        buf: VecStorage<T, Dyn, CFrom>,
290    ) -> VecStorage<MaybeUninit<T>, Dyn, CTo> {
291        let new_buf = buf.resize(rto.value() * cto.value());
292        VecStorage::new(rto, cto, new_buf)
293    }
294}
295
296#[cfg(any(feature = "std", feature = "alloc"))]
297impl<T: Scalar, CFrom: Dim, RTo: DimName> Reallocator<T, Dyn, CFrom, RTo, Dyn>
298    for DefaultAllocator
299{
300    #[inline]
301    unsafe fn reallocate_copy(
302        rto: RTo,
303        cto: Dyn,
304        buf: VecStorage<T, Dyn, CFrom>,
305    ) -> VecStorage<MaybeUninit<T>, RTo, Dyn> {
306        let new_buf = buf.resize(rto.value() * cto.value());
307        VecStorage::new(rto, cto, new_buf)
308    }
309}
310
311#[cfg(any(feature = "std", feature = "alloc"))]
312impl<T: Scalar, RFrom: DimName, CTo: Dim> Reallocator<T, RFrom, Dyn, Dyn, CTo>
313    for DefaultAllocator
314{
315    #[inline]
316    unsafe fn reallocate_copy(
317        rto: Dyn,
318        cto: CTo,
319        buf: VecStorage<T, RFrom, Dyn>,
320    ) -> VecStorage<MaybeUninit<T>, Dyn, CTo> {
321        let new_buf = buf.resize(rto.value() * cto.value());
322        VecStorage::new(rto, cto, new_buf)
323    }
324}
325
326#[cfg(any(feature = "std", feature = "alloc"))]
327impl<T: Scalar, RFrom: DimName, RTo: DimName> Reallocator<T, RFrom, Dyn, RTo, Dyn>
328    for DefaultAllocator
329{
330    #[inline]
331    unsafe fn reallocate_copy(
332        rto: RTo,
333        cto: Dyn,
334        buf: VecStorage<T, RFrom, Dyn>,
335    ) -> VecStorage<MaybeUninit<T>, RTo, Dyn> {
336        let new_buf = buf.resize(rto.value() * cto.value());
337        VecStorage::new(rto, cto, new_buf)
338    }
339}