//! The default matrix data storage allocator. //! //! This will use stack-allocated buffers for matrices with dimensions known at compile-time, and //! heap-allocated buffers for matrices with at least one dimension unknown at compile-time. use std::cmp; use std::mem; use std::ptr; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::Vec; use super::Const; use crate::base::allocator::{Allocator, Reallocator}; use crate::base::array_storage::ArrayStorage; #[cfg(any(feature = "alloc", feature = "std"))] use crate::base::dimension::Dynamic; use crate::base::dimension::{Dim, DimName}; use crate::base::storage::{RawStorage, RawStorageMut}; #[cfg(any(feature = "std", feature = "alloc"))] use crate::base::vec_storage::VecStorage; use crate::base::Scalar; use std::mem::{ManuallyDrop, MaybeUninit}; /* * * Allocator. * */ /// An allocator based on `GenericArray` and `VecStorage` for statically-sized and dynamically-sized /// matrices respectively. #[derive(Copy, Clone, Debug)] pub struct DefaultAllocator; // Static - Static impl Allocator, Const> for DefaultAllocator { type Buffer = ArrayStorage; type BufferUninit = ArrayStorage, R, C>; #[inline] unsafe fn allocate_uninitialized(_: Const, _: Const) -> MaybeUninit { mem::MaybeUninit::::uninit() } #[inline] fn allocate_uninit(_: Const, _: Const) -> ArrayStorage, R, C> { // SAFETY: An uninitialized `[MaybeUninit<_>; _]` is valid. let array: [[MaybeUninit; R]; C] = unsafe { MaybeUninit::uninit().assume_init() }; ArrayStorage(array) } #[inline] unsafe fn assume_init(uninit: ArrayStorage, R, C>) -> ArrayStorage { // Safety: // * The caller guarantees that all elements of the array are initialized // * `MaybeUninit` and T are guaranteed to have the same layout // * `MaybeUnint` does not drop, so there are no double-frees // And thus the conversion is safe ArrayStorage((&uninit as *const _ as *const [_; C]).read()) } #[inline] fn allocate_from_iterator>( nrows: Const, ncols: Const, iter: I, ) -> Self::Buffer { #[cfg(feature = "no_unsound_assume_init")] let mut res: Self::Buffer = unimplemented!(); #[cfg(not(feature = "no_unsound_assume_init"))] let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols).assume_init() }; let mut count = 0; // Safety: this is OK because the Buffer is known to be contiguous. let res_slice = unsafe { res.as_mut_slice_unchecked() }; for (res, e) in res_slice.iter_mut().zip(iter.into_iter()) { *res = e; count += 1; } assert!( count == nrows.value() * ncols.value(), "Matrix init. from iterator: iterator not long enough." ); res } } // Dynamic - Static // Dynamic - Dynamic #[cfg(any(feature = "std", feature = "alloc"))] impl Allocator for DefaultAllocator { type Buffer = VecStorage; type BufferUninit = VecStorage, Dynamic, C>; #[inline] unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> MaybeUninit { let mut res = Vec::new(); let length = nrows.value() * ncols.value(); res.reserve_exact(length); res.set_len(length); mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res)) } #[inline] fn allocate_uninit(nrows: Dynamic, ncols: C) -> VecStorage, Dynamic, C> { let mut data = Vec::new(); let length = nrows.value() * ncols.value(); data.reserve_exact(length); data.resize_with(length, MaybeUninit::uninit); VecStorage::new(nrows, ncols, data) } #[inline] unsafe fn assume_init( uninit: VecStorage, Dynamic, C>, ) -> VecStorage { // Avoids a double-drop. let (nrows, ncols) = uninit.shape(); let vec: Vec<_> = uninit.into(); let mut md = ManuallyDrop::new(vec); // Safety: // - MaybeUninit has the same alignment and layout as T. // - The length and capacity come from a valid vector. let new_data = Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity()); VecStorage::new(nrows, ncols, new_data) } #[inline] fn allocate_from_iterator>( nrows: Dynamic, ncols: C, iter: I, ) -> Self::Buffer { let it = iter.into_iter(); let res: Vec = it.collect(); assert!(res.len() == nrows.value() * ncols.value(), "Allocation from iterator error: the iterator did not yield the correct number of elements."); VecStorage::new(nrows, ncols, res) } } // Static - Dynamic #[cfg(any(feature = "std", feature = "alloc"))] impl Allocator for DefaultAllocator { type Buffer = VecStorage; type BufferUninit = VecStorage, R, Dynamic>; #[inline] unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> MaybeUninit { let mut res = Vec::new(); let length = nrows.value() * ncols.value(); res.reserve_exact(length); res.set_len(length); mem::MaybeUninit::new(VecStorage::new(nrows, ncols, res)) } #[inline] fn allocate_uninit(nrows: R, ncols: Dynamic) -> VecStorage, R, Dynamic> { let mut data = Vec::new(); let length = nrows.value() * ncols.value(); data.reserve_exact(length); data.resize_with(length, MaybeUninit::uninit); VecStorage::new(nrows, ncols, data) } #[inline] unsafe fn assume_init( uninit: VecStorage, R, Dynamic>, ) -> VecStorage { // Avoids a double-drop. let (nrows, ncols) = uninit.shape(); let vec: Vec<_> = uninit.into(); let mut md = ManuallyDrop::new(vec); // Safety: // - MaybeUninit has the same alignment and layout as T. // - The length and capacity come from a valid vector. let new_data = Vec::from_raw_parts(md.as_mut_ptr() as *mut _, md.len(), md.capacity()); VecStorage::new(nrows, ncols, new_data) } #[inline] fn allocate_from_iterator>( nrows: R, ncols: Dynamic, iter: I, ) -> Self::Buffer { let it = iter.into_iter(); let res: Vec = it.collect(); assert!(res.len() == nrows.value() * ncols.value(), "Allocation from iterator error: the iterator did not yield the correct number of elements."); VecStorage::new(nrows, ncols, res) } } /* * * Reallocator. * */ // Anything -> Static × Static impl Reallocator, Const> for DefaultAllocator where RFrom: Dim, CFrom: Dim, Self: Allocator, { #[inline] unsafe fn reallocate_copy( rto: Const, cto: Const, buf: >::Buffer, ) -> ArrayStorage { #[cfg(feature = "no_unsound_assume_init")] let mut res: ArrayStorage = unimplemented!(); #[cfg(not(feature = "no_unsound_assume_init"))] let mut res = , Const>>::allocate_uninitialized(rto, cto) .assume_init(); let (rfrom, cfrom) = buf.shape(); let len_from = rfrom.value() * cfrom.value(); let len_to = rto.value() * cto.value(); ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to)); res } } // Static × Static -> Dynamic × Any #[cfg(any(feature = "std", feature = "alloc"))] impl Reallocator, Const, Dynamic, CTo> for DefaultAllocator where CTo: Dim, { #[inline] unsafe fn reallocate_copy( rto: Dynamic, cto: CTo, buf: ArrayStorage, ) -> VecStorage { #[cfg(feature = "no_unsound_assume_init")] let mut res: VecStorage = unimplemented!(); #[cfg(not(feature = "no_unsound_assume_init"))] let mut res = >::allocate_uninitialized(rto, cto).assume_init(); let (rfrom, cfrom) = buf.shape(); let len_from = rfrom.value() * cfrom.value(); let len_to = rto.value() * cto.value(); ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to)); res } } // Static × Static -> Static × Dynamic #[cfg(any(feature = "std", feature = "alloc"))] impl Reallocator, Const, RTo, Dynamic> for DefaultAllocator where RTo: DimName, { #[inline] unsafe fn reallocate_copy( rto: RTo, cto: Dynamic, buf: ArrayStorage, ) -> VecStorage { #[cfg(feature = "no_unsound_assume_init")] let mut res: VecStorage = unimplemented!(); #[cfg(not(feature = "no_unsound_assume_init"))] let mut res = >::allocate_uninitialized(rto, cto).assume_init(); let (rfrom, cfrom) = buf.shape(); let len_from = rfrom.value() * cfrom.value(); let len_to = rto.value() * cto.value(); ptr::copy_nonoverlapping(buf.ptr(), res.ptr_mut(), cmp::min(len_from, len_to)); res } } // All conversion from a dynamic buffer to a dynamic buffer. #[cfg(any(feature = "std", feature = "alloc"))] impl Reallocator for DefaultAllocator { #[inline] unsafe fn reallocate_copy( rto: Dynamic, cto: CTo, buf: VecStorage, ) -> VecStorage { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } } #[cfg(any(feature = "std", feature = "alloc"))] impl Reallocator for DefaultAllocator { #[inline] unsafe fn reallocate_copy( rto: RTo, cto: Dynamic, buf: VecStorage, ) -> VecStorage { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } } #[cfg(any(feature = "std", feature = "alloc"))] impl Reallocator for DefaultAllocator { #[inline] unsafe fn reallocate_copy( rto: Dynamic, cto: CTo, buf: VecStorage, ) -> VecStorage { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } } #[cfg(any(feature = "std", feature = "alloc"))] impl Reallocator for DefaultAllocator { #[inline] unsafe fn reallocate_copy( rto: RTo, cto: Dynamic, buf: VecStorage, ) -> VecStorage { let new_buf = buf.resize(rto.value() * cto.value()); VecStorage::new(rto, cto, new_buf) } }