@@ -497,6 +497,50 @@ impl<K, V, S> HashMap<K, V, S> {
497497 Drain { base : self . base . drain ( ) }
498498 }
499499
500+ /// Creates an iterator which uses a closure to determine if an element should be removed.
501+ ///
502+ /// If the closure returns true, the element is removed from the map and yielded.
503+ /// If the closure returns false, or panics, the element remains in the map and will not be
504+ /// yielded.
505+ ///
506+ /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of
507+ /// whether you choose to keep or remove it.
508+ ///
509+ /// If the iterator is only partially consumed or not consumed at all, each of the remaining
510+ /// elements will still be subjected to the closure and removed and dropped if it returns true.
511+ ///
512+ /// It is unspecified how many more elements will be subjected to the closure
513+ /// if a panic occurs in the closure, or a panic occurs while dropping an element,
514+ /// or if the `DrainFilter` value is leaked.
515+ ///
516+ /// # Examples
517+ ///
518+ /// Splitting a map into even and odd keys, reusing the original map:
519+ ///
520+ /// ```
521+ /// #![feature(hash_drain_filter)]
522+ /// use std::collections::HashMap;
523+ ///
524+ /// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
525+ /// let drained: HashMap<i32, i32> = map.drain_filter(|k, _v| k % 2 == 0).collect();
526+ ///
527+ /// let mut evens = drained.keys().copied().collect::<Vec<_>>();
528+ /// let mut odds = map.keys().copied().collect::<Vec<_>>();
529+ /// evens.sort();
530+ /// odds.sort();
531+ ///
532+ /// assert_eq!(evens, vec![0, 2, 4, 6]);
533+ /// assert_eq!(odds, vec![1, 3, 5, 7]);
534+ /// ```
535+ #[ inline]
536+ #[ unstable( feature = "hash_drain_filter" , issue = "59618" ) ]
537+ pub fn drain_filter < F > ( & mut self , pred : F ) -> DrainFilter < ' _ , K , V , F >
538+ where
539+ F : FnMut ( & K , & mut V ) -> bool ,
540+ {
541+ DrainFilter { base : self . base . drain_filter ( pred) }
542+ }
543+
500544 /// Clears the map, removing all key-value pairs. Keeps the allocated memory
501545 /// for reuse.
502546 ///
@@ -1190,6 +1234,19 @@ impl<'a, K, V> Drain<'a, K, V> {
11901234 }
11911235}
11921236
1237+ /// A draining, filtering iterator over the entries of a `HashMap`.
1238+ ///
1239+ /// This `struct` is created by the [`drain_filter`] method on [`HashMap`].
1240+ ///
1241+ /// [`drain_filter`]: HashMap::drain_filter
1242+ #[ unstable( feature = "hash_drain_filter" , issue = "59618" ) ]
1243+ pub struct DrainFilter < ' a , K , V , F >
1244+ where
1245+ F : FnMut ( & K , & mut V ) -> bool ,
1246+ {
1247+ base : base:: DrainFilter < ' a , K , V , F > ,
1248+ }
1249+
11931250/// A mutable iterator over the values of a `HashMap`.
11941251///
11951252/// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its
@@ -1990,6 +2047,36 @@ where
19902047 }
19912048}
19922049
2050+ #[ unstable( feature = "hash_drain_filter" , issue = "59618" ) ]
2051+ impl < K , V , F > Iterator for DrainFilter < ' _ , K , V , F >
2052+ where
2053+ F : FnMut ( & K , & mut V ) -> bool ,
2054+ {
2055+ type Item = ( K , V ) ;
2056+
2057+ #[ inline]
2058+ fn next ( & mut self ) -> Option < ( K , V ) > {
2059+ self . base . next ( )
2060+ }
2061+ #[ inline]
2062+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
2063+ self . base . size_hint ( )
2064+ }
2065+ }
2066+
2067+ #[ unstable( feature = "hash_drain_filter" , issue = "59618" ) ]
2068+ impl < K , V , F > FusedIterator for DrainFilter < ' _ , K , V , F > where F : FnMut ( & K , & mut V ) -> bool { }
2069+
2070+ #[ unstable( feature = "hash_drain_filter" , issue = "59618" ) ]
2071+ impl < ' a , K , V , F > fmt:: Debug for DrainFilter < ' a , K , V , F >
2072+ where
2073+ F : FnMut ( & K , & mut V ) -> bool ,
2074+ {
2075+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
2076+ f. pad ( "DrainFilter { .. }" )
2077+ }
2078+ }
2079+
19932080impl < ' a , K , V > Entry < ' a , K , V > {
19942081 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
19952082 /// Ensures a value is in the entry by inserting the default if empty, and returns
0 commit comments