@@ -443,22 +443,58 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
443443 pub fn retain < F > ( & mut self , mut f : F )
444444 where F : FnMut ( & mut T ) -> bool
445445 {
446- let len = self . len ( ) ;
447- let mut del = 0 ;
448- {
449- let v = & mut * * self ;
450-
451- for i in 0 ..len {
452- if !f ( & mut v[ i] ) {
453- del += 1 ;
454- } else if del > 0 {
455- v. swap ( i - del, i) ;
446+ // Check the implementation of
447+ // https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain
448+ // for safety arguments (especially regarding panics in f and when
449+ // dropping elements). Implementation closely mirrored here.
450+
451+ let original_len = self . len ( ) ;
452+ unsafe { self . set_len ( 0 ) } ;
453+
454+ struct BackshiftOnDrop < ' a , T , const CAP : usize > {
455+ v : & ' a mut ArrayVec < T , CAP > ,
456+ processed_len : usize ,
457+ deleted_cnt : usize ,
458+ original_len : usize ,
459+ }
460+
461+ impl < T , const CAP : usize > Drop for BackshiftOnDrop < ' _ , T , CAP > {
462+ fn drop ( & mut self ) {
463+ if self . deleted_cnt > 0 {
464+ unsafe {
465+ ptr:: copy (
466+ self . v . as_ptr ( ) . add ( self . processed_len ) ,
467+ self . v . as_mut_ptr ( ) . add ( self . processed_len - self . deleted_cnt ) ,
468+ self . original_len - self . processed_len
469+ ) ;
470+ }
471+ }
472+ unsafe {
473+ self . v . set_len ( self . original_len - self . deleted_cnt ) ;
456474 }
457475 }
458476 }
459- if del > 0 {
460- self . drain ( len - del..) ;
477+
478+ let mut g = BackshiftOnDrop { v : self , processed_len : 0 , deleted_cnt : 0 , original_len } ;
479+
480+ while g. processed_len < original_len {
481+ let cur = unsafe { g. v . as_mut_ptr ( ) . add ( g. processed_len ) } ;
482+ if !f ( unsafe { & mut * cur } ) {
483+ g. processed_len += 1 ;
484+ g. deleted_cnt += 1 ;
485+ unsafe { ptr:: drop_in_place ( cur) } ;
486+ continue ;
487+ }
488+ if g. deleted_cnt > 0 {
489+ unsafe {
490+ let hole_slot = g. v . as_mut_ptr ( ) . add ( g. processed_len - g. deleted_cnt ) ;
491+ ptr:: copy_nonoverlapping ( cur, hole_slot, 1 ) ;
492+ }
493+ }
494+ g. processed_len += 1 ;
461495 }
496+
497+ drop ( g) ;
462498 }
463499
464500 /// Set the vector’s length without dropping or moving out elements
0 commit comments