1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
//! 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<R: Dim, C: Dim = U1>: Any + Sized {
/// The type of buffer this allocator can instantiate.
type Buffer<T: Scalar>: StorageMut<T, R, C> + IsContiguous + Clone + Debug;
/// The type of buffer with uninitialized components this allocator can instantiate.
type BufferUninit<T: Scalar>: RawStorageMut<MaybeUninit<T>, R, C> + IsContiguous;
/// Allocates a buffer with the given number of rows and columns without initializing its content.
fn allocate_uninit<T: Scalar>(nrows: R, ncols: C) -> Self::BufferUninit<T>;
/// 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<T: Scalar>(uninit: Self::BufferUninit<T>) -> Self::Buffer<T>;
/// Allocates a buffer initialized with the content of the given iterator.
fn allocate_from_iterator<T: Scalar, I: IntoIterator<Item = T>>(
nrows: R,
ncols: C,
iter: I,
) -> Self::Buffer<T>;
#[inline]
/// Allocates a buffer initialized with the content of the given row-major order iterator.
fn allocate_from_row_iterator<T: Scalar, I: IntoIterator<Item = T>>(
nrows: R,
ncols: C,
iter: I,
) -> Self::Buffer<T> {
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."
);
<Self as Allocator<R, C>>::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<T: Scalar, RFrom: Dim, CFrom: Dim, RTo: Dim, CTo: Dim>:
Allocator<RFrom, CFrom> + Allocator<RTo, CTo>
{
/// 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: <Self as Allocator<RFrom, CFrom>>::Buffer<T>,
) -> <Self as Allocator<RTo, CTo>>::BufferUninit<T>;
}
/// The number of rows of the result of a componentwise operation on two matrices.
pub type SameShapeR<R1, R2> = <ShapeConstraint as SameNumberOfRows<R1, R2>>::Representative;
/// The number of columns of the result of a componentwise operation on two matrices.
pub type SameShapeC<C1, C2> = <ShapeConstraint as SameNumberOfColumns<C1, C2>>::Representative;
// TODO: Bad name.
/// Restricts the given number of rows and columns to be respectively the same.
pub trait SameShapeAllocator<R1, C1, R2, C2>:
Allocator<R1, C1> + Allocator<SameShapeR<R1, R2>, SameShapeC<C1, C2>>
where
R1: Dim,
R2: Dim,
C1: Dim,
C2: Dim,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{
}
impl<R1, R2, C1, C2> SameShapeAllocator<R1, C1, R2, C2> for DefaultAllocator
where
R1: Dim,
R2: Dim,
C1: Dim,
C2: Dim,
DefaultAllocator: Allocator<R1, C1> + Allocator<SameShapeR<R1, R2>, SameShapeC<C1, C2>>,
ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2>,
{
}
// XXX: Bad name.
/// Restricts the given number of rows to be equal.
pub trait SameShapeVectorAllocator<R1, R2>:
Allocator<R1> + Allocator<SameShapeR<R1, R2>> + SameShapeAllocator<R1, U1, R2, U1>
where
R1: Dim,
R2: Dim,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{
}
impl<R1, R2> SameShapeVectorAllocator<R1, R2> for DefaultAllocator
where
R1: Dim,
R2: Dim,
DefaultAllocator: Allocator<R1, U1> + Allocator<SameShapeR<R1, R2>>,
ShapeConstraint: SameNumberOfRows<R1, R2>,
{
}