diff --git a/benches/core/matrix.rs b/benches/core/matrix.rs index 7b4f85bd..7f4432e3 100644 --- a/benches/core/matrix.rs +++ b/benches/core/matrix.rs @@ -136,6 +136,30 @@ fn mat500_mul_mat500(bench: &mut criterion::Criterion) { bench.bench_function("mat500_mul_mat500", move |bh| bh.iter(|| &a * &b)); } +fn iter(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(1000, 1000); + + bench.bench_function("iter", move |bh| { + bh.iter(|| { + for value in a.iter() { + criterion::black_box(value); + } + }) + }); +} + +fn iter_rev(bench: &mut criterion::Criterion) { + let a = DMatrix::::new_random(1000, 1000); + + bench.bench_function("iter_rev", move |bh| { + bh.iter(|| { + for value in a.iter().rev() { + criterion::black_box(value); + } + }) + }); +} + fn copy_from(bench: &mut criterion::Criterion) { let a = DMatrix::::new_random(1000, 1000); let mut b = DMatrix::::new_random(1000, 1000); @@ -235,6 +259,8 @@ criterion_group!( mat10_mul_mat10_static, mat100_mul_mat100, mat500_mul_mat500, + iter, + iter_rev, copy_from, axpy, tr_mul_to, diff --git a/src/base/iter.rs b/src/base/iter.rs index 1f330d95..f744cf02 100644 --- a/src/base/iter.rs +++ b/src/base/iter.rs @@ -1,5 +1,6 @@ //! Matrix iterators. +use std::iter::FusedIterator; use std::marker::PhantomData; use std::mem; @@ -111,6 +112,46 @@ macro_rules! iterator { } } + impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + $Storage> DoubleEndedIterator + for $Name<'a, N, R, C, S> + { + #[inline] + fn next_back(&mut self) -> Option<$Ref> { + unsafe { + if self.size == 0 { + None + } else { + // Pre-decrement `size` such that it now counts to the + // element we want to return. + self.size -= 1; + + // Fetch strides + let inner_stride = self.strides.0.value(); + let outer_stride = self.strides.1.value(); + + // Compute number of rows + // Division should be exact + let inner_raw_size = self.inner_end.offset_from(self.inner_ptr) as usize; + let inner_size = inner_raw_size / inner_stride; + + // Compute rows and cols remaining + let outer_remaining = self.size / inner_size; + let inner_remaining = self.size % inner_size; + + // Compute pointer to last element + let last = self.ptr.offset( + (outer_remaining * outer_stride + inner_remaining * inner_stride) + as isize, + ); + + // We want either `& *last` or `&mut *last` here, depending + // on the mutability of `$Ref`. + Some(mem::transmute(last)) + } + } + } + } + impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + $Storage> ExactSizeIterator for $Name<'a, N, R, C, S> { @@ -119,6 +160,11 @@ macro_rules! iterator { self.size } } + + impl<'a, N: Scalar, R: Dim, C: Dim, S: 'a + $Storage> FusedIterator + for $Name<'a, N, R, C, S> + { + } }; } diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index ed7b26d2..14eaeacd 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -21,6 +21,24 @@ fn iter() { assert_eq!(*it.next().unwrap(), 6.0); assert!(it.next().is_none()); + let mut it = a.iter(); + assert_eq!(*it.next().unwrap(), 1.0); + assert_eq!(*it.next_back().unwrap(), 6.0); + assert_eq!(*it.next_back().unwrap(), 3.0); + assert_eq!(*it.next_back().unwrap(), 5.0); + assert_eq!(*it.next().unwrap(), 4.0); + assert_eq!(*it.next().unwrap(), 2.0); + assert!(it.next().is_none()); + + let mut it = a.iter().rev(); + assert_eq!(*it.next().unwrap(), 6.0); + assert_eq!(*it.next().unwrap(), 3.0); + assert_eq!(*it.next().unwrap(), 5.0); + assert_eq!(*it.next().unwrap(), 2.0); + assert_eq!(*it.next().unwrap(), 4.0); + assert_eq!(*it.next().unwrap(), 1.0); + assert!(it.next().is_none()); + let row = a.row(0); let mut it = row.iter(); assert_eq!(*it.next().unwrap(), 1.0);