-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Implement placement-in protocol for BinaryHeap
#39062
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -151,7 +151,7 @@ | |
#![allow(missing_docs)] | ||
#![stable(feature = "rust1", since = "1.0.0")] | ||
|
||
use core::ops::{Deref, DerefMut}; | ||
use core::ops::{Deref, DerefMut, Place, Placer, InPlace}; | ||
use core::iter::{FromIterator, FusedIterator}; | ||
use core::mem::{swap, size_of}; | ||
use core::ptr; | ||
|
@@ -688,6 +688,22 @@ impl<T: Ord> BinaryHeap<T> { | |
} | ||
} | ||
|
||
fn sift_up_ind(&mut self, start: usize, pos: usize) -> usize { | ||
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) { | ||
return hole.pos(); | ||
} | ||
hole.move_to(parent); | ||
} | ||
hole.pos() | ||
} | ||
} | ||
|
||
/// Take an element at `pos` and move it down the heap, | ||
/// while its children are larger. | ||
fn sift_down_range(&mut self, pos: usize, end: usize) { | ||
|
@@ -889,6 +905,19 @@ impl<T: Ord> BinaryHeap<T> { | |
} | ||
} | ||
|
||
impl<T> BinaryHeap<T> | ||
where T: Clone + Ord { | ||
/// kek | ||
#[unstable(feature = "collection_placement", | ||
reason = "placement protocol is subject to change", | ||
issue = "30172")] | ||
pub fn place(&mut self) -> PlaceIn<T> { | ||
PlaceIn { | ||
heap: self, | ||
} | ||
} | ||
} | ||
|
||
/// Hole represents a hole in a slice i.e. an index without valid value | ||
/// (because it was moved from or duplicated). | ||
/// In drop, `Hole` will restore the slice by filling the hole | ||
|
@@ -1189,3 +1218,49 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> { | |
self.extend(iter.into_iter().cloned()); | ||
} | ||
} | ||
|
||
#[unstable(feature = "collection_placement", | ||
reason = "placement protocol is subject to change", | ||
issue = "30172")] | ||
pub struct PlaceIn<'a, T: 'a> | ||
where T: Clone + Ord { | ||
heap: &'a mut BinaryHeap<T>, | ||
} | ||
|
||
#[unstable(feature = "collection_placement", | ||
reason = "placement protocol is subject to change", | ||
issue = "30172")] | ||
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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems… incorrect. Read the comment for |
||
} | ||
} | ||
|
||
#[unstable(feature = "collection_placement", | ||
reason = "placement protocol is subject to change", | ||
issue = "30172")] | ||
impl<'a, T> Placer<T> for PlaceIn<'a, T> | ||
where T: Clone + Ord { | ||
type Place = PlaceIn<'a, T>; | ||
|
||
fn make_place(self) -> Self { | ||
let _ = self.heap.data.place_back().make_place(); | ||
self | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 While this may work in current implementation, because // 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried this initially, but quickly ran into problems, as |
||
} | ||
} | ||
|
||
#[unstable(feature = "collection_placement", | ||
reason = "placement protocol is subject to change", | ||
issue = "30172")] | ||
impl<'a, T> InPlace<T> for PlaceIn<'a, T> | ||
where T: Clone + Ord { | ||
type Owner = &'a T; | ||
|
||
unsafe fn finalize(self) -> &'a T { | ||
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] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
} | ||
} |
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.
You can simply adjust the
sift_up
to return the index, since its a private implementation detail and will also avoid the code duplication.