Skip to content

Commit

Permalink
Always check iterator size when allocating
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasdenH committed May 15, 2024
1 parent afc03cc commit 3e07ad1
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 22 deletions.
15 changes: 15 additions & 0 deletions src/base/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>(
Expand Down
2 changes: 1 addition & 1 deletion src/base/construction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}

Expand Down
159 changes: 149 additions & 10 deletions src/base/default_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
}

/*
Expand Down Expand Up @@ -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);
}
}
}
22 changes: 11 additions & 11 deletions tests/core/matrix_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit 3e07ad1

Please sign in to comment.