//! 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::ops::Mul; use std::ptr; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::Vec; use generic_array::ArrayLength; use typenum::Prod; use base::allocator::{Allocator, Reallocator}; #[cfg(any(feature = "alloc", feature = "std"))] use base::dimension::Dynamic; use base::dimension::{Dim, DimName}; use base::array_storage::ArrayStorage; #[cfg(any(feature = "std", feature = "alloc"))] use base::matrix_vec::MatrixVec; use base::storage::{Storage, StorageMut}; use base::Scalar; /* * * Allocator. * */ /// An allocator based on `GenericArray` and `MatrixVec` for statically-sized and dynamically-sized /// matrices respectively. pub struct DefaultAllocator; // Static - Static impl Allocator for DefaultAllocator where N: Scalar, R: DimName, C: DimName, R::Value: Mul, Prod: ArrayLength, { type Buffer = ArrayStorage; #[inline] unsafe fn allocate_uninitialized(_: R, _: C) -> Self::Buffer { mem::uninitialized() } #[inline] fn allocate_from_iterator>( nrows: R, ncols: C, iter: I, ) -> Self::Buffer { let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols) }; let mut count = 0; for (res, e) in res.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 = MatrixVec; #[inline] unsafe fn allocate_uninitialized(nrows: Dynamic, ncols: C) -> Self::Buffer { let mut res = Vec::new(); let length = nrows.value() * ncols.value(); res.reserve_exact(length); res.set_len(length); MatrixVec::new(nrows, ncols, res) } #[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."); MatrixVec::new(nrows, ncols, res) } } // Static - Dynamic #[cfg(any(feature = "std", feature = "alloc"))] impl Allocator for DefaultAllocator { type Buffer = MatrixVec; #[inline] unsafe fn allocate_uninitialized(nrows: R, ncols: Dynamic) -> Self::Buffer { let mut res = Vec::new(); let length = nrows.value() * ncols.value(); res.reserve_exact(length); res.set_len(length); MatrixVec::new(nrows, ncols, res) } #[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."); MatrixVec::new(nrows, ncols, res) } } /* * * Reallocator. * */ // Anything -> Static × Static impl Reallocator for DefaultAllocator where RFrom: Dim, CFrom: Dim, RTo: DimName, CTo: DimName, Self: Allocator, RTo::Value: Mul, Prod: ArrayLength, { #[inline] unsafe fn reallocate_copy( rto: RTo, cto: CTo, buf: >::Buffer, ) -> ArrayStorage { let mut res = >::allocate_uninitialized(rto, cto); 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 for DefaultAllocator where RFrom: DimName, CFrom: DimName, CTo: Dim, RFrom::Value: Mul, Prod: ArrayLength, { #[inline] unsafe fn reallocate_copy( rto: Dynamic, cto: CTo, buf: ArrayStorage, ) -> MatrixVec { let mut res = >::allocate_uninitialized(rto, cto); 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 for DefaultAllocator where RFrom: DimName, CFrom: DimName, RTo: DimName, RFrom::Value: Mul, Prod: ArrayLength, { #[inline] unsafe fn reallocate_copy( rto: RTo, cto: Dynamic, buf: ArrayStorage, ) -> MatrixVec { let mut res = >::allocate_uninitialized(rto, cto); 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: MatrixVec, ) -> MatrixVec { let new_buf = buf.resize(rto.value() * cto.value()); MatrixVec::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: MatrixVec, ) -> MatrixVec { let new_buf = buf.resize(rto.value() * cto.value()); MatrixVec::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: MatrixVec, ) -> MatrixVec { let new_buf = buf.resize(rto.value() * cto.value()); MatrixVec::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: MatrixVec, ) -> MatrixVec { let new_buf = buf.resize(rto.value() * cto.value()); MatrixVec::new(rto, cto, new_buf) } }