about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorErick Tryzelaar <erick.tryzelaar@gmail.com>2014-06-23 19:27:54 -0400
committerErick Tryzelaar <erick.tryzelaar@gmail.com>2014-06-29 12:32:24 -0700
commitab1bd3adf673ef7a515242a2dcc09ce360d41d9c (patch)
treef4bab1a0c84e691a800be3d8e9cbb7c7cb197714 /src/libcore
parent1ea9991921d2969517e445230997b8771d84bdb4 (diff)
downloadrust-ab1bd3adf673ef7a515242a2dcc09ce360d41d9c.tar.gz
rust-ab1bd3adf673ef7a515242a2dcc09ce360d41d9c.zip
core: optimize {option,result}::collect
The bug #11084 causes these collect functions to run about
twice as slow as they should because llvm is having trouble
optimizing away the closure for some reason. This patch works
around that performance bug by using a simple adapter iterator
explicitly for capturing if the outer iterator returns an
error.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/option.rs32
-rw-r--r--src/libcore/result.rs32
2 files changed, 44 insertions, 20 deletions
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index 9748235e94a..8fb10fcca0c 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -587,20 +587,32 @@ impl<A> ExactSize<A> for Item<A> {}
 /// ```
 #[inline]
 pub fn collect<T, Iter: Iterator<Option<T>>, V: FromIterator<T>>(iter: Iter) -> Option<V> {
-    // FIXME(#11084): This should be twice as fast once this bug is closed.
-    let mut iter = iter.scan(false, |state, x| {
-        match x {
-            Some(x) => Some(x),
-            None => {
-                *state = true;
-                None
+    // FIXME(#11084): This could be replaced with Iterator::scan when this
+    // performance bug is closed.
+
+    struct Adapter<Iter> {
+        iter: Iter,
+        found_none: bool,
+    }
+
+    impl<T, Iter: Iterator<Option<T>>> Iterator<T> for Adapter<Iter> {
+        #[inline]
+        fn next(&mut self) -> Option<T> {
+            match self.iter.next() {
+                Some(Some(value)) => Some(value),
+                Some(None) => {
+                    self.found_none = true;
+                    None
+                }
+                None => None,
             }
         }
-    });
+    }
 
-    let v: V = FromIterator::from_iter(iter.by_ref());
+    let mut adapter = Adapter { iter: iter, found_none: false };
+    let v: V = FromIterator::from_iter(adapter.by_ref());
 
-    if iter.state {
+    if adapter.found_none {
         None
     } else {
         Some(v)
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 6c163b79199..8cd56713ffb 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -585,20 +585,32 @@ impl<T: Show, E> Result<T, E> {
 /// ```
 #[inline]
 pub fn collect<T, E, Iter: Iterator<Result<T, E>>, V: FromIterator<T>>(iter: Iter) -> Result<V, E> {
-    // FIXME(#11084): This should be twice as fast once this bug is closed.
-    let mut iter = iter.scan(None, |state, x| {
-        match x {
-            Ok(x) => Some(x),
-            Err(err) => {
-                *state = Some(err);
-                None
+    // FIXME(#11084): This could be replaced with Iterator::scan when this
+    // performance bug is closed.
+
+    struct Adapter<Iter, E> {
+        iter: Iter,
+        err: Option<E>,
+    }
+
+    impl<T, E, Iter: Iterator<Result<T, E>>> Iterator<T> for Adapter<Iter, E> {
+        #[inline]
+        fn next(&mut self) -> Option<T> {
+            match self.iter.next() {
+                Some(Ok(value)) => Some(value),
+                Some(Err(err)) => {
+                    self.err = Some(err);
+                    None
+                }
+                None => None,
             }
         }
-    });
+    }
 
-    let v: V = FromIterator::from_iter(iter.by_ref());
+    let mut adapter = Adapter { iter: iter, err: None };
+    let v: V = FromIterator::from_iter(adapter.by_ref());
 
-    match iter.state {
+    match adapter.err {
         Some(err) => Err(err),
         None => Ok(v),
     }