Skip to content

Commit 5375ce4

Browse files
authored
Rollup merge of rust-lang#52910 - ljedrz:fix_48994, r=sfackler
Calculate capacity when collecting into Option and Result I was browsing the [perf page](http://perf.rust-lang.org) to see the impact of my recent changes (e.g. rust-lang#52697) and I was surprised that some of the results were not as awesome as I expected. I dug some more and found an issue that is the probable culprit: [Collecting into a Result<Vec<_>> doesn't reserve the capacity in advance](rust-lang#48994). Collecting into `Option` or `Result` might result in an empty collection, but there is no reason why we shouldn't provide a non-zero lower bound when we know the `Iterator` we are collecting from doesn't contain any `None` or `Err`. We know this, because the `Adapter` iterator used in the `FromIterator` implementations for `Option` and `Result` registers if any `None` or `Err` are present in the `Iterator` in question; we can use this information and return a more accurate lower bound in case we know it won't be equal to zero. I [have benchmarked](https://gist.github.com/ljedrz/c2fcc19f6260976ae7a46ae47aa71fb5) collecting into `Option` and `Result` using the current implementation and one with the proposed changes; I have also benchmarked a push loop with a known capacity as a reference that should be slower than using `FromIterator` (i.e. `collect()`). The results are quite promising: ``` test bench_collect_to_option_new ... bench: 246 ns/iter (+/- 23) test bench_collect_to_option_old ... bench: 954 ns/iter (+/- 54) test bench_collect_to_result_new ... bench: 250 ns/iter (+/- 25) test bench_collect_to_result_old ... bench: 939 ns/iter (+/- 104) test bench_push_loop_to_option ... bench: 294 ns/iter (+/- 21) test bench_push_loop_to_result ... bench: 303 ns/iter (+/- 29) ``` Fixes rust-lang#48994.
2 parents 9a7af03 + 77aa031 commit 5375ce4

File tree

2 files changed

+7
-4
lines changed

2 files changed

+7
-4
lines changed

src/libcore/option.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,8 +1277,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
12771277
if self.found_none {
12781278
(0, Some(0))
12791279
} else {
1280-
let (_, upper) = self.iter.size_hint();
1281-
(0, upper)
1280+
self.iter.size_hint()
12821281
}
12831282
}
12841283
}

src/libcore/result.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,9 +1214,13 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
12141214
}
12151215
}
12161216

1217+
#[inline]
12171218
fn size_hint(&self) -> (usize, Option<usize>) {
1218-
let (_min, max) = self.iter.size_hint();
1219-
(0, max)
1219+
if self.err.is_some() {
1220+
(0, Some(0))
1221+
} else {
1222+
self.iter.size_hint()
1223+
}
12201224
}
12211225
}
12221226

0 commit comments

Comments
 (0)