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

Add Iterator::partition_in_place() and is_partitioned() #62278

Merged
merged 7 commits into from
Jul 10, 2019

Conversation

cuviper
Copy link
Member

@cuviper cuviper commented Jul 1, 2019

partition_in_place() swaps &mut T items in-place to satisfy the
predicate, so all true items precede all false items. This requires
a DoubleEndedIterator so we can search from front and back for items
that need swapping.

is_partitioned() checks whether the predicate is already satisfied.

@rust-highfive
Copy link
Collaborator

r? @alexcrichton

(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 Jul 1, 2019
@Mark-Simulacrum
Copy link
Member

inplace_partition personally sounds like a better name to me than partition_mut.

@cuviper
Copy link
Member Author

cuviper commented Jul 1, 2019

These are inspired by C++ partition and is_partitioned, spurred by this question about mimicking #include <algorithm>.

This requires a DoubleEndedIterator so we can search from front and back for items that need swapping.

Implementation note: C++ allows partition with only ForwardIt, but they have to use two mutable iterators (cursors) to implement it, which Rust can't really allow. The best I could imagine is keeping a queue of &mut T we've already seen, eligible for swapping, which would require allocation (non-core) and seems generally distasteful.

C++ does talk about bi-directional modes too, which I imagine would work like what I have here.

@Mark-Simulacrum

inplace_partition personally sounds like a better name to me than partition_mut.

I'm open to renaming. I don't think an inplace_ prefix is used anywhere else, but there are examples of ptr::drop_in_place and Alloc::grow_in_place and shrink_in_place.

@Mark-Simulacrum
Copy link
Member

Ah -- in that case I think partition_in_place is probably the better name. I thought we had something similar :) I think the _mut suffix is a bit odd, since the iterator must be &mut to even be able to call the method.

@cuviper
Copy link
Member Author

cuviper commented Jul 1, 2019

I would have used partition alone if it didn't exist! 🙂 Ours is similar to C++'s partition_copy.

@jonas-schievink jonas-schievink added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Jul 1, 2019
@cuviper
Copy link
Member Author

cuviper commented Jul 1, 2019

There's also itertools::partition() -- at a (too-brief) glance I had assumed it was just an IntoIterator wrapper on Iterator::partition, like many of their other free functions, but it actually does the same as my partition_mut, in-place. They return the usize index of the partition split, which seems useful.

I wonder if we might also want an index from is_partitioned, or another method along these lines like find_partition(pred) -> Option<usize>. C++ has partition_point returning an iterator, but we can approximate that already with skip_while(predicate).

@Centril
Copy link
Contributor

Centril commented Jul 1, 2019

_in_place does seem like the better naming.

I would have used partition alone if it didn't exist! 🙂 Ours is similar to C++'s partition_copy.

(That wouldn't have been very appropriate imo as our naming is primarily Haskell based...)

@cuviper cuviper changed the title Add Iterator::partition_mut() and is_partitioned() Add Iterator::partition_in_place() and is_partitioned() Jul 1, 2019
@cuviper
Copy link
Member Author

cuviper commented Jul 1, 2019

OK, that's 3 votes for partition_in_place -- changed!

@alexcrichton
Copy link
Member

This looks great to me, thanks @cuviper! Could a few more tests be included as well beyond the doc tests?

Otherwise API-wise would it be feasible to return a usize from partition_in_place to indicate the size of one of the partitions? That way for array indexing you could easily split at the index aftewards in theory

@cuviper cuviper added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 6, 2019
@cuviper
Copy link
Member Author

cuviper commented Jul 6, 2019

Thanks for the review -- sorry I didn't get back to this yet. I can definitely add more tests, and I think partition_in_place -> usize should be feasible too.

cuviper and others added 5 commits July 9, 2019 12:39
`partition_mut()` swaps `&mut T` items in-place to satisfy the
predicate, so all `true` items precede all `false` items. This requires
a `DoubleEndedIterator` so we can search from front and back for items
that need swapping.

`is_partitioned()` checks whether the predicate is already satisfied.
Co-Authored-By: Mazdak Farrokhzad <[email protected]>
@cuviper cuviper added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 9, 2019
@cuviper
Copy link
Member Author

cuviper commented Jul 9, 2019

OK, ready for another review.

// FIXME: should we worry about the count overflowing? The only way to have more than
// `usize::MAX` mutable references is with ZSTs, which aren't useful to partition...

// These closure "factory" functions exist to avoid genericity in `Self`.
Copy link
Member Author

Choose a reason for hiding this comment

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

On this, see also #62429.

@alexcrichton
Copy link
Member

Looks great to me, thanks @cuviper! r=me with the tracking issue numbers filled in

@cuviper
Copy link
Member Author

cuviper commented Jul 9, 2019

Done!

@bors r=alexcrichton

@bors
Copy link
Contributor

bors commented Jul 9, 2019

📌 Commit 7171c83 has been approved by alexcrichton

@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 Jul 9, 2019
Centril added a commit to Centril/rust that referenced this pull request Jul 10, 2019
Add Iterator::partition_in_place() and is_partitioned()

`partition_in_place()` swaps `&mut T` items in-place to satisfy the
predicate, so all `true` items precede all `false` items. This requires
a `DoubleEndedIterator` so we can search from front and back for items
that need swapping.

`is_partitioned()` checks whether the predicate is already satisfied.
bors added a commit that referenced this pull request Jul 10, 2019
Rollup of 5 pull requests

Successful merges:

 - #61853 (Emit warning when trying to use PGO in conjunction with unwinding on …)
 - #62278 (Add Iterator::partition_in_place() and is_partitioned())
 - #62283 (Target::arch can take more than listed options)
 - #62393 (Fix pretty-printing of `$crate` (take 4))
 - #62474 (Prepare for LLVM 9 update)

Failed merges:

r? @ghost
@bors
Copy link
Contributor

bors commented Jul 10, 2019

⌛ Testing commit 7171c83 with merge 0324a2b...

@bors bors merged commit 7171c83 into rust-lang:master Jul 10, 2019
@cuviper cuviper deleted the iter-partition branch April 3, 2020 18:40
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. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants