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

Implement placement-in protocol for BinaryHeap #39062

Merged
merged 2 commits into from
Jan 20, 2017

Conversation

martinhath
Copy link
Contributor

Related to #30172, and loosley based on #38551.

At the moment, this PR is in a pretty rough state, but I wanted to get some feedback to see if I'm going in the right direction.

I hope the Mentor label of #30172 is still applicable, even though it's a year old 😄

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.

Copy link
Member

@nagisa nagisa left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! And obviously the mentorship tag still applies :) If you have any questions, drop by on any of the IRC channels (#rust-internals, #rust-libs, etc). My nick there is same as here.

impl<'a, T> Place<T> for PlaceIn<'a, T>
where T: Clone + Ord {
fn pointer(&mut self) -> *mut T {
self.heap.data.place_back().pointer()
Copy link
Member

Choose a reason for hiding this comment

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

This seems… incorrect. Read the comment for Placer.


fn make_place(self) -> Self {
let _ = self.heap.data.place_back().make_place();
self
Copy link
Member

Choose a reason for hiding this comment

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

Implementation of this is going in the right direction but not quite there yet.

Probably the most notable issue here is that the Place that you create in the underlying vector gets immediatelly dropped, after which you are not allowed to put anything into the place in question anymore.

While this may work in current implementation, because PlaceBack for Vec has no Drop defined, consider what would happen if it had one:

// self.heap.data here is just big enough that a call to make_place would resize the vector.
let place = self.heap.data.place_back().make_place(); // resizes vector
drop(place); // resizes the vector back to the original size if was implemented weirdly
// now the placement protocol asks for a pointer to put data in
self.heap.data.place_back().pointer() // returns a pointer out of bounds!

This implementation therefore does not follow the placement protocol.

What ought be done instead is a new structure such as this (I think, feel free to explore alternative designs! generics omitted for brevity):

struct BinaryHeapPlace {
    heap: &mut BinaryHeap
    place: vec::PlaceBack
}

and then use the place in this structure to produce the pointer and also call the finalize on.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried this initially, but quickly ran into problems, as vec::PlaceBack borrows the vec its created from. Might there be some clever way of bypassing this problem? I would like to reuse vec::PlaceBack somehow, as it does exactly what I try to do, and just throw in the heap.sift_up in InPlace::finalize, but it seems to be hard wrt. borrowing and aliasing stuff.

let len = self.heap.len();
let _ = self.heap.data.place_back().finalize();
let i = self.heap.sift_up_ind(0, len);
&mut self.heap.data[i]
Copy link
Member

Choose a reason for hiding this comment

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

Returning an immutable reference seems sensible, but you needn’t to do a &mut self.heap.data[i] here; while return value of finalize cannot be reused, you can still avoid a bounds check by simply doing self.heap.get_unchecked(i), as the index is guaranteed to be in bounds.

@@ -688,6 +688,22 @@ impl<T: Ord> BinaryHeap<T> {
}
}

fn sift_up_ind(&mut self, start: usize, pos: usize) -> usize {
Copy link
Member

Choose a reason for hiding this comment

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

You can simply adjust the sift_up to return the index, since its a private implementation detail and will also avoid the code duplication.

Copy link
Member

@nagisa nagisa left a comment

Choose a reason for hiding this comment

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

Looks nice and clean.

unsafe {
// Take out the value at `pos` and create a hole.
let mut hole = Hole::new(&mut self.data, pos);

while hole.pos() > start {
let parent = (hole.pos() - 1) / 2;
if hole.element() <= hole.get(parent) {
break;
return hole.pos();
Copy link
Member

Choose a reason for hiding this comment

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

nit: why not leave break here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ops, I think I'll revert that 😄

@alexcrichton
Copy link
Member

r? @nagisa

(who looks like is definitely still willing to mentor!)

@alexcrichton
Copy link
Member

Er, @nagisa feel free to ping/cc me when this is ready and I'll r=you

@nagisa
Copy link
Member

nagisa commented Jan 17, 2017

This impl looks great to me. Certainly r+ from me.

@alexcrichton
Copy link
Member

@bors: r=nagisa

@bors
Copy link
Contributor

bors commented Jan 17, 2017

📌 Commit 90fbe15 has been approved by nagisa

@alexcrichton alexcrichton added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Jan 19, 2017
@bors
Copy link
Contributor

bors commented Jan 20, 2017

⌛ Testing commit 90fbe15 with merge a52da95...

bors added a commit that referenced this pull request Jan 20, 2017
Implement placement-in protocol for `BinaryHeap`

Related to #30172, and loosley based on #38551.

At the moment, this PR is in a pretty rough state, but I wanted to get some feedback to see if I'm going in the right direction.

I hope the Mentor label of #30172 is still applicable, even though it's a year old 😄
@bors
Copy link
Contributor

bors commented Jan 20, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: nagisa
Pushing a52da95 to master...

@bors bors merged commit 90fbe15 into rust-lang:master Jan 20, 2017
bors added a commit that referenced this pull request Jan 20, 2017
bors added a commit that referenced this pull request Jan 21, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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.

5 participants