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:
parent
1ea9991921
commit
ab1bd3adf6
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue