Always check iterator size when allocating

This commit is contained in:
Thomas den Hollander 2024-05-15 10:05:26 +02:00
parent afc03cc403
commit 3e07ad1b52
4 changed files with 176 additions and 22 deletions

View File

@ -36,12 +36,27 @@ pub trait Allocator<T, R: Dim, C: Dim = U1>: Any + Sized {
unsafe fn assume_init(uninit: Self::BufferUninit) -> Self::Buffer;
/// Allocates a buffer initialized with the content of the given iterator.
///
/// # Panics
///
/// This function will panic if the iterator yields too few or too many
/// elements.
fn allocate_from_iterator<I: IntoIterator<Item = T>>(
nrows: R,
ncols: C,
iter: I,
) -> Self::Buffer;
/// Allocates a buffer from a `Vec<T>`.
///
/// # Panics
///
/// This function will panic if the `Vec` contains too few or too many
/// elements.
fn allocate_from_vec(nrows: R, ncols: C, vec: Vec<T>) -> Self::Buffer {
Self::allocate_from_iterator(nrows, ncols, vec)
}
#[inline]
/// Allocates a buffer initialized with the content of the given row-major order iterator.
fn allocate_from_row_iterator<I: IntoIterator<Item = T>>(

View File

@ -331,7 +331,7 @@ where
#[inline]
#[cfg(any(feature = "std", feature = "alloc"))]
pub fn from_vec_generic(nrows: R, ncols: C, data: Vec<T>) -> Self {
Self::from_iterator_generic(nrows, ncols, data)
Self::from_data(DefaultAllocator::allocate_from_vec(nrows, ncols, data))
}
}

View File

@ -68,14 +68,16 @@ impl<T: Scalar, const R: usize, const C: usize> Allocator<T, Const<R>, Const<C>>
// Safety: conversion to a slice 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()) {
let mut it = iter.into_iter();
for (res, e) in res_slice.iter_mut().zip(&mut it) {
*res = MaybeUninit::new(e);
count += 1;
}
assert!(
it.next().is_none() &&
count == nrows.value() * ncols.value(),
"Matrix init. from iterator: iterator not long enough."
"Matrix init. from iterator: the iterator did not yield the correct number of elements."
);
// Safety: the assertion above made sure that the iterator
@ -121,13 +123,23 @@ impl<T: Scalar, C: Dim> Allocator<T, Dyn, C> for DefaultAllocator {
ncols: C,
iter: I,
) -> Self::Buffer {
let it = iter.into_iter();
let res: Vec<T> = it.collect();
assert!(res.len() == nrows.value() * ncols.value(),
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
let size = nrows.value() * ncols.value();
let mut it = iter.into_iter();
let res: Vec<T> = (&mut it).take(size).collect();
assert!(it.next().is_none() && res.len() == size,
"Matrix init. from iterator: the iterator did not yield the correct number of elements.");
VecStorage::new(nrows, ncols, res)
}
#[inline]
fn allocate_from_vec(nrows: Dyn, ncols: C, vec: Vec<T>) -> Self::Buffer {
assert!(
vec.len() == nrows.value() * ncols.value(),
"Matrix init. from vec: the vec does not have the right size."
);
VecStorage::new(nrows, ncols, vec)
}
}
// Static - Dyn
@ -167,13 +179,24 @@ impl<T: Scalar, R: DimName> Allocator<T, R, Dyn> for DefaultAllocator {
ncols: Dyn,
iter: I,
) -> Self::Buffer {
let it = iter.into_iter();
let res: Vec<T> = it.collect();
assert!(res.len() == nrows.value() * ncols.value(),
"Allocation from iterator error: the iterator did not yield the correct number of elements.");
let size = nrows.value() * ncols.value();
let mut it = iter.into_iter();
let res: Vec<T> = (&mut it).take(size).collect();
assert!(it.next().is_none() && res.len() == size,
"Matrix init. from iterator: the iterator did not yield the correct number of elements.");
VecStorage::new(nrows, ncols, res)
}
#[inline]
fn allocate_from_vec(nrows: R, ncols: Dyn, vec: Vec<T>) -> Self::Buffer {
assert_eq!(
vec.len(),
nrows.value() * ncols.value(),
"Matrix init. from vec: the vec does not have the right size."
);
VecStorage::new(nrows, ncols, vec)
}
}
/*
@ -333,3 +356,119 @@ impl<T: Scalar, RFrom: DimName, RTo: DimName> Reallocator<T, RFrom, Dyn, RTo, Dy
VecStorage::new(rto, cto, new_buf)
}
}
#[cfg(test)]
mod tests {
/// Tests for `DefaultAllocator` with constant dimensions.
mod static_static {
use crate::{allocator::Allocator, Const, DefaultAllocator};
#[test]
#[should_panic(
expected = "Matrix init. from iterator: the iterator did not yield the correct number of elements."
)]
fn allocate_from_iter_too_small() {
let iter = &[1i32];
let _ = DefaultAllocator::allocate_from_iterator(Const::<10>, Const::<5>, iter);
}
#[test]
#[should_panic(
expected = "Matrix init. from iterator: the iterator did not yield the correct number of elements."
)]
fn allocate_iter_too_big() {
let iter = &[1u32, 2, 3, 4, 5, 6, 7];
let _ = DefaultAllocator::allocate_from_iterator(Const::<2>, Const::<3>, iter);
}
#[test]
#[should_panic(
expected = "Matrix init. from iterator: the iterator did not yield the correct number of elements."
)]
fn allocate_from_vec_too_small() {
let vec = vec![1u8];
let _ = DefaultAllocator::allocate_from_vec(Const::<4>, Const::<2>, vec);
}
#[test]
#[should_panic(
expected = "Matrix init. from iterator: the iterator did not yield the correct number of elements."
)]
fn allocate_from_vec_too_big() {
let vec = vec![1usize, 2, 3, 4, 5, 6];
let _ = DefaultAllocator::allocate_from_vec(Const::<5>, Const::<1>, vec);
}
}
mod dyn_static {
use crate::{allocator::Allocator, Const, DefaultAllocator, Dyn};
#[test]
#[should_panic(
expected = "Matrix init. from iterator: the iterator did not yield the correct number of elements."
)]
fn allocate_from_iter_too_small() {
let iter = &[1i32];
let _ = DefaultAllocator::allocate_from_iterator(Dyn(4), Const::<5>, iter);
}
#[test]
#[should_panic(
expected = "Matrix init. from iterator: the iterator did not yield the correct number of elements."
)]
fn allocate_iter_too_big() {
let iter = &[1u32, 2, 3, 4];
let _ = DefaultAllocator::allocate_from_iterator(Dyn(1), Const::<3>, iter);
}
#[test]
#[should_panic(expected = "Matrix init. from vec: the vec does not have the right size.")]
fn allocate_from_vec_too_small() {
let vec = vec![1u8];
let _ = DefaultAllocator::allocate_from_vec(Dyn(4), Const::<2>, vec);
}
#[test]
#[should_panic(expected = "Matrix init. from vec: the vec does not have the right size.")]
fn allocate_from_vec_too_big() {
let vec = vec![1usize, 2, 3, 4, 5, 6];
let _ = DefaultAllocator::allocate_from_vec(Dyn(5), Const::<1>, vec);
}
}
mod static_dyn {
use crate::{allocator::Allocator, Const, DefaultAllocator, Dyn};
#[test]
#[should_panic(
expected = "Matrix init. from iterator: the iterator did not yield the correct number of elements."
)]
fn allocate_from_iter_too_small() {
let iter = &[1i32];
let _ = DefaultAllocator::allocate_from_iterator(Const::<5>, Dyn(4), iter);
}
#[test]
#[should_panic(
expected = "Matrix init. from iterator: the iterator did not yield the correct number of elements."
)]
fn allocate_iter_too_big() {
let iter = &[1u32, 2, 3, 4];
let _ = DefaultAllocator::allocate_from_iterator(Const::<3>, Dyn(1), iter);
}
#[test]
#[should_panic(expected = "Matrix init. from vec: the vec does not have the right size.")]
fn allocate_from_vec_too_small() {
let vec = vec![1u8];
let _ = DefaultAllocator::allocate_from_vec(Const::<2>, Dyn(4), vec);
}
#[test]
#[should_panic(expected = "Matrix init. from vec: the vec does not have the right size.")]
fn allocate_from_vec_too_big() {
let vec = vec![1usize, 2, 3, 4, 5, 6];
let _ = DefaultAllocator::allocate_from_vec(Const::<1>, Dyn(5), vec);
}
}
}

View File

@ -208,19 +208,19 @@ fn new_from_slice() {
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0 ];
let expected2 = Matrix2::from_column_slice(&data);
let expected3 = Matrix3::from_column_slice(&data);
let expected2x3 = Matrix2x3::from_column_slice(&data);
let expected3x2 = Matrix3x2::from_column_slice(&data);
let expected2 = Matrix2::from_column_slice(&data[0..4]);
let expected3 = Matrix3::from_column_slice(&data[0..9]);
let expected2x3 = Matrix2x3::from_column_slice(&data[0..6]);
let expected3x2 = Matrix3x2::from_column_slice(&data[0..6]);
{
let m2 = MatrixView2::from_slice(&data);
let m3 = MatrixView3::from_slice(&data);
let m2x3 = MatrixView2x3::from_slice(&data);
let m3x2 = MatrixView3x2::from_slice(&data);
let m2xX = MatrixView2xX::from_slice(&data, 3);
let mXx3 = MatrixViewXx3::from_slice(&data, 2);
let mXxX = DMatrixView::from_slice(&data, 2, 3);
let m2 = MatrixView2::from_slice(&data[0..4]);
let m3 = MatrixView3::from_slice(&data[0..9]);
let m2x3 = MatrixView2x3::from_slice(&data[0..6]);
let m3x2 = MatrixView3x2::from_slice(&data[0..6]);
let m2xX = MatrixView2xX::from_slice(&data[0..6], 3);
let mXx3 = MatrixViewXx3::from_slice(&data[0..6], 2);
let mXxX = DMatrixView::from_slice(&data[0..6], 2, 3);
assert!(m2.eq(&expected2));
assert!(m3.eq(&expected3));