From 3e07ad1b52d69716d0cc7b846f4c0588722a5fb4 Mon Sep 17 00:00:00 2001 From: Thomas den Hollander Date: Wed, 15 May 2024 10:05:26 +0200 Subject: [PATCH] Always check iterator size when allocating --- src/base/allocator.rs | 15 ++++ src/base/construction.rs | 2 +- src/base/default_allocator.rs | 159 +++++++++++++++++++++++++++++++--- tests/core/matrix_view.rs | 22 ++--- 4 files changed, 176 insertions(+), 22 deletions(-) diff --git a/src/base/allocator.rs b/src/base/allocator.rs index 10c4bd31..a600e780 100644 --- a/src/base/allocator.rs +++ b/src/base/allocator.rs @@ -36,12 +36,27 @@ pub trait Allocator: 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>( nrows: R, ncols: C, iter: I, ) -> Self::Buffer; + /// Allocates a buffer from a `Vec`. + /// + /// # 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) -> 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>( diff --git a/src/base/construction.rs b/src/base/construction.rs index 43475179..493b8b15 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -331,7 +331,7 @@ where #[inline] #[cfg(any(feature = "std", feature = "alloc"))] pub fn from_vec_generic(nrows: R, ncols: C, data: Vec) -> Self { - Self::from_iterator_generic(nrows, ncols, data) + Self::from_data(DefaultAllocator::allocate_from_vec(nrows, ncols, data)) } } diff --git a/src/base/default_allocator.rs b/src/base/default_allocator.rs index 3c132413..793efe86 100644 --- a/src/base/default_allocator.rs +++ b/src/base/default_allocator.rs @@ -68,14 +68,16 @@ impl Allocator, Const> // 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 Allocator for DefaultAllocator { ncols: C, iter: I, ) -> Self::Buffer { - let it = iter.into_iter(); - let res: Vec = 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 = (&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) -> 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 Allocator for DefaultAllocator { ncols: Dyn, iter: I, ) -> Self::Buffer { - let it = iter.into_iter(); - let res: Vec = 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 = (&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) -> 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 Reallocator, 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); + } + } +} diff --git a/tests/core/matrix_view.rs b/tests/core/matrix_view.rs index 4ce49d02..c848384e 100644 --- a/tests/core/matrix_view.rs +++ b/tests/core/matrix_view.rs @@ -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));