@@ -1371,21 +1371,78 @@ impl<T, A: Allocator> Vec<T, A> {
13711371 F : FnMut ( & T ) -> bool ,
13721372 {
13731373 let len = self . len ( ) ;
1374- let mut del = 0 ;
1375- {
1376- let v = & mut * * self ;
1377-
1378- for i in 0 ..len {
1379- if !f ( & v[ i] ) {
1380- del += 1 ;
1381- } else if del > 0 {
1382- v. swap ( i - del, i) ;
1374+ // Avoid double drop if the drop guard is not executed,
1375+ // since we may make some holes during the process.
1376+ unsafe { self . set_len ( 0 ) } ;
1377+
1378+ // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked]
1379+ // |<- processed len ->| ^- next to check
1380+ // |<- deleted cnt ->|
1381+ // |<- original_len ->|
1382+ // Kept: Elements which predicate returns true on.
1383+ // Hole: Moved or dropped element slot.
1384+ // Unchecked: Unchecked valid elements.
1385+ //
1386+ // This drop guard will be invoked when predicate or `drop` of element panicked.
1387+ // It shifts unchecked elements to cover holes and `set_len` to the correct length.
1388+ // In cases when predicate and `drop` never panick, it will be optimized out.
1389+ struct BackshiftOnDrop < ' a , T , A : Allocator > {
1390+ v : & ' a mut Vec < T , A > ,
1391+ processed_len : usize ,
1392+ deleted_cnt : usize ,
1393+ original_len : usize ,
1394+ }
1395+
1396+ impl < T , A : Allocator > Drop for BackshiftOnDrop < ' _ , T , A > {
1397+ fn drop ( & mut self ) {
1398+ if self . deleted_cnt > 0 {
1399+ // SAFETY: Fill the hole of dropped or moved
1400+ unsafe {
1401+ ptr:: copy (
1402+ self . v . as_ptr ( ) . offset ( self . processed_len as isize ) ,
1403+ self . v
1404+ . as_mut_ptr ( )
1405+ . offset ( self . processed_len as isize - self . deleted_cnt as isize ) ,
1406+ self . original_len - self . processed_len ,
1407+ ) ;
1408+ self . v . set_len ( self . original_len - self . deleted_cnt ) ;
1409+ }
13831410 }
13841411 }
13851412 }
1386- if del > 0 {
1387- self . truncate ( len - del) ;
1413+
1414+ let mut guard = BackshiftOnDrop {
1415+ v : self ,
1416+ processed_len : 0 ,
1417+ deleted_cnt : 0 ,
1418+ original_len : len,
1419+ } ;
1420+
1421+ let mut del = 0usize ;
1422+ for i in 0 ..len {
1423+ // SAFETY: Unchecked element must be valid.
1424+ let cur = unsafe { & mut * guard. v . as_mut_ptr ( ) . offset ( i as isize ) } ;
1425+ if !f ( cur) {
1426+ del += 1 ;
1427+ // Advance early to avoid double drop if `drop_in_place` panicked.
1428+ guard. processed_len = i + 1 ;
1429+ guard. deleted_cnt = del;
1430+ // SAFETY: We never touch this element again after dropped.
1431+ unsafe { ptr:: drop_in_place ( cur) } ;
1432+ } else if del > 0 {
1433+ // SAFETY: `del` > 0 so the hole slot must not overlap with current element.
1434+ // We use copy for move, and never touch this element again.
1435+ unsafe {
1436+ let hole_slot = guard. v . as_mut_ptr ( ) . offset ( i as isize - del as isize ) ;
1437+ ptr:: copy_nonoverlapping ( cur, hole_slot, 1 ) ;
1438+ }
1439+ guard. processed_len = i + 1 ;
1440+ }
13881441 }
1442+
1443+ // All holes are at the end now. Simply cut them out.
1444+ unsafe { guard. v . set_len ( len - del) } ;
1445+ mem:: forget ( guard) ;
13891446 }
13901447
13911448 /// Removes all but the first of consecutive elements in the vector that resolve to the same
0 commit comments