Skip to content

Commit fe30b5b

Browse files
committed
Try to guess a smarter initial capacity in Vec::from_iter
1 parent dbcb33f commit fe30b5b

File tree

1 file changed

+32
-11
lines changed

1 file changed

+32
-11
lines changed

src/liballoc/vec.rs

+32-11
Original file line numberDiff line numberDiff line change
@@ -1857,19 +1857,40 @@ impl<T, I> SpecExtend<T, I> for Vec<T>
18571857
// empty, but the loop in extend_desugared() is not going to see the
18581858
// vector being full in the few subsequent loop iterations.
18591859
// So we get better branch prediction.
1860-
let mut vector = match iterator.next() {
1861-
None => return Vec::new(),
1862-
Some(element) => {
1863-
let (lower, _) = iterator.size_hint();
1864-
let mut vector = Vec::with_capacity(lower.saturating_add(1));
1865-
unsafe {
1866-
ptr::write(vector.get_unchecked_mut(0), element);
1867-
vector.set_len(1);
1860+
let element =
1861+
if let Some(x) = iterator.next() { x }
1862+
else { return Vec::new() };
1863+
let (lower, upper) = iterator.size_hint();
1864+
let upper = upper.unwrap_or(lower);
1865+
let mut vector =
1866+
if lower >= upper / 2 {
1867+
// This branch covers three main cases:
1868+
// - There was no upper bound, so we just use the lower.
1869+
// - The hint turned out to be exact, so we use it.
1870+
// - Picking the upper won't waste more that the doubling
1871+
// strategy might anyway, so go directly there.
1872+
Vec::with_capacity(upper.saturating_add(1))
1873+
} else {
1874+
// Try to start near the geometric mean of the range. That's
1875+
// never all that high -- even 0B..1GB will only allocate 32kB --
1876+
// but it's much more useful than the lower bound, especially
1877+
// for iterator adapters like filter that have lower == 0.
1878+
let mut v = Vec::new();
1879+
let mag_diff = lower.leading_zeros() - upper.leading_zeros();
1880+
let guess = upper >> (mag_diff / 2);
1881+
match v.try_reserve(guess.saturating_add(1)) {
1882+
Ok(_) => v,
1883+
Err(_) => Vec::with_capacity(lower.saturating_add(1)),
18681884
}
1869-
vector
1870-
}
1871-
};
1885+
};
1886+
unsafe {
1887+
ptr::write(vector.get_unchecked_mut(0), element);
1888+
vector.set_len(1);
1889+
}
18721890
<Vec<T> as SpecExtend<T, I>>::spec_extend(&mut vector, iterator);
1891+
if vector.len() < vector.capacity() / 2 {
1892+
vector.shrink_to_fit();
1893+
}
18731894
vector
18741895
}
18751896

0 commit comments

Comments
 (0)