-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Specialize methods on iter::Cloned<I> where I::Item: Copy. #36791
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
Conversation
r? @aturon (rust_highfive has picked a reviewer for you, use r? to override) |
Please wait for travis to pass before bringing in bors. I'm at a coffee shop with a slow internet connection and an out-of-date rust snapshot so I can't so much as run |
In the future, it might be nice to introduce an auto-derived |
Tripping over #36053. We may have to wait a cycle (or backport to beta). |
cc @rust-lang/libs, @bluss |
Then it can implement |
Also, the cloned adapter (well, adapters in general) appear to be inhibiting some optimizations. Benchmarks: #![feature(test)]
extern crate test;
use test::Bencher;
#[bench]
fn bench_cloned(b: &mut Bencher) {
let strings: Vec<_> = vec!["asfd"; 1000];
b.iter(|| {
for i in test::black_box(strings.iter()).cloned() {
test::black_box(i);
}
})
}
#[bench]
fn bench_map(b: &mut Bencher) {
let strings: Vec<_> = vec!["asfd"; 1000];
b.iter(|| {
for i in test::black_box(strings.iter()).map(|&x|x) {
test::black_box(i);
}
})
}
#[bench]
fn bench_pat(b: &mut Bencher) {
let strings: Vec<_> = vec!["asfd"; 1000];
b.iter(|| {
for &i in test::black_box(strings.iter()) {
test::black_box(i);
}
})
}
Edit: Actually, I think the last case is just optimizing the deref somehow. Never mind. #[bench]
fn bench_deref(b: &mut Bencher) {
let strings: Vec<_> = vec!["asfd"; 1000];
b.iter(|| {
for i in test::black_box(strings.iter()) {
test::black_box(*test::black_box(i));
}
})
}
|
@Stebalien It's pretty hard to say if those results are realistic, or artifacts of how black box interacts with the optimization of the loop. I'll put in my own straw men: integer sum/autovectorization and linear search and here all the three variants are the same. https://gist.github.com/bluss/3f5ded1cdd7304e1abc7dc586ed1c1fa |
Instead of cloning a bunch of copyable types only to drop them (in `nth`, `last`, and `count`), take advantage of rust-lang#1521 (Copy clone semantics) and don't bother cloning them in the first place (directly call `nth`, `last`, and `count` on the wrapped iterator). If the wrapped iterator optimizes these methods, `Cloned` now inherits this optimization.
dfda6a9
to
a19d61a
Compare
@Stebalien if this is rebased, perhaps it's got a green travis now? |
Not unless #36848 has been fixed. |
Ah ok, in that case do we want to close this? |
Might as well. |
A common idiom when iterating over a collection of, e.g.,
&str
s is to writemy_collection.iter().cloned().something_else()
. Unfortunately, because the call toclone
might do something interesting, we can't specializecount
,last
, andnth
as discussed in #28125. However, now that rust-lang/rfcs#1521 has been merged and we have specialization, we can specializecount
,last
, andnth
foriter::Cloned<I> where I::Item: Copy
(this also optimizesskip
). Benchmarks below:Results: