Skip to content

Commit 49aef96

Browse files
committed
Add HashMap::drain_filter and HashSet::drain_filter
Implements #59618.
1 parent ebd15e7 commit 49aef96

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

library/std/src/collections/hash/map.rs

+87
Original file line numberDiff line numberDiff line change
@@ -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+
19932080
impl<'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

library/std/src/collections/hash/set.rs

+84
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,47 @@ impl<T, S> HashSet<T, S> {
247247
Drain { base: self.base.drain() }
248248
}
249249

250+
/// Creates an iterator which uses a closure to determine if a value should be removed.
251+
///
252+
/// If the closure returns true, then the value is removed and yielded.
253+
/// If the closure returns false, the value will remain in the list and will not be yielded
254+
/// by the iterator.
255+
///
256+
/// If the iterator is only partially consumed or not consumed at all, each of the remaining
257+
/// values will still be subjected to the closure and removed and dropped if it returns true.
258+
///
259+
/// It is unspecified how many more values will be subjected to the closure
260+
/// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the
261+
/// `DrainFilter` itself is leaked.
262+
///
263+
/// # Examples
264+
///
265+
/// Splitting a set into even and odd values, reusing the original set:
266+
///
267+
/// ```
268+
/// #![feature(hash_drain_filter)]
269+
/// use std::collections::HashSet;
270+
///
271+
/// let mut set: HashSet<i32> = (0..8).collect();
272+
/// let drained: HashSet<i32> = set.drain_filter(|v| v % 2 == 0).collect();
273+
///
274+
/// let mut evens = drained.into_iter().collect::<Vec<_>>();
275+
/// let mut odds = set.into_iter().collect::<Vec<_>>();
276+
/// evens.sort();
277+
/// odds.sort();
278+
///
279+
/// assert_eq!(evens, vec![0, 2, 4, 6]);
280+
/// assert_eq!(odds, vec![1, 3, 5, 7]);
281+
/// ```
282+
#[inline]
283+
#[unstable(feature = "hash_drain_filter", issue = "59618")]
284+
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
285+
where
286+
F: FnMut(&T) -> bool,
287+
{
288+
DrainFilter { base: self.base.drain_filter(pred) }
289+
}
290+
250291
/// Clears the set, removing all values.
251292
///
252293
/// # Examples
@@ -1159,6 +1200,19 @@ pub struct Drain<'a, K: 'a> {
11591200
base: base::Drain<'a, K>,
11601201
}
11611202

1203+
/// A draining, filtering iterator over the items of a `HashSet`.
1204+
///
1205+
/// This `struct` is created by the [`drain_filter`] method on [`HashSet`].
1206+
///
1207+
/// [`drain_filter`]: HashSet::drain_filter
1208+
#[unstable(feature = "hash_drain_filter", issue = "59618")]
1209+
pub struct DrainFilter<'a, K, F>
1210+
where
1211+
F: FnMut(&K) -> bool,
1212+
{
1213+
base: base::DrainFilter<'a, K, F>,
1214+
}
1215+
11621216
/// A lazy iterator producing elements in the intersection of `HashSet`s.
11631217
///
11641218
/// This `struct` is created by the [`intersection`] method on [`HashSet`].
@@ -1348,6 +1402,36 @@ impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
13481402
}
13491403
}
13501404

1405+
#[unstable(feature = "hash_drain_filter", issue = "59618")]
1406+
impl<K, F> Iterator for DrainFilter<'_, K, F>
1407+
where
1408+
F: FnMut(&K) -> bool,
1409+
{
1410+
type Item = K;
1411+
1412+
#[inline]
1413+
fn next(&mut self) -> Option<K> {
1414+
self.base.next()
1415+
}
1416+
#[inline]
1417+
fn size_hint(&self) -> (usize, Option<usize>) {
1418+
self.base.size_hint()
1419+
}
1420+
}
1421+
1422+
#[unstable(feature = "hash_drain_filter", issue = "59618")]
1423+
impl<K, F> FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {}
1424+
1425+
#[unstable(feature = "hash_drain_filter", issue = "59618")]
1426+
impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F>
1427+
where
1428+
F: FnMut(&K) -> bool,
1429+
{
1430+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1431+
f.pad("DrainFilter { .. }")
1432+
}
1433+
}
1434+
13511435
#[stable(feature = "rust1", since = "1.0.0")]
13521436
impl<T, S> Clone for Intersection<'_, T, S> {
13531437
#[inline]

0 commit comments

Comments
 (0)