diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index cd62c3e05244c..73fb37ba796de 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1918,7 +1918,7 @@ impl<'a, T: 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec } impl Vec { - fn extend_desugared>(&mut self, mut iterator: I) { + fn extend_desugared>(&mut self, iterator: I) { // This is the case for a general iterator. // // This function should be the moral equivalent of: @@ -1926,18 +1926,19 @@ impl Vec { // for item in iterator { // self.push(item); // } - while let Some(element) = iterator.next() { + let (lower, _) = iterator.size_hint(); + self.reserve(lower); + // rust-lang/rust#59605: `for_each` call leverages specialized + // override, if any, of `for_each` or `fold` for Iterator `I`. + iterator.for_each(|element| { let len = self.len(); - if len == self.capacity() { - let (lower, _) = iterator.size_hint(); - self.reserve(lower.saturating_add(1)); - } + if len == self.capacity() { self.reserve(1); } unsafe { ptr::write(self.get_unchecked_mut(len), element); // NB can't overflow since we would have had to alloc the address space self.set_len(len + 1); } - } + }); } /// Creates a splicing iterator that replaces the specified range in the vector diff --git a/src/libcore/benches/iter.rs b/src/libcore/benches/iter.rs index 7dcfad8306fce..ce78446b4dd7d 100644 --- a/src/libcore/benches/iter.rs +++ b/src/libcore/benches/iter.rs @@ -344,3 +344,15 @@ fn bench_partial_cmp(b: &mut Bencher) { fn bench_lt(b: &mut Bencher) { b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box))) } + +// rust-lang/rust#11084: benchmark how built-in `FromIterator` for +// `Result` performs, to avoid unknowingly regressing its performance. +#[bench] +fn bench_result_from_iter_into_vec(b: &mut Bencher) { + let expected = vec![1; 1000]; + let v: Vec> = vec![Ok(1); 1000]; + b.iter(|| { + let result: Result, String> = FromIterator::from_iter(v.iter().cloned()); + assert_eq!(result.unwrap(), expected); + }); +} diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index cccd51b577930..eae3d3f74e45e 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -1672,6 +1672,21 @@ impl Iterator for Scan where } }).into_try() } + + #[inline] + fn fold(mut self, init: C, mut g: G) -> C where + Self: Sized, G: FnMut(C, Self::Item) -> C, + { + // self.try_fold(init, move |acc, x| Ok::(g(acc, x))).unwrap() + let state = &mut self.state; + let f = &mut self.f; + self.iter.fold(init, move |acc, x| { + match f(state, x) { + None => acc, + Some(x) => g(acc, x), + } + }) + } } /// An iterator that yields `None` forever after the underlying iterator diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 3da92c0a05ac4..7821592683e4d 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -1338,44 +1338,13 @@ impl> FromIterator> for Option { /// [`Iterator`]: ../iter/trait.Iterator.html #[inline] fn from_iter>>(iter: I) -> Option { - // FIXME(#11084): This could be replaced with Iterator::scan when this - // performance bug is closed. + let mut found_none = false; + let v: V = FromIterator::from_iter(iter.into_iter().scan((), |_, elem| { + if elem.is_none() { found_none = true; } + elem + })); - struct Adapter { - iter: Iter, - found_none: bool, - } - - impl>> Iterator for Adapter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Some(value)) => Some(value), - Some(None) => { - self.found_none = true; - None - } - None => None, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.found_none { - (0, Some(0)) - } else { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } - } - } - - let mut adapter = Adapter { iter: iter.into_iter(), found_none: false }; - let v: V = FromIterator::from_iter(adapter.by_ref()); - - if adapter.found_none { + if found_none { None } else { Some(v) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9b7b83689861b..183065c5e67cf 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1232,41 +1232,17 @@ impl> FromIterator> for Result { /// so the final value of `shared` is 6 (= `3 + 2 + 1`), not 16. #[inline] fn from_iter>>(iter: I) -> Result { - // FIXME(#11084): This could be replaced with Iterator::scan when this - // performance bug is closed. - - struct Adapter { - iter: Iter, - err: Option, - } - - impl>> Iterator for Adapter { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Ok(value)) => Some(value), - Some(Err(err)) => { - self.err = Some(err); - None - } - None => None, - } + let mut found_err = None; + let v: V = FromIterator::from_iter(iter.into_iter().scan((), |_, elem| { + match elem { + Err(err) => { found_err = Some(err); None } + Ok(v) => Some(v) } + })); - fn size_hint(&self) -> (usize, Option) { - let (_min, max) = self.iter.size_hint(); - (0, max) - } - } - - let mut adapter = Adapter { iter: iter.into_iter(), err: None }; - let v: V = FromIterator::from_iter(adapter.by_ref()); - - match adapter.err { + match found_err { Some(err) => Err(err), - None => Ok(v), + None => Ok(v) } } }