Skip to content

Commit

Permalink
Auto merge of #22200 - alexcrichton:opt-vec-collect, r=huonw
Browse files Browse the repository at this point in the history
This PR is an optimization of the `FromIterator` implementation of `Vec`

Benchmark: https://gist.github.com/alexcrichton/03d666159a28a80e7c70

Before:

    test macro_repeat1     ... bench:        57 ns/iter (+/- 1)
    test macro_repeat2     ... bench:        56 ns/iter (+/- 1)
    test map_clone1        ... bench:       828 ns/iter (+/- 13)
    test map_clone2        ... bench:       828 ns/iter (+/- 8)
    test repeat1           ... bench:      1104 ns/iter (+/- 10)
    test repeat2           ... bench:      1106 ns/iter (+/- 11)

After:

    test macro_repeat1     ... bench:        75 ns/iter (+/- 21)
    test macro_repeat2     ... bench:        59 ns/iter (+/- 31)
    test map_clone1        ... bench:        34 ns/iter (+/- 22)
    test map_clone2        ... bench:        52 ns/iter (+/- 21)
    test repeat1           ... bench:        34 ns/iter (+/- 11)
    test repeat2           ... bench:        33 ns/iter (+/- 12)

The idea behind this optimization is to avoid all bounds checks for space
already allocated into the vector. This may involve running the iterator twice,
but the first run of the iterator should be optimizable to a memcpy or memset if
possible.

The same treatment can in theory be applied to `Vec::extend` but the benchmarks
for that currently get *worse* if the change is applied. This appears to be some
LLVM optimizations going awry but it's seems prudent to land at least the
`collect` portion beforehand.
  • Loading branch information
bors committed Feb 13, 2015
2 parents cf636c2 + 985fc7d commit b9ba643
Showing 1 changed file with 11 additions and 1 deletion.
12 changes: 11 additions & 1 deletion src/libcollections/vec.rs
Expand Up @@ -1386,7 +1386,17 @@ impl<T> FromIterator<T> for Vec<T> {
fn from_iter<I:Iterator<Item=T>>(iterator: I) -> Vec<T> {
let (lower, _) = iterator.size_hint();
let mut vector = Vec::with_capacity(lower);
for element in iterator {

let mut i = iterator.fuse();
for element in i.by_ref().take(vector.capacity()) {
let len = vector.len();
unsafe {
ptr::write(vector.get_unchecked_mut(len), element);
vector.set_len(len + 1);
}
}

for element in i {
vector.push(element)
}
vector
Expand Down

0 comments on commit b9ba643

Please sign in to comment.