Skip to content
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

Remove duplicated code from Iterator::{ne, lt, le, gt, ge} #59262

Merged
merged 3 commits into from
Apr 2, 2019
Merged

Remove duplicated code from Iterator::{ne, lt, le, gt, ge} #59262

merged 3 commits into from
Apr 2, 2019

Conversation

timvermeulen
Copy link
Contributor

This PR delegates Iterator::ne to Iterator::eq and Iterator::{lt, le, gt, ge} to Iterator::partial_cmp.

Oddly enough, this change actually simplifies the generated assembly in some cases, although I don't understand assembly well enough to see if the longer assembly is doing something clever.

I also added two extremely simple benchmarks:

// before
test iter::bench_lt               ... bench:      98,404 ns/iter (+/- 21,008)
test iter::bench_partial_cmp      ... bench:      62,437 ns/iter (+/- 5,009)

// after
test iter::bench_lt               ... bench:      61,757 ns/iter (+/- 8,770)
test iter::bench_partial_cmp      ... bench:      62,151 ns/iter (+/- 13,753)

I have no idea why the current lt/le/gt/ge implementations don't seem to be compiled optimally, but simply having them call partial_cmp seems to be an improvement.

See #44729 for a previous discussion.

@rust-highfive
Copy link
Collaborator

r? @Kimundi

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 17, 2019
Some(Ordering::Greater) => return false,
None => return false,
}
match self.partial_cmp(other) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not self.partial_cmp(other) == Some(Ordering::Less)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, you probably wanted to keep it consistent across le/lt/ge/gt... I think that's okay then

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was indeed the rationale, but looking at it again, it might actually be worth it. It's a lot simpler and it's still consistent between lt/gt.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So is it worth to also fix std::cmp::PartialOrd?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean exactly?

@hellow554
Copy link
Contributor

hellow554 commented Mar 18, 2019

What about eq/ne (ne already does !eq)?

@hellow554
Copy link
Contributor

You could also redirect parital_cmp to cmp, e.g. and wrapping it into Some, because they use exactly the same code :/

@timvermeulen
Copy link
Contributor Author

@hellow554 Unfortunately we can't forward partial_cmp to cmp since cmp requires that Self::Item: Ord. I suppose we could instead forward cmp to partial_cmp (+ .unwrap()), but that doesn't seem worth it. The same applies to eq, it can't be forwarded to cmp/partial_cmp.

There's indeed still some code duplication left but I haven't found a nice way to get rid of it without sacrificing readability. I'm open to suggestions though!

@hellow554
Copy link
Contributor

I suppose we could instead forward cmp to partial_cmp (+ .unwrap()), but that doesn't seem worth it.

I think it's worth it, because they share the exact same code (except the Option stuff). Code duplication is almost always bad, so why not remove it?

@timvermeulen
Copy link
Contributor Author

As much as I'd like to get rid of all the duplicate code here, I think that particular abstraction is the wrong one to make (in part because it's not obvious to me whether it will always compile the same way, in case the compiler doesn't figure out the None case is impossible). It would also not get rid of the duplicate code in eq, so maybe we should instead try to come up with a function that eq/partial_cmp/cmp can all forward to (but not necessarily in this PR).

@Centril
Copy link
Contributor

Centril commented Mar 30, 2019

r? @scottmcm

@rust-highfive rust-highfive assigned scottmcm and unassigned Kimundi Mar 30, 2019
@scottmcm
Copy link
Member

scottmcm commented Apr 2, 2019

Sure, making the way this is implemented match how le/gt/etc are implemented on PartialOrd sounds good to me.

@bors r+ rollup

(We might do something different if we could abort early for lengths, but we can't for general iterators)

@bors
Copy link
Contributor

bors commented Apr 2, 2019

📌 Commit 075b269 has been approved by scottmcm

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 2, 2019
@bors
Copy link
Contributor

bors commented Apr 2, 2019

💡 This pull request was already approved, no need to approve it again.

@bors
Copy link
Contributor

bors commented Apr 2, 2019

📌 Commit 075b269 has been approved by scottmcm

Centril added a commit to Centril/rust that referenced this pull request Apr 2, 2019
…scottmcm

Remove duplicated code from Iterator::{ne, lt, le, gt, ge}

This PR delegates `Iterator::ne` to `Iterator::eq` and `Iterator::{lt, le, gt, ge}` to `Iterator::partial_cmp`.

Oddly enough, this change actually simplifies the generated assembly [in some cases](https://rust.godbolt.org/z/riBtNe), although I don't understand assembly well enough to see if the longer assembly is doing something clever.

I also added two extremely simple benchmarks:
```
// before
test iter::bench_lt               ... bench:      98,404 ns/iter (+/- 21,008)
test iter::bench_partial_cmp      ... bench:      62,437 ns/iter (+/- 5,009)

// after
test iter::bench_lt               ... bench:      61,757 ns/iter (+/- 8,770)
test iter::bench_partial_cmp      ... bench:      62,151 ns/iter (+/- 13,753)
```

I have no idea why the current `lt`/`le`/`gt`/`ge` implementations don't seem to be compiled optimally, but simply having them call `partial_cmp` seems to be an improvement.

See rust-lang#44729 for a previous discussion.
bors added a commit that referenced this pull request Apr 2, 2019
Rollup of 8 pull requests

Successful merges:

 - #59262 (Remove duplicated code from Iterator::{ne, lt, le, gt, ge})
 - #59286 (Refactor async fn return type lowering)
 - #59444 (Implement useful steps_between for all integers)
 - #59452 (Speed up rustdoc run a bit)
 - #59533 (Support allocating iterators with arenas)
 - #59585 (Fixes for shallow borrows)
 - #59607 (Renames `EvalErrorKind` to `InterpError`)
 - #59613 (SGX target: convert a bunch of panics to aborts)

Failed merges:

 - #59630 (Shrink `mir::Statement`.)

r? @ghost
@bors bors merged commit 075b269 into rust-lang:master Apr 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants