Skip to content

Commit 8b7638d

Browse files
committed
Add Range parameter to BTreeMap::extract_if and BTreeSet::extract_if
This change was requested in the btree_extract_if tracking issue: rust-lang#70530 (comment)
1 parent a230e7a commit 8b7638d

File tree

2 files changed

+57
-19
lines changed

2 files changed

+57
-19
lines changed

alloc/src/collections/btree/map.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
11511151
K: Ord,
11521152
F: FnMut(&K, &mut V) -> bool,
11531153
{
1154-
self.extract_if(|k, v| !f(k, v)).for_each(drop);
1154+
self.extract_if(.., |k, v| !f(k, v)).for_each(drop);
11551155
}
11561156

11571157
/// Moves all elements from `other` into `self`, leaving `other` empty.
@@ -1429,27 +1429,30 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
14291429
/// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
14301430
/// ```
14311431
#[unstable(feature = "btree_extract_if", issue = "70530")]
1432-
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A>
1432+
pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, R, F, A>
14331433
where
14341434
K: Ord,
1435+
R: RangeBounds<K>,
14351436
F: FnMut(&K, &mut V) -> bool,
14361437
{
1437-
let (inner, alloc) = self.extract_if_inner();
1438+
let (inner, alloc) = self.extract_if_inner(range);
14381439
ExtractIf { pred, inner, alloc }
14391440
}
14401441

1441-
pub(super) fn extract_if_inner(&mut self) -> (ExtractIfInner<'_, K, V>, A)
1442+
pub(super) fn extract_if_inner<R>(&mut self, range: R) -> (ExtractIfInner<'_, K, V, R>, A)
14421443
where
14431444
K: Ord,
1445+
R: RangeBounds<K>,
14441446
{
14451447
if let Some(root) = self.root.as_mut() {
14461448
let (root, dormant_root) = DormantMutRef::new(root);
1447-
let front = root.borrow_mut().first_leaf_edge();
1449+
let first = root.borrow_mut().lower_bound(SearchBound::from_range(range.start_bound()));
14481450
(
14491451
ExtractIfInner {
14501452
length: &mut self.length,
14511453
dormant_root: Some(dormant_root),
1452-
cur_leaf_edge: Some(front),
1454+
cur_leaf_edge: Some(first),
1455+
range,
14531456
},
14541457
(*self.alloc).clone(),
14551458
)
@@ -1459,6 +1462,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
14591462
length: &mut self.length,
14601463
dormant_root: None,
14611464
cur_leaf_edge: None,
1465+
range,
14621466
},
14631467
(*self.alloc).clone(),
14641468
)
@@ -1917,18 +1921,19 @@ pub struct ExtractIf<
19171921
'a,
19181922
K,
19191923
V,
1924+
R,
19201925
F,
19211926
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
19221927
> {
19231928
pred: F,
1924-
inner: ExtractIfInner<'a, K, V>,
1929+
inner: ExtractIfInner<'a, K, V, R>,
19251930
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
19261931
alloc: A,
19271932
}
19281933

19291934
/// Most of the implementation of ExtractIf are generic over the type
19301935
/// of the predicate, thus also serving for BTreeSet::ExtractIf.
1931-
pub(super) struct ExtractIfInner<'a, K, V> {
1936+
pub(super) struct ExtractIfInner<'a, K, V, R> {
19321937
/// Reference to the length field in the borrowed map, updated live.
19331938
length: &'a mut usize,
19341939
/// Buried reference to the root field in the borrowed map.
@@ -1938,10 +1943,13 @@ pub(super) struct ExtractIfInner<'a, K, V> {
19381943
/// Empty if the map has no root, if iteration went beyond the last leaf edge,
19391944
/// or if a panic occurred in the predicate.
19401945
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
1946+
/// Range over which iteration was requested. We don't need the left side, but we
1947+
/// can't extract the right side without requiring K: Clone.
1948+
range: R,
19411949
}
19421950

19431951
#[unstable(feature = "btree_extract_if", issue = "70530")]
1944-
impl<K, V, F, A> fmt::Debug for ExtractIf<'_, K, V, F, A>
1952+
impl<K, V, R, F, A> fmt::Debug for ExtractIf<'_, K, V, R, F, A>
19451953
where
19461954
K: fmt::Debug,
19471955
V: fmt::Debug,
@@ -1953,8 +1961,10 @@ where
19531961
}
19541962

19551963
#[unstable(feature = "btree_extract_if", issue = "70530")]
1956-
impl<K, V, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, F, A>
1964+
impl<K, V, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, R, F, A>
19571965
where
1966+
K: PartialOrd,
1967+
R: RangeBounds<K>,
19581968
F: FnMut(&K, &mut V) -> bool,
19591969
{
19601970
type Item = (K, V);
@@ -1968,7 +1978,7 @@ where
19681978
}
19691979
}
19701980

1971-
impl<'a, K, V> ExtractIfInner<'a, K, V> {
1981+
impl<'a, K, V, R> ExtractIfInner<'a, K, V, R> {
19721982
/// Allow Debug implementations to predict the next element.
19731983
pub(super) fn peek(&self) -> Option<(&K, &V)> {
19741984
let edge = self.cur_leaf_edge.as_ref()?;
@@ -1978,10 +1988,22 @@ impl<'a, K, V> ExtractIfInner<'a, K, V> {
19781988
/// Implementation of a typical `ExtractIf::next` method, given the predicate.
19791989
pub(super) fn next<F, A: Allocator + Clone>(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)>
19801990
where
1991+
K: PartialOrd,
1992+
R: RangeBounds<K>,
19811993
F: FnMut(&K, &mut V) -> bool,
19821994
{
19831995
while let Ok(mut kv) = self.cur_leaf_edge.take()?.next_kv() {
19841996
let (k, v) = kv.kv_mut();
1997+
1998+
// On creation, we navigated directly to the left bound, so we need only check the
1999+
// right bound here to decide whether to stop.
2000+
match self.range.end_bound() {
2001+
Bound::Included(ref end) if (*k).le(end) => (),
2002+
Bound::Excluded(ref end) if (*k).lt(end) => (),
2003+
Bound::Unbounded => (),
2004+
_ => return None,
2005+
}
2006+
19852007
if pred(k, v) {
19862008
*self.length -= 1;
19872009
let (kv, pos) = kv.remove_kv_tracking(
@@ -2013,7 +2035,13 @@ impl<'a, K, V> ExtractIfInner<'a, K, V> {
20132035
}
20142036

20152037
#[unstable(feature = "btree_extract_if", issue = "70530")]
2016-
impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
2038+
impl<K, V, R, F> FusedIterator for ExtractIf<'_, K, V, R, F>
2039+
where
2040+
K: PartialOrd,
2041+
R: RangeBounds<K>,
2042+
F: FnMut(&K, &mut V) -> bool,
2043+
{
2044+
}
20172045

20182046
#[stable(feature = "btree_range", since = "1.17.0")]
20192047
impl<'a, K, V> Iterator for Range<'a, K, V> {

alloc/src/collections/btree/set.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
11091109
T: Ord,
11101110
F: FnMut(&T) -> bool,
11111111
{
1112-
self.extract_if(|v| !f(v)).for_each(drop);
1112+
self.extract_if(.., |v| !f(v)).for_each(drop);
11131113
}
11141114

11151115
/// Moves all elements from `other` into `self`, leaving `other` empty.
@@ -1214,12 +1214,13 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
12141214
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7]);
12151215
/// ```
12161216
#[unstable(feature = "btree_extract_if", issue = "70530")]
1217-
pub fn extract_if<'a, F>(&'a mut self, pred: F) -> ExtractIf<'a, T, F, A>
1217+
pub fn extract_if<'a, F, R>(&'a mut self, range: R, pred: F) -> ExtractIf<'a, T, R, F, A>
12181218
where
12191219
T: Ord,
1220+
R: RangeBounds<T>,
12201221
F: 'a + FnMut(&T) -> bool,
12211222
{
1222-
let (inner, alloc) = self.map.extract_if_inner();
1223+
let (inner, alloc) = self.map.extract_if_inner(range);
12231224
ExtractIf { pred, inner, alloc }
12241225
}
12251226

@@ -1554,17 +1555,18 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet<T, A> {
15541555
pub struct ExtractIf<
15551556
'a,
15561557
T,
1558+
R,
15571559
F,
15581560
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
15591561
> {
15601562
pred: F,
1561-
inner: super::map::ExtractIfInner<'a, T, SetValZST>,
1563+
inner: super::map::ExtractIfInner<'a, T, SetValZST, R>,
15621564
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
15631565
alloc: A,
15641566
}
15651567

15661568
#[unstable(feature = "btree_extract_if", issue = "70530")]
1567-
impl<T, F, A> fmt::Debug for ExtractIf<'_, T, F, A>
1569+
impl<T, R, F, A> fmt::Debug for ExtractIf<'_, T, R, F, A>
15681570
where
15691571
T: fmt::Debug,
15701572
A: Allocator + Clone,
@@ -1577,8 +1579,10 @@ where
15771579
}
15781580

15791581
#[unstable(feature = "btree_extract_if", issue = "70530")]
1580-
impl<'a, T, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, F, A>
1582+
impl<'a, T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A>
15811583
where
1584+
T: PartialOrd,
1585+
R: RangeBounds<T>,
15821586
F: 'a + FnMut(&T) -> bool,
15831587
{
15841588
type Item = T;
@@ -1595,7 +1599,13 @@ where
15951599
}
15961600

15971601
#[unstable(feature = "btree_extract_if", issue = "70530")]
1598-
impl<T, F, A: Allocator + Clone> FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&T) -> bool {}
1602+
impl<T, R, F, A: Allocator + Clone> FusedIterator for ExtractIf<'_, T, R, F, A>
1603+
where
1604+
T: PartialOrd,
1605+
R: RangeBounds<T>,
1606+
F: FnMut(&T) -> bool,
1607+
{
1608+
}
15991609

16001610
#[stable(feature = "rust1", since = "1.0.0")]
16011611
impl<T: Ord, A: Allocator + Clone> Extend<T> for BTreeSet<T, A> {

0 commit comments

Comments
 (0)