Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always check iterator size when allocating #1394

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading