From 345c6b4970337361847681f9ebf16f835fac3a52 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Fri, 19 Feb 2021 23:20:39 +0100 Subject: [PATCH 1/3] Mirror optimization of std::Vec::retain (rust-lang/rust#81126) --- src/arrayvec.rs | 60 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index f00efeb..dc2b766 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -443,22 +443,58 @@ impl ArrayVec { pub fn retain(&mut self, mut f: F) where F: FnMut(&mut T) -> bool { - let len = self.len(); - let mut del = 0; - { - let v = &mut **self; - - for i in 0..len { - if !f(&mut v[i]) { - del += 1; - } else if del > 0 { - v.swap(i - del, i); + // Check the implementation of + // https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain + // for safety arguments (especially regarding panics in f and when + // dropping elements). Implementation closely mirrored here. + + let original_len = self.len(); + unsafe { self.set_len(0) }; + + struct BackshiftOnDrop<'a, A: Array> { + v: &'a mut ArrayVec, + processed_len: usize, + deleted_cnt: usize, + original_len: usize, + } + + impl Drop for BackshiftOnDrop<'_, A> { + fn drop(&mut self) { + if self.deleted_cnt > 0 { + unsafe { + ptr::copy( + self.v.as_ptr().add(self.processed_len), + self.v.as_mut_ptr().add(self.processed_len - self.deleted_cnt), + self.original_len - self.processed_len + ); + } + } + unsafe { + self.v.set_len(self.original_len - self.deleted_cnt); } } } - if del > 0 { - self.drain(len - del..); + + let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; + + while g.processed_len < original_len { + let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; + if !f(cur) { + g.processed_len += 1; + g.deleted_cnt += 1; + unsafe { ptr::drop_in_place(cur) }; + continue; + } + if g.deleted_cnt > 0 { + unsafe { + let hole_slot = g.v.as_mut_ptr().add(g.processed_len - g.deleted_cnt); + ptr::copy_nonoverlapping(cur, hole_slot, 1); + } + } + g.processed_len += 1; } + + drop(g); } /// Set the vector’s length without dropping or moving out elements From c094906a1326330c0cb0aaa10eb50dde412f116b Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Mon, 22 Feb 2021 18:43:17 +0100 Subject: [PATCH 2/3] Fix mutable reborrow Co-authored-by: bluss --- src/arrayvec.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index dc2b766..541e0c9 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -478,8 +478,8 @@ impl ArrayVec { let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; while g.processed_len < original_len { - let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; - if !f(cur) { + let cur = unsafe { g.v.as_mut_ptr().add(g.processed_len) }; + if !f(unsafe { &mut *cur }) { g.processed_len += 1; g.deleted_cnt += 1; unsafe { ptr::drop_in_place(cur) }; From b82a6d497751995bd09d61f52a13e903fd047c94 Mon Sep 17 00:00:00 2001 From: bluss Date: Mon, 29 Mar 2021 17:43:01 +0200 Subject: [PATCH 3/3] FIX: Update .retain() optimization for const generics --- src/arrayvec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 541e0c9..3c18df4 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -451,14 +451,14 @@ impl ArrayVec { let original_len = self.len(); unsafe { self.set_len(0) }; - struct BackshiftOnDrop<'a, A: Array> { - v: &'a mut ArrayVec, + struct BackshiftOnDrop<'a, T, const CAP: usize> { + v: &'a mut ArrayVec, processed_len: usize, deleted_cnt: usize, original_len: usize, } - impl Drop for BackshiftOnDrop<'_, A> { + impl Drop for BackshiftOnDrop<'_, T, CAP> { fn drop(&mut self) { if self.deleted_cnt > 0 { unsafe {