Optimize unnecessary check in Vec::retain

Co-authored-by: oxalica <oxalicc@pm.me>
This commit is contained in:
TennyZhuang 2021-08-16 09:52:15 +08:00
parent 20e14e4030
commit 3839ca9953

View File

@ -1485,7 +1485,15 @@ fn drop(&mut self) {
let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len };
while g.processed_len < original_len {
// process_one return a bool indicates whether the processing element should be retained.
#[inline(always)]
fn process_one<F, T, A: Allocator, const DELETED: bool>(
f: &mut F,
g: &mut BackshiftOnDrop<'_, T, A>,
) -> bool
where
F: FnMut(&T) -> bool,
{
// SAFETY: Unchecked element must be valid.
let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) };
if !f(cur) {
@ -1495,9 +1503,9 @@ fn drop(&mut self) {
// SAFETY: We never touch this element again after dropped.
unsafe { ptr::drop_in_place(cur) };
// We already advanced the counter.
continue;
return false;
}
if g.deleted_cnt > 0 {
if DELETED {
// SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element.
// We use copy for move, and never touch this element again.
unsafe {
@ -1506,6 +1514,19 @@ fn drop(&mut self) {
}
}
g.processed_len += 1;
return true;
}
// Stage 1: Nothing was deleted.
while g.processed_len != original_len {
if !process_one::<F, T, A, false>(&mut f, &mut g) {
break;
}
}
// Stage 2: Some elements were deleted.
while g.processed_len != original_len {
process_one::<F, T, A, true>(&mut f, &mut g);
}
// All item are processed. This can be optimized to `set_len` by LLVM.