-
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
collections: Make BinaryHeap panic safe in sift_up / sift_down #25856
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @brson (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. 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. |
I prototyped this using a general scope guard, but this Hole representation turned out to be nice. LLVM needs to be on our side here and see that the removed element's Edited: Moved useful info from this comment into the merge message itself (above) |
Using only unchecked indexing in |
|
||
impl<'a, T> Hole<'a, T> { | ||
/// Create a new Hole at index `pos`. | ||
pub fn new(data: &'a mut [T], pos: usize) -> Self { |
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.
Could the pub
be dropped from these functions? (Hole
isn't exposed so they shouldn't need to be exposed either)
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.
It makes the code more portable, though. e.g. we can happily move this to a module without worrying.
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.
It came out with pub, I think pub
is natural as soon as the methods are intended to be called from outside the struct itself. I know our privacy doesn't work that way, but it does once the code grows and yes you move it out to a module. I'm fine either way but I prefer pub.
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.
Idiomatically code in the rest of the standard library does not do this, so let's stick to existing conventions. We can add pub
if necessary at a later date, but code should be as conservative as possible in exports today.
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.
ok that's fine
Thanks. I'll add a test that makes sure no destructors were called right after catching the panic, before I inspect the data further. That should cover it (and fails on old version of BinaryHeap). |
ptr::write(&mut self.data[pos], x); | ||
pos = parent; | ||
while hole.pos() > start { | ||
let parent = (hole.pos() - 1) >> 1; |
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.
Surely LLVM can convert the much more semantically clear /2
to this?
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'll fix it. Haven't really looked at changing anything besides what's needed, though.
This looks great! |
PR updated. Everything is addressed, removed pub. The test checks for number of drop calls now (old binary heap used to drop 1 on panic), but it could still have tracked drops in even more detail. |
Use a struct called Hole that keeps track of an invalid location in the vector and fills the hole on drop. I include a run-pass test that the current BinaryHeap fails, and the new one passes. Fixes rust-lang#25842
wait, oh I totally thought I had spotted a bug and wondered how that could have slipped my tests, but no, it's fine. Pushed an update with one scope less that I didn't need, so the diff for sift_down is easier to read. |
@bors r+ Sweet! |
📌 Commit 5249cbb has been approved by |
collections: Make BinaryHeap panic safe in sift_up / sift_down Use a struct called Hole that keeps track of an invalid location in the vector and fills the hole on drop. I include a run-pass test that the current BinaryHeap fails, and the new one passes. NOTE: The BinaryHeap will still be inconsistent after a comparison fails. It will not have the heap property. What we fix is just that elements will be valid values. This is actually a performance win -- the new code does not bother to write in `zeroed()` values in the holes, it just leaves them as they were. Net result is something like a 5% decrease in runtime for `BinaryHeap::from_vec`. This can be further improved by using unchecked indexing (I confirmed it makes a difference, not a surprise with the non-sequential access going on), but let's leave that for another PR. Safety first 😉 Fixes #25842
Nice work @bluss! |
triage: beta-accepted |
collections: Make BinaryHeap panic safe in sift_up / sift_down
Use a struct called Hole that keeps track of an invalid location
in the vector and fills the hole on drop.
I include a run-pass test that the current BinaryHeap fails, and the new
one passes.
NOTE: The BinaryHeap will still be inconsistent after a comparison fails. It will
not have the heap property. What we fix is just that elements will be valid
values.
This is actually a performance win -- the new code does not bother to write in
zeroed()
values in the holes, it just leaves them as they were.
Net result is something like a 5% decrease in runtime for
BinaryHeap::from_vec
. Thiscan be further improved by using unchecked indexing (I confirmed it makes a difference,
not a surprise with the non-sequential access going on), but let's leave that for another PR.
Safety first 😉
Fixes #25842