Skip to content

Reverse drain_filter behavior to match libstd #187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Changed
- `drain_filter` now removes and yields items that do match the predicate,
rather than items that don't. This is a **breaking change** to match the
behavior of the `drain_filter` methods in `std`.

## [v0.8.2] - 2020-08-08

### Changed
Expand Down
24 changes: 15 additions & 9 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,24 +584,30 @@ impl<K, V, S> HashMap<K, V, S> {
}
}

/// Drains elements which are false under the given predicate,
/// Drains elements which are true under the given predicate,
/// and returns an iterator over the removed items.
///
/// In other words, move all pairs `(k, v)` such that `f(&k,&mut v)` returns `false` out
/// In other words, move all pairs `(k, v)` such that `f(&k,&mut v)` returns `true` out
/// into another iterator.
///
/// When the returned DrainedFilter is dropped, the elements that don't satisfy
/// When the returned DrainedFilter is dropped, any remaining elements that satisfy
/// the predicate are dropped from the table.
///
/// # Examples
///
/// ```
/// use hashbrown::HashMap;
///
/// let mut map: HashMap<i32, i32> = (0..8).map(|x|(x, x*10)).collect();
/// let drained = map.drain_filter(|&k, _| k % 2 == 0);
/// assert_eq!(drained.count(), 4);
/// assert_eq!(map.len(), 4);
/// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
/// let drained: HashMap<i32, i32> = map.drain_filter(|k, _v| k % 2 == 0).collect();
///
/// let mut evens = drained.keys().cloned().collect::<Vec<_>>();
/// let mut odds = map.keys().cloned().collect::<Vec<_>>();
/// evens.sort();
/// odds.sort();
///
/// assert_eq!(evens, vec![0, 2, 4, 6]);
/// assert_eq!(odds, vec![1, 3, 5, 7]);
/// ```
#[cfg_attr(feature = "inline-more", inline)]
pub fn drain_filter<F>(&mut self, f: F) -> DrainFilter<'_, K, V, F>
Expand Down Expand Up @@ -1401,7 +1407,7 @@ impl<K, V> DrainFilterInner<'_, K, V> {
unsafe {
while let Some(item) = self.iter.next() {
let &mut (ref key, ref mut value) = item.as_mut();
if !f(key, value) {
if f(key, value) {
return Some(self.table.remove(item));
}
}
Expand Down Expand Up @@ -3763,7 +3769,7 @@ mod test_map {
let drained = map.drain_filter(|&k, _| k % 2 == 0);
let mut out = drained.collect::<Vec<_>>();
out.sort_unstable();
assert_eq!(vec![(1, 10), (3, 30), (5, 50), (7, 70)], out);
assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out);
assert_eq!(map.len(), 4);
}
{
Expand Down
20 changes: 13 additions & 7 deletions src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,13 +352,13 @@ impl<T, S> HashSet<T, S> {
self.map.retain(|k, _| f(k));
}

/// Drains elements which are false under the given predicate,
/// Drains elements which are true under the given predicate,
/// and returns an iterator over the removed items.
///
/// In other words, move all elements `e` such that `f(&e)` returns `false` out
/// In other words, move all elements `e` such that `f(&e)` returns `true` out
/// into another iterator.
///
/// When the returned DrainedFilter is dropped, the elements that don't satisfy
/// When the returned DrainedFilter is dropped, any remaining elements that satisfy
/// the predicate are dropped from the set.
///
/// # Examples
Expand All @@ -367,9 +367,15 @@ impl<T, S> HashSet<T, S> {
/// use hashbrown::HashSet;
///
/// let mut set: HashSet<i32> = (0..8).collect();
/// let drained = set.drain_filter(|&k| k % 2 == 0);
/// assert_eq!(drained.count(), 4);
/// assert_eq!(set.len(), 4);
/// let drained: HashSet<i32> = set.drain_filter(|v| v % 2 == 0).collect();
///
/// let mut evens = drained.into_iter().collect::<Vec<_>>();
/// let mut odds = set.into_iter().collect::<Vec<_>>();
/// evens.sort();
/// odds.sort();
///
/// assert_eq!(evens, vec![0, 2, 4, 6]);
/// assert_eq!(odds, vec![1, 3, 5, 7]);
/// ```
#[cfg_attr(feature = "inline-more", inline)]
pub fn drain_filter<F>(&mut self, f: F) -> DrainFilter<'_, T, F>
Expand Down Expand Up @@ -2074,7 +2080,7 @@ mod test_set {
let drained = set.drain_filter(|&k| k % 2 == 0);
let mut out = drained.collect::<Vec<_>>();
out.sort_unstable();
assert_eq!(vec![1, 3, 5, 7], out);
assert_eq!(vec![0, 2, 4, 6], out);
assert_eq!(set.len(), 4);
}
{
Expand Down