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