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.
This commit is contained in:
Erick Tryzelaar 2014-06-23 19:27:54 -04:00
parent 1ea9991921
commit ab1bd3adf6
2 changed files with 44 additions and 20 deletions

View File

@ -587,20 +587,32 @@ impl<A> ExactSize<A> for Item<A> {}
/// ``` /// ```
#[inline] #[inline]
pub fn collect<T, Iter: Iterator<Option<T>>, V: FromIterator<T>>(iter: Iter) -> Option<V> { 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. // FIXME(#11084): This could be replaced with Iterator::scan when this
let mut iter = iter.scan(false, |state, x| { // performance bug is closed.
match x {
Some(x) => Some(x), struct Adapter<Iter> {
None => { iter: Iter,
*state = true; 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 => 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 None
} else { } else {
Some(v) Some(v)

View File

@ -585,20 +585,32 @@ impl<T: Show, E> Result<T, E> {
/// ``` /// ```
#[inline] #[inline]
pub fn collect<T, E, Iter: Iterator<Result<T, E>>, V: FromIterator<T>>(iter: Iter) -> Result<V, E> { 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. // FIXME(#11084): This could be replaced with Iterator::scan when this
let mut iter = iter.scan(None, |state, x| { // performance bug is closed.
match x {
Ok(x) => Some(x), struct Adapter<Iter, E> {
Err(err) => { iter: Iter,
*state = Some(err); 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 => 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), Some(err) => Err(err),
None => Ok(v), None => Ok(v),
} }