Add Extend::{extend_one,extend_reserve} by cuviper · Pull Request #72162 · rust-lang/rust (original) (raw)
Are we using size hints already to pre-reserve?
There's no way to do that in partition
and unzip
as-is, since they only have Default + Extend
to work with. So that new pre-allocation does play a big part in the performance gain.
I would've expected an extend(Some(foo)) to basically compile down to a push - if that doesn't happen today, perhaps worth investigating?
Here's a playground of the benchmarks from #72085, and my local results:
test bench_functional ... bench: 1,292 ns/iter (+/- 31)
test bench_imperative_extend ... bench: 803 ns/iter (+/- 8)
test bench_imperative_push ... bench: 410 ns/iter (+/- 6)
Note that functional
is the status quo unzip
, whereas this PR gets it down to push
performance.
Looking at the assembly, the biggest difference I see is that extend(Some(_))
has an unconditional call to reserve
, I believe from here, whereas push only calls that when it actually needs more capacity. Maybe we could branch like that in extend
too, but I think that would pessimize the general case, compared to partition
and unzip
that are hammering extend
in a loop.
That's particular to Vec
-- other containers may have their own trade-offs. Note that I did make the default extend_one
just call extend(Some(_))
anyway.
I think the only reason we have the somewhat awkward method names is also because Extend is im the prelude, right? So we don't want to use e.g. push and reserve?
Yeah, I think being in the prelude warrants caution in method ambiguity.