@@ -1319,6 +1319,127 @@ impl<'bump, T: 'bump> Vec<'bump, T> {
1319
1319
self . drain_filter ( |x| !f ( x) ) ;
1320
1320
}
1321
1321
1322
+ /// Retains only the elements specified by the predicate, passing a mutable reference to it.
1323
+ ///
1324
+ /// In other words, remove all elements `e` such that `f(&mut e)` returns `false`.
1325
+ /// This method operates in place, visiting each element exactly once in the
1326
+ /// original order, and preserves the order of the retained elements.
1327
+ ///
1328
+ /// # Examples
1329
+ ///
1330
+ /// ```
1331
+ /// let mut vec = vec![1, 2, 3, 4];
1332
+ /// vec.retain_mut(|x| if *x <= 3 {
1333
+ /// *x += 1;
1334
+ /// true
1335
+ /// } else {
1336
+ /// false
1337
+ /// });
1338
+ /// assert_eq!(vec, [2, 3, 4]);
1339
+ /// ```
1340
+ // The implementation is based on the [`std::vec::Vec::retain_mut`].
1341
+ //
1342
+ // Allowing the following clippy rules just to make the code same as the original implementation.
1343
+ #[ expect( clippy:: items_after_statements, clippy:: redundant_else) ]
1344
+ pub fn retain_mut < F > ( & mut self , mut f : F )
1345
+ where
1346
+ F : FnMut ( & mut T ) -> bool ,
1347
+ {
1348
+ let original_len = self . len ( ) ;
1349
+
1350
+ if original_len == 0 {
1351
+ // Empty case: explicit return allows better optimization, vs letting compiler infer it
1352
+ return ;
1353
+ }
1354
+
1355
+ // Avoid double drop if the drop guard is not executed,
1356
+ // since we may make some holes during the process.
1357
+ unsafe { self . set_len ( 0 ) } ;
1358
+
1359
+ // Vec: [Kept, Kept, Hole, Hole, Hole, Hole, Unchecked, Unchecked]
1360
+ // |<- processed len ->| ^- next to check
1361
+ // |<- deleted cnt ->|
1362
+ // |<- original_len ->|
1363
+ // Kept: Elements which predicate returns true on.
1364
+ // Hole: Moved or dropped element slot.
1365
+ // Unchecked: Unchecked valid elements.
1366
+ //
1367
+ // This drop guard will be invoked when predicate or `drop` of element panicked.
1368
+ // It shifts unchecked elements to cover holes and `set_len` to the correct length.
1369
+ // In cases when predicate and `drop` never panick, it will be optimized out.
1370
+ struct BackshiftOnDrop < ' bump , ' a , T > {
1371
+ v : & ' a mut Vec < ' bump , T > ,
1372
+ processed_len : usize ,
1373
+ deleted_cnt : usize ,
1374
+ original_len : usize ,
1375
+ }
1376
+
1377
+ impl < T > Drop for BackshiftOnDrop < ' _ , ' _ , T > {
1378
+ fn drop ( & mut self ) {
1379
+ if self . deleted_cnt > 0 {
1380
+ // SAFETY: Trailing unchecked items must be valid since we never touch them.
1381
+ unsafe {
1382
+ ptr:: copy (
1383
+ self . v . as_ptr ( ) . add ( self . processed_len ) ,
1384
+ self . v . as_mut_ptr ( ) . add ( self . processed_len - self . deleted_cnt ) ,
1385
+ self . original_len - self . processed_len ,
1386
+ ) ;
1387
+ }
1388
+ }
1389
+ // SAFETY: After filling holes, all items are in contiguous memory.
1390
+ unsafe {
1391
+ self . v . set_len ( self . original_len - self . deleted_cnt ) ;
1392
+ }
1393
+ }
1394
+ }
1395
+
1396
+ let mut g = BackshiftOnDrop { v : self , processed_len : 0 , deleted_cnt : 0 , original_len } ;
1397
+
1398
+ fn process_loop < F , T , const DELETED : bool > (
1399
+ original_len : usize ,
1400
+ f : & mut F ,
1401
+ g : & mut BackshiftOnDrop < ' _ , ' _ , T > ,
1402
+ ) where
1403
+ F : FnMut ( & mut T ) -> bool ,
1404
+ {
1405
+ while g. processed_len != original_len {
1406
+ // SAFETY: Unchecked element must be valid.
1407
+ let cur = unsafe { & mut * g. v . as_mut_ptr ( ) . add ( g. processed_len ) } ;
1408
+ if !f ( cur) {
1409
+ // Advance early to avoid double drop if `drop_in_place` panicked.
1410
+ g. processed_len += 1 ;
1411
+ g. deleted_cnt += 1 ;
1412
+ // SAFETY: We never touch this element again after dropped.
1413
+ unsafe { ptr:: drop_in_place ( cur) } ;
1414
+ // We already advanced the counter.
1415
+ if DELETED {
1416
+ continue ;
1417
+ } else {
1418
+ break ;
1419
+ }
1420
+ }
1421
+ if DELETED {
1422
+ // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element.
1423
+ // We use copy for move, and never touch this element again.
1424
+ unsafe {
1425
+ let hole_slot = g. v . as_mut_ptr ( ) . add ( g. processed_len - g. deleted_cnt ) ;
1426
+ ptr:: copy_nonoverlapping ( cur, hole_slot, 1 ) ;
1427
+ }
1428
+ }
1429
+ g. processed_len += 1 ;
1430
+ }
1431
+ }
1432
+
1433
+ // Stage 1: Nothing was deleted.
1434
+ process_loop :: < F , T , false > ( original_len, & mut f, & mut g) ;
1435
+
1436
+ // Stage 2: Some elements were deleted.
1437
+ process_loop :: < F , T , true > ( original_len, & mut f, & mut g) ;
1438
+
1439
+ // All item are processed. This can be optimized to `set_len` by LLVM.
1440
+ drop ( g) ;
1441
+ }
1442
+
1322
1443
/// Creates an iterator that removes the elements in the vector
1323
1444
/// for which the predicate returns `true` and yields the removed items.
1324
1445
///
0 commit comments