//! Abstract definition of a matrix data storage allocator. use std::any::Any; use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; use crate::base::dimension::{Dim, U1}; use crate::base::{DefaultAllocator, Scalar}; use crate::storage::{IsContiguous, RawStorageMut}; use crate::StorageMut; use std::fmt::Debug; use std::mem::MaybeUninit; /// A matrix allocator of a memory buffer that may contain `R::to_usize() * C::to_usize()` /// elements of type `T`. /// /// An allocator is said to be: /// − static: if `R` and `C` both implement `DimName`. /// − dynamic: if either one (or both) of `R` or `C` is equal to `Dyn`. /// /// Every allocator must be both static and dynamic. Though not all implementations may share the /// same `Buffer` type. pub trait Allocator: Any + Sized { /// The type of buffer this allocator can instantiate. type Buffer: StorageMut + IsContiguous + Clone + Debug; /// The type of buffer with uninitialized components this allocator can instantiate. type BufferUninit: RawStorageMut, R, C> + IsContiguous; /// Allocates a buffer with the given number of rows and columns without initializing its content. fn allocate_uninit(nrows: R, ncols: C) -> Self::BufferUninit; /// Assumes a data buffer to be initialized. /// /// # Safety /// The user must make sure that every single entry of the buffer has been initialized, /// or Undefined Behavior will immediately occur. unsafe fn assume_init(uninit: Self::BufferUninit) -> Self::Buffer; /// Allocates a buffer initialized with the content of the given iterator. fn allocate_from_iterator>( nrows: R, ncols: C, iter: I, ) -> Self::Buffer; #[inline] /// Allocates a buffer initialized with the content of the given row-major order iterator. fn allocate_from_row_iterator>( nrows: R, ncols: C, iter: I, ) -> Self::Buffer { let mut res = Self::allocate_uninit(nrows, ncols); let mut count = 0; unsafe { // OK because the allocated buffer is guaranteed to be contiguous. let res_ptr = res.as_mut_slice_unchecked(); for (k, e) in iter .into_iter() .take(ncols.value() * nrows.value()) .enumerate() { let i = k / ncols.value(); let j = k % ncols.value(); // result[(i, j)] = e; *res_ptr.get_unchecked_mut(i + j * nrows.value()) = MaybeUninit::new(e); count += 1; } assert!( count == nrows.value() * ncols.value(), "Matrix init. from row iterator: iterator not long enough." ); >::assume_init(res) } } } /// A matrix reallocator. Changes the size of the memory buffer that initially contains (`RFrom` × /// `CFrom`) elements to a smaller or larger size (`RTo`, `CTo`). pub trait Reallocator: Allocator + Allocator { /// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer /// `buf`. Data stored by `buf` are linearly copied to the output: /// /// # Safety /// The following invariants must be respected by the implementors of this method: /// * The copy is performed as if both were just arrays (without taking into account the matrix structure). /// * If the underlying buffer is being shrunk, the removed elements must **not** be dropped /// by this method. Dropping them is the responsibility of the caller. unsafe fn reallocate_copy( nrows: RTo, ncols: CTo, buf: >::Buffer, ) -> >::BufferUninit; } /// The number of rows of the result of a componentwise operation on two matrices. pub type SameShapeR = >::Representative; /// The number of columns of the result of a componentwise operation on two matrices. pub type SameShapeC = >::Representative; // TODO: Bad name. /// Restricts the given number of rows and columns to be respectively the same. pub trait SameShapeAllocator: Allocator + Allocator, SameShapeC> where R1: Dim, R2: Dim, C1: Dim, C2: Dim, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, { } impl SameShapeAllocator for DefaultAllocator where R1: Dim, R2: Dim, C1: Dim, C2: Dim, DefaultAllocator: Allocator + Allocator, SameShapeC>, ShapeConstraint: SameNumberOfRows + SameNumberOfColumns, { } // XXX: Bad name. /// Restricts the given number of rows to be equal. pub trait SameShapeVectorAllocator: Allocator + Allocator> + SameShapeAllocator where R1: Dim, R2: Dim, ShapeConstraint: SameNumberOfRows, { } impl SameShapeVectorAllocator for DefaultAllocator where R1: Dim, R2: Dim, DefaultAllocator: Allocator + Allocator>, ShapeConstraint: SameNumberOfRows, { }