]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #24180 - huonw:optimise-max-etc, r=alexcrichton
authorbors <bors@rust-lang.org>
Fri, 10 Apr 2015 07:54:18 +0000 (07:54 +0000)
committerbors <bors@rust-lang.org>
Fri, 10 Apr 2015 07:54:18 +0000 (07:54 +0000)
The main change in this patch is removing the use of `Option` inside the
inner loops of those functions to avoid comparisons where one branch
will only trigger on the first pass through the loop.

The included benchmarks go from:

    test bench_max    ... bench:       372 ns/iter (+/- 118)
    test bench_max_by ... bench:       428 ns/iter (+/- 33)
    test bench_max_by2 ... bench:      7128 ns/iter (+/- 326)

to:

    test bench_max    ... bench:       317 ns/iter (+/- 64)
    test bench_max_by ... bench:       356 ns/iter (+/- 270)
    test bench_max_by2 ... bench:      1387 ns/iter (+/- 183)

Problem noticed in http://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/

1  2 
src/libcore/iter.rs
src/libcoretest/iter.rs

index 8cbdda758697b370bee105c7d5d409d6d9276c31,8feae0bfb09eb46c25d7f31f48f498f1eadf6684..527a7297f85b9912142b20e9a459228acf7c20bc
@@@ -1023,49 -1012,39 +1013,80 @@@ pub trait Iterator 
              }
          }
      }
 +
 +    /// Iterates over the entire iterator, summing up all the elements
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```
 +    /// # #![feature(core)]
 +    ///
 +    /// let a = [1, 2, 3, 4, 5];
 +    /// let mut it = a.iter().cloned();
 +    /// assert!(it.sum::<i32>() == 15);
 +    /// ```
 +    #[unstable(feature="core")]
 +    fn sum<S=<Self as Iterator>::Item>(self) -> S where
 +        S: Add<Self::Item, Output=S> + Zero,
 +        Self: Sized,
 +    {
 +        self.fold(Zero::zero(), |s, e| s + e)
 +    }
 +
 +    /// Iterates over the entire iterator, multiplying all the elements
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```
 +    /// # #![feature(core)]
 +    ///
 +    /// fn factorial(n: u32) -> u32 {
 +    ///     (1..).take_while(|&i| i <= n).product()
 +    /// }
 +    /// assert!(factorial(0) == 1);
 +    /// assert!(factorial(1) == 1);
 +    /// assert!(factorial(5) == 120);
 +    /// ```
 +    #[unstable(feature="core")]
 +    fn product<P=<Self as Iterator>::Item>(self) -> P where
 +        P: Mul<Self::Item, Output=P> + One,
 +        Self: Sized,
 +    {
 +        self.fold(One::one(), |p, e| p * e)
 +    }
  }
  
+ /// Select an element from an iterator based on the given projection
+ /// and "comparison" function.
+ ///
+ /// This is an idiosyncratic helper to try to factor out the
+ /// commonalities of {max,min}{,_by}. In particular, this avoids
+ /// having to implement optimisations several times.
+ #[inline]
+ fn select_fold1<I,B, FProj, FCmp>(mut it: I,
+                                   mut f_proj: FProj,
+                                   mut f_cmp: FCmp) -> Option<(B, I::Item)>
+     where I: Iterator,
+           FProj: FnMut(&I::Item) -> B,
+           FCmp: FnMut(&B, &I::Item, &B, &I::Item) -> bool
+ {
+     // start with the first element as our selection. This avoids
+     // having to use `Option`s inside the loop, translating to a
+     // sizeable performance gain (6x in one case).
+     it.next().map(|mut sel| {
+         let mut sel_p = f_proj(&sel);
+         for x in it {
+             let x_p = f_proj(&x);
+             if f_cmp(&sel_p,  &sel, &x_p, &x) {
+                 sel = x;
+                 sel_p = x_p;
+             }
+         }
+         (sel_p, sel)
+     })
+ }
  #[stable(feature = "rust1", since = "1.0.0")]
  impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I {
      type Item = I::Item;
Simple merge