mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Rebuild BinaryHeap on unwind from retain
This commit is contained in:
parent
0d3eaa848c
commit
fa2ff4d7e5
@ -851,18 +851,30 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
where
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
let mut first_removed = self.len();
|
||||
struct RebuildOnDrop<'a, T: Ord> {
|
||||
heap: &'a mut BinaryHeap<T>,
|
||||
first_removed: usize,
|
||||
}
|
||||
|
||||
let mut guard = RebuildOnDrop { first_removed: self.len(), heap: self };
|
||||
|
||||
let mut i = 0;
|
||||
self.data.retain(|e| {
|
||||
guard.heap.data.retain(|e| {
|
||||
let keep = f(e);
|
||||
if !keep && i < first_removed {
|
||||
first_removed = i;
|
||||
if !keep && i < guard.first_removed {
|
||||
guard.first_removed = i;
|
||||
}
|
||||
i += 1;
|
||||
keep
|
||||
});
|
||||
// data[0..first_removed] is untouched, so we only need to rebuild the tail:
|
||||
self.rebuild_tail(first_removed);
|
||||
|
||||
impl<'a, T: Ord> Drop for RebuildOnDrop<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
// data[..first_removed] is untouched, so we only need to
|
||||
// rebuild the tail:
|
||||
self.heap.rebuild_tail(self.first_removed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,7 +488,9 @@ fn test_retain_catch_unwind() {
|
||||
});
|
||||
}));
|
||||
|
||||
assert_eq!(heap.into_vec(), [1, 2]); // BAD!!
|
||||
// Naively this would be [1, 2] (an invalid heap) if BinaryHeap delegates to
|
||||
// Vec's retain impl and then does not rebuild the heap after that unwinds.
|
||||
assert_eq!(heap.into_vec(), [2, 1]);
|
||||
}
|
||||
|
||||
// old binaryheap failed this test
|
||||
|
Loading…
Reference in New Issue
Block a user