Skip to content

Commit 339b15f

Browse files
committed
extract_if with traits
1 parent 664c364 commit 339b15f

File tree

3 files changed

+78
-33
lines changed

3 files changed

+78
-33
lines changed

src/map.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::raw::{Allocator, Bucket, Global, RawExtractIf};
1+
use crate::raw::{Allocator, Bucket, Global};
22
use crate::{table, DefaultHashBuilder, Equivalent, HashTable, TryReserveError};
33
use ::alloc::borrow::ToOwned;
44
use core::borrow::Borrow;
@@ -960,14 +960,10 @@ impl<K, V, S, A: Allocator> HashMap<K, V, S, A> {
960960
#[cfg_attr(feature = "inline-more", inline)]
961961
pub fn extract_if<F>(&mut self, f: F) -> ExtractIf<'_, K, V, F, A>
962962
where
963-
F: FnMut(&K, &mut V) -> bool,
963+
F: Filter<K, V>,
964964
{
965965
ExtractIf {
966-
f,
967-
inner: RawExtractIf {
968-
iter: unsafe { self.table.raw.iter() },
969-
table: &mut self.table.raw,
970-
},
966+
inner: self.table.extract_if(KeyVal(f)),
971967
}
972968
}
973969

@@ -2590,6 +2586,29 @@ impl<K, V, A: Allocator> Drain<'_, K, V, A> {
25902586
}
25912587
}
25922588

2589+
/// Adapter between [`map::Filter`](Filter) and [`table::Filter`].
2590+
struct KeyVal<F>(F);
2591+
impl<K, V, F: Filter<K, V>> table::Filter<(K, V)> for KeyVal<F> {
2592+
#[inline]
2593+
fn should_extract(&mut self, (ref key, ref mut val): &mut (K, V)) -> bool {
2594+
self.0.should_extract(key, val)
2595+
}
2596+
}
2597+
2598+
/// Filter for [`ExtractIf`].
2599+
///
2600+
/// Accepts `FnMut(&K, &mut V) -> bool`, but can be implemented directly.
2601+
pub trait Filter<K, V> {
2602+
/// Whether the element should be extracted.
2603+
fn should_extract(&mut self, key: &K, value: &mut V) -> bool;
2604+
}
2605+
impl<K, V, F: FnMut(&K, &mut V) -> bool> Filter<K, V> for F {
2606+
#[inline]
2607+
fn should_extract(&mut self, key: &K, value: &mut V) -> bool {
2608+
(self)(key, value)
2609+
}
2610+
}
2611+
25932612
/// A draining iterator over entries of a `HashMap` which don't satisfy the predicate
25942613
/// `f(&k, &mut v)` in arbitrary order. The iterator element type is `(K, V)`.
25952614
///
@@ -2623,25 +2642,24 @@ impl<K, V, A: Allocator> Drain<'_, K, V, A> {
26232642
/// ```
26242643
#[must_use = "Iterators are lazy unless consumed"]
26252644
pub struct ExtractIf<'a, K, V, F, A: Allocator = Global> {
2626-
f: F,
2627-
inner: RawExtractIf<'a, (K, V), A>,
2645+
inner: table::ExtractIf<'a, (K, V), KeyVal<F>, A>,
26282646
}
26292647

26302648
impl<K, V, F, A> Iterator for ExtractIf<'_, K, V, F, A>
26312649
where
2632-
F: FnMut(&K, &mut V) -> bool,
2650+
F: Filter<K, V>,
26332651
A: Allocator,
26342652
{
26352653
type Item = (K, V);
26362654

26372655
#[cfg_attr(feature = "inline-more", inline)]
26382656
fn next(&mut self) -> Option<Self::Item> {
2639-
self.inner.next(|&mut (ref k, ref mut v)| (self.f)(k, v))
2657+
self.inner.next()
26402658
}
26412659

26422660
#[inline]
26432661
fn size_hint(&self) -> (usize, Option<usize>) {
2644-
(0, self.inner.iter.size_hint().1)
2662+
self.inner.size_hint()
26452663
}
26462664
}
26472665

src/set.rs

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign,
55
use core::{fmt, mem};
66
use map::make_hash;
77

8-
use super::map::{self, HashMap, Keys};
9-
use crate::raw::{Allocator, Global, RawExtractIf};
8+
use crate::map::{self, HashMap, Keys};
9+
use crate::raw::{Allocator, Global};
1010
use crate::DefaultHashBuilder;
1111

1212
// Future Optimization (FIXME!)
@@ -403,14 +403,10 @@ impl<T, S, A: Allocator> HashSet<T, S, A> {
403403
#[cfg_attr(feature = "inline-more", inline)]
404404
pub fn extract_if<F>(&mut self, f: F) -> ExtractIf<'_, T, F, A>
405405
where
406-
F: FnMut(&T) -> bool,
406+
F: Filter<T>,
407407
{
408408
ExtractIf {
409-
f,
410-
inner: RawExtractIf {
411-
iter: unsafe { self.map.table.raw.iter() },
412-
table: &mut self.map.table.raw,
413-
},
409+
inner: self.map.extract_if(Key(f)),
414410
}
415411
}
416412

@@ -1663,6 +1659,29 @@ pub struct Drain<'a, K, A: Allocator = Global> {
16631659
iter: map::Drain<'a, K, (), A>,
16641660
}
16651661

1662+
/// Adapter between [`set::Filter`](Filter) and [`map::Filter`].
1663+
struct Key<F>(F);
1664+
impl<T, F: Filter<T>> map::Filter<T, ()> for Key<F> {
1665+
#[inline]
1666+
fn should_extract(&mut self, key: &T, (): &mut ()) -> bool {
1667+
self.0.should_extract(key)
1668+
}
1669+
}
1670+
1671+
/// Filter for [`ExtractIf`].
1672+
///
1673+
/// Accepts `FnMut(&K) -> bool`, but can be implemented directly.
1674+
pub trait Filter<K> {
1675+
/// Whether the element should be extracted.
1676+
fn should_extract(&mut self, key: &K) -> bool;
1677+
}
1678+
impl<K, F: FnMut(&K) -> bool> Filter<K> for F {
1679+
#[inline]
1680+
fn should_extract(&mut self, key: &K) -> bool {
1681+
(self)(key)
1682+
}
1683+
}
1684+
16661685
/// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`.
16671686
///
16681687
/// This `struct` is created by the [`extract_if`] method on [`HashSet`]. See its
@@ -1672,8 +1691,7 @@ pub struct Drain<'a, K, A: Allocator = Global> {
16721691
/// [`HashSet`]: struct.HashSet.html
16731692
#[must_use = "Iterators are lazy unless consumed"]
16741693
pub struct ExtractIf<'a, K, F, A: Allocator = Global> {
1675-
f: F,
1676-
inner: RawExtractIf<'a, (K, ()), A>,
1694+
inner: map::ExtractIf<'a, K, (), Key<F>, A>,
16771695
}
16781696

16791697
/// A lazy iterator producing elements in the intersection of `HashSet`s.
@@ -1906,20 +1924,18 @@ impl<K: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, K, A> {
19061924

19071925
impl<K, F, A: Allocator> Iterator for ExtractIf<'_, K, F, A>
19081926
where
1909-
F: FnMut(&K) -> bool,
1927+
F: Filter<K>,
19101928
{
19111929
type Item = K;
19121930

19131931
#[cfg_attr(feature = "inline-more", inline)]
19141932
fn next(&mut self) -> Option<Self::Item> {
1915-
self.inner
1916-
.next(|&mut (ref k, ())| (self.f)(k))
1917-
.map(|(k, ())| k)
1933+
self.inner.next().map(|(k, ())| k)
19181934
}
19191935

19201936
#[inline]
19211937
fn size_hint(&self) -> (usize, Option<usize>) {
1922-
(0, self.inner.iter.size_hint().1)
1938+
self.inner.size_hint()
19231939
}
19241940
}
19251941

src/table.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,7 @@ where
13811381
/// ```
13821382
pub fn extract_if<F>(&mut self, f: F) -> ExtractIf<'_, T, F, A>
13831383
where
1384-
F: FnMut(&mut T) -> bool,
1384+
F: Filter<T>,
13851385
{
13861386
ExtractIf {
13871387
f,
@@ -3157,6 +3157,20 @@ impl<T: fmt::Debug, A: Allocator> fmt::Debug for Drain<'_, T, A> {
31573157
}
31583158
}
31593159

3160+
/// Filter for [`ExtractIf`].
3161+
///
3162+
/// Accepts `FnMut(&mut T) -> bool`, but can be implemented directly.
3163+
pub trait Filter<T> {
3164+
/// Whether the element should be extracted.
3165+
fn should_extract(&mut self, elem: &mut T) -> bool;
3166+
}
3167+
impl<T, F: FnMut(&mut T) -> bool> Filter<T> for F {
3168+
#[inline]
3169+
fn should_extract(&mut self, elem: &mut T) -> bool {
3170+
(self)(elem)
3171+
}
3172+
}
3173+
31603174
/// A draining iterator over entries of a `HashTable` which don't satisfy the predicate `f`.
31613175
///
31623176
/// This `struct` is created by [`HashTable::extract_if`]. See its
@@ -3167,15 +3181,12 @@ pub struct ExtractIf<'a, T, F, A: Allocator = Global> {
31673181
inner: RawExtractIf<'a, T, A>,
31683182
}
31693183

3170-
impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
3171-
where
3172-
F: FnMut(&mut T) -> bool,
3173-
{
3184+
impl<T, F: Filter<T>, A: Allocator> Iterator for ExtractIf<'_, T, F, A> {
31743185
type Item = T;
31753186

31763187
#[inline]
31773188
fn next(&mut self) -> Option<Self::Item> {
3178-
self.inner.next(|val| (self.f)(val))
3189+
self.inner.next(|val| self.f.should_extract(val))
31793190
}
31803191

31813192
#[inline]

0 commit comments

Comments
 (0)