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