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
|
where
|
||||||
F: FnMut(&T) -> bool,
|
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;
|
let mut i = 0;
|
||||||
self.data.retain(|e| {
|
guard.heap.data.retain(|e| {
|
||||||
let keep = f(e);
|
let keep = f(e);
|
||||||
if !keep && i < first_removed {
|
if !keep && i < guard.first_removed {
|
||||||
first_removed = i;
|
guard.first_removed = i;
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
keep
|
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
|
// old binaryheap failed this test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user