@@ -468,22 +468,58 @@ impl<A: Array> ArrayVec<A> {
468
468
pub fn retain < F > ( & mut self , mut f : F )
469
469
where F : FnMut ( & mut A :: Item ) -> bool
470
470
{
471
- let len = self . len ( ) ;
472
- let mut del = 0 ;
473
- {
474
- let v = & mut * * self ;
475
-
476
- for i in 0 ..len {
477
- if !f ( & mut v[ i] ) {
478
- del += 1 ;
479
- } else if del > 0 {
480
- v. swap ( i - del, i) ;
471
+ // Check the implementation of
472
+ // https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain
473
+ // for safety arguments (especially regarding panics in f and when
474
+ // dropping elements). Implementation closely mirrored here.
475
+
476
+ let original_len = self . len ( ) ;
477
+ unsafe { self . set_len ( 0 ) } ;
478
+
479
+ struct BackshiftOnDrop < ' a , A : Array > {
480
+ v : & ' a mut ArrayVec < A > ,
481
+ processed_len : usize ,
482
+ deleted_cnt : usize ,
483
+ original_len : usize ,
484
+ }
485
+
486
+ impl < A : Array > Drop for BackshiftOnDrop < ' _ , A > {
487
+ fn drop ( & mut self ) {
488
+ if self . deleted_cnt > 0 {
489
+ unsafe {
490
+ ptr:: copy (
491
+ self . v . as_ptr ( ) . add ( self . processed_len ) ,
492
+ self . v . as_mut_ptr ( ) . add ( self . processed_len - self . deleted_cnt ) ,
493
+ self . original_len - self . processed_len
494
+ ) ;
495
+ }
496
+ }
497
+ unsafe {
498
+ self . v . set_len ( self . original_len - self . deleted_cnt ) ;
481
499
}
482
500
}
483
501
}
484
- if del > 0 {
485
- self . drain ( len - del..) ;
502
+
503
+ let mut g = BackshiftOnDrop { v : self , processed_len : 0 , deleted_cnt : 0 , original_len } ;
504
+
505
+ while g. processed_len < original_len {
506
+ let cur = unsafe { & mut * g. v . as_mut_ptr ( ) . add ( g. processed_len ) } ;
507
+ if !f ( cur) {
508
+ g. processed_len += 1 ;
509
+ g. deleted_cnt += 1 ;
510
+ unsafe { ptr:: drop_in_place ( cur) } ;
511
+ continue ;
512
+ }
513
+ if g. deleted_cnt > 0 {
514
+ unsafe {
515
+ let hole_slot = g. v . as_mut_ptr ( ) . add ( g. processed_len - g. deleted_cnt ) ;
516
+ ptr:: copy_nonoverlapping ( cur, hole_slot, 1 ) ;
517
+ }
518
+ }
519
+ g. processed_len += 1 ;
486
520
}
521
+
522
+ drop ( g) ;
487
523
}
488
524
489
525
/// Set the vector’s length without dropping or moving out elements
0 commit comments