-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace push loops with extend() where possible #52738
Conversation
r? @eddyb (rust_highfive has picked a reviewer for you, use r? to override) |
Drive by comment, All these lovely clean up prs you have submitted... maybe we should suggest that clippy lint for them? So they can spread to the ecosystem? |
@Eh2406 clippy has an impressive set of working lints and some of them were a direct inspiration for some of my cleanups. I checked the ones that I haven't seen in clippy and it appears that they have already been proposed 😃: |
src/libsyntax/ast.rs
Outdated
@@ -949,7 +949,7 @@ impl Expr { | |||
ExprKind::Array(exprs) if exprs.len() == 1 => | |||
exprs[0].to_ty().map(TyKind::Slice)?, | |||
ExprKind::Tup(exprs) => { | |||
let mut tys = Vec::new(); | |||
let mut tys = Vec::with_capacity(exprs.len()); | |||
for expr in exprs { | |||
tys.push(expr.to_ty()?); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can do this sort of thing by using .collect::<Result<Vec<_>, _>>()
(for Result
element types).
src/librustc/cfg/construct.rs
Outdated
for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() { | ||
data.exiting_scopes.push(id); | ||
} | ||
data.exiting_scopes.extend( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be collect
instead.
for (_, obligation) in r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id) { | ||
my_region_obligations.push(obligation); | ||
} | ||
my_region_obligations.extend( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be collect
instead.
} | ||
signature_metadata.extend( | ||
signature.inputs().iter().map(|argument_type| type_metadata(cx, argument_type, span)) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be collect
instead (using iter::once
for the first element above).
for n in glob_map.get(&id).unwrap() { | ||
names.push(n.to_string()); | ||
} | ||
names.extend(glob_map.get(&id).unwrap().iter().map(|n| n.to_string())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be collect
instead.
src/libstd/sys/redox/process.rs
Outdated
for arg in self.args.iter() { | ||
args.push([arg.as_ptr() as usize, arg.len()]); | ||
} | ||
args.extend(self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be collect
instead (with iter::once
).
for declared_bound in ¶m.bounds { | ||
bounds.push((*declared_bound).clone()); | ||
} | ||
bounds.extend(param.bounds.iter().cloned()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be collect
instead.
@eddyb great suggestions, applied. thanks! |
Rebased after 1bc49a9. |
} | ||
let mut r_o = self.region_obligations.borrow_mut(); | ||
let my_region_obligations = r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id) | ||
.map(|(_, obligation)| obligation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure you need to collect this, and not hold that borrow_mut
for that long, because the loop calls methods on self
which could try to borrow again self.region_obligations
. cc @nikomatsakis
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to collect this, but the borrowed value didn't live long enough
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What did you write? I'm guessing it's just some scope thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, let v = { let mut x = y.borrow_mut(); x.foo().collect() };
doesn't work, you need another variable inside the block, e.g. let v = { let mut x = y.borrow_mut(); let v = x.foo().collect(); v };
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah, that should work; I'll fix this shortly.
src/libsyntax/ast.rs
Outdated
@@ -500,7 +500,7 @@ impl Pat { | |||
PatKind::Slice(pats, None, _) if pats.len() == 1 => | |||
pats[0].to_ty().map(TyKind::Slice)?, | |||
PatKind::Tuple(pats, None) => { | |||
let mut tys = Vec::new(); | |||
let mut tys = Vec::with_capacity(pats.len()); | |||
for pat in pats { | |||
tys.push(pat.to_ty()?); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure this can also use collect
(it's a lot like the code below).
@bors r+ |
📌 Commit 6071fb762a3add82a54307fbe79df83c5c9bdb85 has been approved by |
⌛ Testing commit 6071fb762a3add82a54307fbe79df83c5c9bdb85 with merge e7f363a2f3b01512e6ca1cdd569db506711f38a5... |
💔 Test failed - status-travis |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
Ah yes, Redox isn't |
@eddyb can you ask bors to retry? |
@bors r+ |
📌 Commit 59c8a27 has been approved by |
Replace push loops with extend() where possible Or set the vector capacity where I couldn't do it. According to my [simple benchmark](https://gist.github.com/ljedrz/568e97621b749849684c1da71c27dceb) `extend`ing a vector can be over **10 times** faster than `push`ing to it in a loop: 10 elements (6.1 times faster): ``` test bench_extension ... bench: 75 ns/iter (+/- 23) test bench_push_loop ... bench: 458 ns/iter (+/- 142) ``` 100 elements (11.12 times faster): ``` test bench_extension ... bench: 87 ns/iter (+/- 26) test bench_push_loop ... bench: 968 ns/iter (+/- 3,528) ``` 1000 elements (11.04 times faster): ``` test bench_extension ... bench: 311 ns/iter (+/- 9) test bench_push_loop ... bench: 3,436 ns/iter (+/- 233) ``` Seems like a good idea to use `extend` as much as possible.
☀️ Test successful - status-appveyor, status-travis |
…-Simulacrum Use Vec::extend in SmallVec::extend when applicable As calculated in rust-lang#52738, `Vec::extend` is much faster than `push`ing to it in a loop. We can take advantage of this method in `SmallVec` too - at least in cases when its underlying object is an `AccumulateVec::Heap`. ~~This approach also accidentally improves the `push` loop of the `AccumulateVec::Array` variant, because it doesn't utilize `SmallVec::push` which performs `self.reserve(1)` with every iteration; this is unnecessary, because we're already reserving the whole space we will be needing by performing `self.reserve(iter.size_hint().0)` at the beginning.~~
…-Simulacrum Use Vec::extend in SmallVec::extend when applicable As calculated in rust-lang#52738, `Vec::extend` is much faster than `push`ing to it in a loop. We can take advantage of this method in `SmallVec` too - at least in cases when its underlying object is an `AccumulateVec::Heap`. ~~This approach also accidentally improves the `push` loop of the `AccumulateVec::Array` variant, because it doesn't utilize `SmallVec::push` which performs `self.reserve(1)` with every iteration; this is unnecessary, because we're already reserving the whole space we will be needing by performing `self.reserve(iter.size_hint().0)` at the beginning.~~
Don't collect() when size_hint is useless This adjusts PRs rust-lang#52738 and rust-lang#52697 by falling back to calculating capacity and extending or pushing in a loop where `collect()` can't be trusted to calculate the right capacity. It is a performance win.
Don't collect() when size_hint is useless This adjusts PRs rust-lang#52738 and rust-lang#52697 by falling back to calculating capacity and extending or pushing in a loop where `collect()` can't be trusted to calculate the right capacity. It is a performance win.
Or set the vector capacity where I couldn't do it.
According to my simple benchmark
extend
ing a vector can be over 10 times faster thanpush
ing to it in a loop:10 elements (6.1 times faster):
100 elements (11.12 times faster):
1000 elements (11.04 times faster):
Seems like a good idea to use
extend
as much as possible.