@@ -443,22 +443,58 @@ impl<T, const CAP: usize> ArrayVec<T, CAP> {
443
443
pub fn retain < F > ( & mut self , mut f : F )
444
444
where F : FnMut ( & mut T ) -> bool
445
445
{
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 , A : Array > {
455
+ v : & ' a mut ArrayVec < A > ,
456
+ processed_len : usize ,
457
+ deleted_cnt : usize ,
458
+ original_len : usize ,
459
+ }
460
+
461
+ impl < A : Array > Drop for BackshiftOnDrop < ' _ , A > {
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 ) ;
456
474
}
457
475
}
458
476
}
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 { & mut * g. v . as_mut_ptr ( ) . add ( g. processed_len ) } ;
482
+ if !f ( 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 ;
461
495
}
496
+
497
+ drop ( g) ;
462
498
}
463
499
464
500
/// Set the vector’s length without dropping or moving out elements
0 commit comments