Skip to content

Commit 1b90dab

Browse files
committed
Make Iterator::unzip fast
Closes rust-lang#72085 This consists of the following optimizations: * Adds a `with_capacity` function to `Extend`. This definitely needs more thought if it's going to be stabilized, so I'm not writing an RFC yet. This takes off most of the performance gap. * Optimizes `Vec`'s `Extend` implementation for the case where `size_hint` is 1. This shaves off the remaining performance gap.
1 parent d903a9d commit 1b90dab

File tree

4 files changed

+24
-3
lines changed

4 files changed

+24
-3
lines changed

src/liballoc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@
125125
#![feature(alloc_layout_extra)]
126126
#![feature(try_trait)]
127127
#![feature(associated_type_bounds)]
128+
#![feature(extend_with_capacity)]
128129

129130
// Allow testing this library
130131

src/liballoc/vec.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2048,6 +2048,11 @@ impl<T> Extend<T> for Vec<T> {
20482048
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
20492049
<Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter())
20502050
}
2051+
2052+
#[inline]
2053+
fn with_capacity(capacity: usize) -> Self {
2054+
Self::with_capacity(capacity)
2055+
}
20512056
}
20522057

20532058
// Specialization trait used for Vec::from_iter and Vec::extend
@@ -2097,7 +2102,7 @@ where
20972102
vector
20982103
}
20992104

2100-
default fn spec_extend(&mut self, iterator: I) {
2105+
default fn spec_extend(&mut self, mut iterator: I) {
21012106
// This is the case for a TrustedLen iterator.
21022107
let (low, high) = iterator.size_hint();
21032108
if let Some(high_value) = high {
@@ -2109,6 +2114,14 @@ where
21092114
);
21102115
}
21112116
if let Some(additional) = high {
2117+
if additional == 1 {
2118+
// work around inefficiencies in generic vec.extend(Some(x))
2119+
if let Some(x) = iterator.next() {
2120+
self.push(x);
2121+
}
2122+
return;
2123+
}
2124+
21122125
self.reserve(additional);
21132126
unsafe {
21142127
let mut ptr = self.as_mut_ptr().add(self.len());

src/libcore/iter/traits/collect.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,12 @@ pub trait Extend<A> {
341341
/// ```
342342
#[stable(feature = "rust1", since = "1.0.0")]
343343
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T);
344+
345+
/// Creates this collection with a reserved capacity.
346+
#[unstable(feature = "extend_with_capacity", issue = "none")]
347+
fn with_capacity(_capacity: usize) -> Self where Self: Default {
348+
Self::default()
349+
}
344350
}
345351

346352
#[stable(feature = "extend_for_unit", since = "1.28.0")]

src/libcore/iter/traits/iterator.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2672,8 +2672,9 @@ pub trait Iterator {
26722672
}
26732673
}
26742674

2675-
let mut ts: FromA = Default::default();
2676-
let mut us: FromB = Default::default();
2675+
let cap = self.size_hint().0.saturating_add(1);
2676+
let mut ts: FromA = Extend::with_capacity(cap);
2677+
let mut us: FromB = Extend::with_capacity(cap);
26772678

26782679
self.for_each(extend(&mut ts, &mut us));
26792680

0 commit comments

Comments
 (0)