Skip to content

Commit b9ba643

Browse files
committed
Auto merge of #22200 - alexcrichton:opt-vec-collect, r=huonw
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.
2 parents cf636c2 + 985fc7d commit b9ba643

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

src/libcollections/vec.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,17 @@ impl<T> FromIterator<T> for Vec<T> {
13861386
fn from_iter<I:Iterator<Item=T>>(iterator: I) -> Vec<T> {
13871387
let (lower, _) = iterator.size_hint();
13881388
let mut vector = Vec::with_capacity(lower);
1389-
for element in iterator {
1389+
1390+
let mut i = iterator.fuse();
1391+
for element in i.by_ref().take(vector.capacity()) {
1392+
let len = vector.len();
1393+
unsafe {
1394+
ptr::write(vector.get_unchecked_mut(len), element);
1395+
vector.set_len(len + 1);
1396+
}
1397+
}
1398+
1399+
for element in i {
13901400
vector.push(element)
13911401
}
13921402
vector

0 commit comments

Comments
 (0)