@@ -4,9 +4,10 @@ use core::borrow::Borrow;
4
4
use core:: fmt;
5
5
use core:: hash:: { BuildHasher , Hash } ;
6
6
use core:: iter:: { Chain , FromIterator , FusedIterator } ;
7
+ use core:: mem;
7
8
use core:: ops:: { BitAnd , BitOr , BitXor , Sub } ;
8
9
9
- use super :: map:: { self , DefaultHashBuilder , HashMap , Keys } ;
10
+ use super :: map:: { self , ConsumeAllOnDrop , DefaultHashBuilder , DrainFilterInner , HashMap , Keys } ;
10
11
11
12
// Future Optimization (FIXME!)
12
13
// =============================
@@ -285,6 +286,39 @@ impl<T, S> HashSet<T, S> {
285
286
self . map . retain ( |k, _| f ( k) ) ;
286
287
}
287
288
289
+ /// Drains elements which are false under the given predicate,
290
+ /// and returns an iterator over the removed items.
291
+ ///
292
+ /// In other words, move all elements `e` such that `f(&e)` returns `false` out
293
+ /// into another iterator.
294
+ ///
295
+ /// When the returned DrainedFilter is dropped, the elements that don't satisfy
296
+ /// the predicate are dropped from the set.
297
+ ///
298
+ /// # Examples
299
+ ///
300
+ /// ```
301
+ /// use hashbrown::HashSet;
302
+ ///
303
+ /// let mut set: HashSet<i32> = (0..8).collect();
304
+ /// let drained = set.drain_filter(|&k| k % 2 == 0);
305
+ /// assert_eq!(drained.count(), 4);
306
+ /// assert_eq!(set.len(), 4);
307
+ /// ```
308
+ #[ cfg_attr( feature = "inline-more" , inline) ]
309
+ pub fn drain_filter < F > ( & mut self , f : F ) -> DrainFilter < ' _ , T , F >
310
+ where
311
+ F : FnMut ( & T ) -> bool ,
312
+ {
313
+ DrainFilter {
314
+ f,
315
+ inner : DrainFilterInner {
316
+ iter : unsafe { self . map . table . iter ( ) } ,
317
+ table : & mut self . map . table ,
318
+ } ,
319
+ }
320
+ }
321
+
288
322
/// Clears the set, removing all values.
289
323
///
290
324
/// # Examples
@@ -1185,6 +1219,21 @@ pub struct Drain<'a, K> {
1185
1219
iter : map:: Drain < ' a , K , ( ) > ,
1186
1220
}
1187
1221
1222
+ /// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`.
1223
+ ///
1224
+ /// This `struct` is created by the [`drain_filter`] method on [`HashSet`]. See its
1225
+ /// documentation for more.
1226
+ ///
1227
+ /// [`drain_filter`]: struct.HashSet.html#method.drain_filter
1228
+ /// [`HashSet`]: struct.HashSet.html
1229
+ pub struct DrainFilter < ' a , K , F >
1230
+ where
1231
+ F : FnMut ( & K ) -> bool ,
1232
+ {
1233
+ f : F ,
1234
+ inner : DrainFilterInner < ' a , K , ( ) > ,
1235
+ }
1236
+
1188
1237
/// A lazy iterator producing elements in the intersection of `HashSet`s.
1189
1238
///
1190
1239
/// This `struct` is created by the [`intersection`] method on [`HashSet`].
@@ -1365,6 +1414,34 @@ impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
1365
1414
}
1366
1415
}
1367
1416
1417
+ impl < ' a , K , F > Drop for DrainFilter < ' a , K , F >
1418
+ where
1419
+ F : FnMut ( & K ) -> bool ,
1420
+ {
1421
+ #[ cfg_attr( feature = "inline-more" , inline) ]
1422
+ fn drop ( & mut self ) {
1423
+ while let Some ( item) = self . next ( ) {
1424
+ let guard = ConsumeAllOnDrop ( self ) ;
1425
+ drop ( item) ;
1426
+ mem:: forget ( guard) ;
1427
+ }
1428
+ }
1429
+ }
1430
+
1431
+ impl < K , F > Iterator for DrainFilter < ' _ , K , F >
1432
+ where
1433
+ F : FnMut ( & K ) -> bool ,
1434
+ {
1435
+ type Item = K ;
1436
+
1437
+ #[ cfg_attr( feature = "inline-more" , inline) ]
1438
+ fn next ( & mut self ) -> Option < Self :: Item > {
1439
+ let f = & mut self . f ;
1440
+ let ( k, _) = self . inner . next ( & mut |k, _| f ( k) ) ?;
1441
+ Some ( k)
1442
+ }
1443
+ }
1444
+
1368
1445
impl < T , S > Clone for Intersection < ' _ , T , S > {
1369
1446
#[ cfg_attr( feature = "inline-more" , inline) ]
1370
1447
fn clone ( & self ) -> Self {
@@ -1973,4 +2050,21 @@ mod test_set {
1973
2050
assert ! ( set. contains( & 4 ) ) ;
1974
2051
assert ! ( set. contains( & 6 ) ) ;
1975
2052
}
2053
+
2054
+ #[ test]
2055
+ fn test_drain_filter ( ) {
2056
+ {
2057
+ let mut set: HashSet < i32 > = ( 0 ..8 ) . collect ( ) ;
2058
+ let drained = set. drain_filter ( |& k| k % 2 == 0 ) ;
2059
+ let mut out = drained. collect :: < Vec < _ > > ( ) ;
2060
+ out. sort_unstable ( ) ;
2061
+ assert_eq ! ( vec![ 1 , 3 , 5 , 7 ] , out) ;
2062
+ assert_eq ! ( set. len( ) , 4 ) ;
2063
+ }
2064
+ {
2065
+ let mut set: HashSet < i32 > = ( 0 ..8 ) . collect ( ) ;
2066
+ drop ( set. drain_filter ( |& k| k % 2 == 0 ) ) ;
2067
+ assert_eq ! ( set. len( ) , 4 , "Removes non-matching items on drop" ) ;
2068
+ }
2069
+ }
1976
2070
}
0 commit comments