]> git.lizzy.rs Git - rust.git/commitdiff
Optimize rposition
authorBjörn Steinbrink <bsteinbr@gmail.com>
Tue, 3 Feb 2015 15:54:06 +0000 (16:54 +0100)
committerBjörn Steinbrink <bsteinbr@gmail.com>
Tue, 3 Feb 2015 15:54:06 +0000 (16:54 +0100)
The extra check caused by the expect() call can, in general, not be
optimized away, because the length of the iterator is unknown at compile
time, causing a noticable slow-down. Since the check only triggers if
the element isn't actually found in the iterator, i.e. it isn't
guaranteed to trigger for ill-behaved ExactSizeIterators, it seems
reasonable to switch to an implementation that doesn't need the check
and just always returns None if the value isn't found.

Benchmark:
````rust
let v: Vec<u8> = (0..1024*65).map(|_| 0).collect();
b.iter(|| {
    v.as_slice().iter().rposition(|&c| c == 1)
});
````

Before:
````
test rposition  ... bench:     49939 ns/iter (+/- 23)
````

After:
````
test rposition  ... bench:     33306 ns/iter (+/- 68)
````

src/libcore/iter.rs

index d0734f9c0395faec4b2713420651137cf4a3e4ec..417bcab5140aff56c234f9f67473daa054a41da9 100644 (file)
@@ -723,11 +723,12 @@ fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
         P: FnMut(Self::Item) -> bool,
         Self: ExactSizeIterator + DoubleEndedIterator
     {
-        let len = self.len();
-        for i in (0..len).rev() {
-            if predicate(self.next_back().expect("rposition: incorrect ExactSizeIterator")) {
+        let mut i = self.len() - 1;
+        while let Some(v) = self.next_back() {
+            if predicate(v) {
                 return Some(i);
             }
+            i -= 1;
         }
         None
     }