Merge pull request #797 from Recmo/remco/feat/double-ended-iter

impl DoubleEndedIterator for {MatrixIter, MatrixIterMut}
This commit is contained in:
Sébastien Crozet 2021-02-25 15:46:11 +01:00 committed by GitHub
commit bc6faa22f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 0 deletions

View File

@ -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::<f64>::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::<f64>::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::<f64>::new_random(1000, 1000);
let mut b = DMatrix::<f64>::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,

View File

@ -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<N, R, C>> 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<N, R, C>> 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<N, R, C>> FusedIterator
for $Name<'a, N, R, C, S>
{
}
};
}

View File

@ -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);