diff --git a/src/base/allocator.rs b/src/base/allocator.rs index 29286420..ccbcca37 100644 --- a/src/base/allocator.rs +++ b/src/base/allocator.rs @@ -41,6 +41,13 @@ pub trait Allocator: Any + Sized { ncols: C, iter: I, ) -> Self::Buffer; + + /// Allocates a buffer initialized with the content of the given row-major order iterator. + fn allocate_from_row_iterator>( + nrows: R, + ncols: C, + iter: I, + ) -> Self::Buffer; } /// A matrix reallocator. Changes the size of the memory buffer that initially contains (`RFrom` × diff --git a/src/base/construction.rs b/src/base/construction.rs index fe4e4b08..009d8c76 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -86,6 +86,17 @@ where Self::from_data(DefaultAllocator::allocate_from_iterator(nrows, ncols, iter)) } + /// Creates a matrix with all its elements filled by an row-major order iterator. + #[inline] + pub fn from_row_iterator_generic(nrows: R, ncols: C, iter: I) -> Self + where + I: IntoIterator, + { + Self::from_data(DefaultAllocator::allocate_from_row_iterator( + nrows, ncols, iter, + )) + } + /// Creates a matrix with its elements filled with the components provided by a slice in /// row-major order. /// @@ -479,6 +490,36 @@ macro_rules! impl_constructors( Self::from_iterator_generic($($gargs, )* iter) } + /// Creates a matrix or vector with all its elements filled by a row-major iterator. + /// + /// The output matrix is filled row-by-row. + /// + /// ## Example + /// ``` + /// # use nalgebra::{Matrix2x3, Vector3, DVector, DMatrix}; + /// # use std::iter; + /// + /// let v = Vector3::from_row_iterator((0..3).into_iter()); + /// // The additional argument represents the vector dimension. + /// let dv = DVector::from_row_iterator(3, (0..3).into_iter()); + /// let m = Matrix2x3::from_row_iterator((0..6).into_iter()); + /// // The two additional arguments represent the matrix dimensions. + /// let dm = DMatrix::from_row_iterator(2, 3, (0..6).into_iter()); + /// + /// // For Vectors from_row_iterator is identical to from_iterator + /// assert!(v.x == 0 && v.y == 1 && v.z == 2); + /// assert!(dv[0] == 0 && dv[1] == 1 && dv[2] == 2); + /// assert!(m.m11 == 0 && m.m12 == 1 && m.m13 == 2 && + /// m.m21 == 3 && m.m22 == 4 && m.m23 == 5); + /// assert!(dm[(0, 0)] == 0 && dm[(0, 1)] == 1 && dm[(0, 2)] == 2 && + /// dm[(1, 0)] == 3 && dm[(1, 1)] == 4 && dm[(1, 2)] == 5); + /// ``` + #[inline] + pub fn from_row_iterator($($args: usize,)* iter: I) -> Self + where I: IntoIterator { + Self::from_row_iterator_generic($($gargs, )* iter) + } + /// Creates a matrix or vector filled with the results of a function applied to each of its /// component coordinates. /// diff --git a/src/base/default_allocator.rs b/src/base/default_allocator.rs index 09197bbd..e055604c 100644 --- a/src/base/default_allocator.rs +++ b/src/base/default_allocator.rs @@ -80,6 +80,40 @@ impl Allocator, Const> // yielded enough elements to initialize our matrix. unsafe { , Const>>::assume_init(res) } } + + #[inline] + fn allocate_from_row_iterator>( + nrows: Const, + ncols: Const, + iter: I, + ) -> Self::Buffer { + #[cfg(feature = "no_unsound_assume_init")] + let mut res: Self::Buffer = unimplemented!(); + #[cfg(not(feature = "no_unsound_assume_init"))] + let mut res = unsafe { Self::allocate_uninitialized(nrows, ncols).assume_init() }; + let mut count = 0; + let res_ptr = res.as_mut_slice(); + + for (i, e) in iter + .into_iter() + .take(ncols.value() * nrows.value()) + .enumerate() + { + unsafe { + *res_ptr + .get_unchecked_mut((i % ncols.value()) * nrows.value() + i / ncols.value()) = e; + } + // res_ptr[(i % ncols.value()) * nrows.value() + i / ncols.value()] = e; + count += 1; + } + + assert!( + count == nrows.value() * ncols.value(), + "Matrix init. from row iterator: iterator not long enough." + ); + + res + } } // Dynamic - Static @@ -128,6 +162,32 @@ impl Allocator for DefaultAllocator { VecStorage::new(nrows, ncols, res) } + + #[inline] + fn allocate_from_row_iterator>( + nrows: Dynamic, + ncols: C, + iter: I, + ) -> Self::Buffer { + let it = iter.into_iter().take(nrows.value() * ncols.value()); + let mut res: Vec = Vec::with_capacity(nrows.value() * ncols.value()); + let res_ptr = res.as_mut_ptr(); + let mut count = 0; + + unsafe { + for (i, e) in it.enumerate() { + *res_ptr.add((i % ncols.value()) * nrows.value() + i / ncols.value()) = e; + count += 1; + } + res.set_len(nrows.value() * ncols.value()); + } + assert!( + count == nrows.value() * ncols.value(), + "Matrix init. from row iterator: iterator not long enough." + ); + + VecStorage::new(nrows, ncols, res) + } } // Static - Dynamic @@ -176,6 +236,32 @@ impl Allocator for DefaultAllocator { VecStorage::new(nrows, ncols, res) } + + #[inline] + fn allocate_from_row_iterator>( + nrows: R, + ncols: Dynamic, + iter: I, + ) -> Self::Buffer { + let it = iter.into_iter().take(nrows.value() * ncols.value()); + let mut res: Vec = Vec::with_capacity(nrows.value() * ncols.value()); + let res_ptr = res.as_mut_ptr(); + let mut count = 0; + + unsafe { + for (i, e) in it.enumerate() { + *res_ptr.add((i % ncols.value()) * nrows.value() + i / ncols.value()) = e; + count += 1; + } + res.set_len(nrows.value() * ncols.value()); + } + assert!( + count == nrows.value() * ncols.value(), + "Matrix init. from row iterator: iterator not long enough." + ); + + VecStorage::new(nrows, ncols, res) + } } /*