Skip to content

Commit 7c34f44

Browse files
Rollup merge of rust-lang#140825 - rs-sac:ext, r=workingjubilee
Add Range parameter to `BTreeMap::extract_if` and `BTreeSet::extract_if` This new parameter was requested in the btree_extract_if tracking issue: rust-lang#70530 (comment) I attempted to follow the style used by `Vec::extract_if`. Before: ```rust impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[unstable(feature = "btree_extract_if", issue = "70530")] pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A> where K: Ord, F: FnMut(&K, &mut V) -> bool; } ``` After: ```rust impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { #[unstable(feature = "btree_extract_if", issue = "70530")] pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, R, F, A> where K: Ord, R: RangeBounds<K>, F: FnMut(&K, &mut V) -> bool; } ``` Related: rust-lang#70530 — While I believe I have adjusted all of the necessary bits, as this is my first attempt to contribute to Rust, I may have overlooked something out of ignorance, but if you can point out any oversight, I shall attempt to remedy it.
2 parents c7ac933 + 736223d commit 7c34f44

File tree

7 files changed

+150
-66
lines changed

7 files changed

+150
-66
lines changed

alloc/src/collections/btree/map.rs

Lines changed: 48 additions & 14 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.
@@ -1397,7 +1397,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13971397
}
13981398
}
13991399

1400-
/// Creates an iterator that visits all elements (key-value pairs) in
1400+
/// Creates an iterator that visits elements (key-value pairs) in the specified range in
14011401
/// ascending key order and uses a closure to determine if an element
14021402
/// should be removed.
14031403
///
@@ -1423,33 +1423,42 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
14231423
/// use std::collections::BTreeMap;
14241424
///
14251425
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
1426-
/// let evens: BTreeMap<_, _> = map.extract_if(|k, _v| k % 2 == 0).collect();
1426+
/// let evens: BTreeMap<_, _> = map.extract_if(.., |k, _v| k % 2 == 0).collect();
14271427
/// let odds = map;
14281428
/// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]);
14291429
/// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
1430+
///
1431+
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
1432+
/// let low: BTreeMap<_, _> = map.extract_if(0..4, |_k, _v| true).collect();
1433+
/// let high = map;
1434+
/// assert_eq!(low.keys().copied().collect::<Vec<_>>(), [0, 1, 2, 3]);
1435+
/// assert_eq!(high.keys().copied().collect::<Vec<_>>(), [4, 5, 6, 7]);
14301436
/// ```
14311437
#[unstable(feature = "btree_extract_if", issue = "70530")]
1432-
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A>
1438+
pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, R, F, A>
14331439
where
14341440
K: Ord,
1441+
R: RangeBounds<K>,
14351442
F: FnMut(&K, &mut V) -> bool,
14361443
{
1437-
let (inner, alloc) = self.extract_if_inner();
1444+
let (inner, alloc) = self.extract_if_inner(range);
14381445
ExtractIf { pred, inner, alloc }
14391446
}
14401447

1441-
pub(super) fn extract_if_inner(&mut self) -> (ExtractIfInner<'_, K, V>, A)
1448+
pub(super) fn extract_if_inner<R>(&mut self, range: R) -> (ExtractIfInner<'_, K, V, R>, A)
14421449
where
14431450
K: Ord,
1451+
R: RangeBounds<K>,
14441452
{
14451453
if let Some(root) = self.root.as_mut() {
14461454
let (root, dormant_root) = DormantMutRef::new(root);
1447-
let front = root.borrow_mut().first_leaf_edge();
1455+
let first = root.borrow_mut().lower_bound(SearchBound::from_range(range.start_bound()));
14481456
(
14491457
ExtractIfInner {
14501458
length: &mut self.length,
14511459
dormant_root: Some(dormant_root),
1452-
cur_leaf_edge: Some(front),
1460+
cur_leaf_edge: Some(first),
1461+
range,
14531462
},
14541463
(*self.alloc).clone(),
14551464
)
@@ -1459,6 +1468,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
14591468
length: &mut self.length,
14601469
dormant_root: None,
14611470
cur_leaf_edge: None,
1471+
range,
14621472
},
14631473
(*self.alloc).clone(),
14641474
)
@@ -1917,18 +1927,19 @@ pub struct ExtractIf<
19171927
'a,
19181928
K,
19191929
V,
1930+
R,
19201931
F,
19211932
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global,
19221933
> {
19231934
pred: F,
1924-
inner: ExtractIfInner<'a, K, V>,
1935+
inner: ExtractIfInner<'a, K, V, R>,
19251936
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
19261937
alloc: A,
19271938
}
19281939

19291940
/// Most of the implementation of ExtractIf are generic over the type
19301941
/// of the predicate, thus also serving for BTreeSet::ExtractIf.
1931-
pub(super) struct ExtractIfInner<'a, K, V> {
1942+
pub(super) struct ExtractIfInner<'a, K, V, R> {
19321943
/// Reference to the length field in the borrowed map, updated live.
19331944
length: &'a mut usize,
19341945
/// Buried reference to the root field in the borrowed map.
@@ -1938,10 +1949,13 @@ pub(super) struct ExtractIfInner<'a, K, V> {
19381949
/// Empty if the map has no root, if iteration went beyond the last leaf edge,
19391950
/// or if a panic occurred in the predicate.
19401951
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
1952+
/// Range over which iteration was requested. We don't need the left side, but we
1953+
/// can't extract the right side without requiring K: Clone.
1954+
range: R,
19411955
}
19421956

19431957
#[unstable(feature = "btree_extract_if", issue = "70530")]
1944-
impl<K, V, F, A> fmt::Debug for ExtractIf<'_, K, V, F, A>
1958+
impl<K, V, R, F, A> fmt::Debug for ExtractIf<'_, K, V, R, F, A>
19451959
where
19461960
K: fmt::Debug,
19471961
V: fmt::Debug,
@@ -1953,8 +1967,10 @@ where
19531967
}
19541968

19551969
#[unstable(feature = "btree_extract_if", issue = "70530")]
1956-
impl<K, V, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, F, A>
1970+
impl<K, V, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, R, F, A>
19571971
where
1972+
K: PartialOrd,
1973+
R: RangeBounds<K>,
19581974
F: FnMut(&K, &mut V) -> bool,
19591975
{
19601976
type Item = (K, V);
@@ -1968,7 +1984,7 @@ where
19681984
}
19691985
}
19701986

1971-
impl<'a, K, V> ExtractIfInner<'a, K, V> {
1987+
impl<'a, K, V, R> ExtractIfInner<'a, K, V, R> {
19721988
/// Allow Debug implementations to predict the next element.
19731989
pub(super) fn peek(&self) -> Option<(&K, &V)> {
19741990
let edge = self.cur_leaf_edge.as_ref()?;
@@ -1978,10 +1994,22 @@ impl<'a, K, V> ExtractIfInner<'a, K, V> {
19781994
/// Implementation of a typical `ExtractIf::next` method, given the predicate.
19791995
pub(super) fn next<F, A: Allocator + Clone>(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)>
19801996
where
1997+
K: PartialOrd,
1998+
R: RangeBounds<K>,
19811999
F: FnMut(&K, &mut V) -> bool,
19822000
{
19832001
while let Ok(mut kv) = self.cur_leaf_edge.take()?.next_kv() {
19842002
let (k, v) = kv.kv_mut();
2003+
2004+
// On creation, we navigated directly to the left bound, so we need only check the
2005+
// right bound here to decide whether to stop.
2006+
match self.range.end_bound() {
2007+
Bound::Included(ref end) if (*k).le(end) => (),
2008+
Bound::Excluded(ref end) if (*k).lt(end) => (),
2009+
Bound::Unbounded => (),
2010+
_ => return None,
2011+
}
2012+
19852013
if pred(k, v) {
19862014
*self.length -= 1;
19872015
let (kv, pos) = kv.remove_kv_tracking(
@@ -2013,7 +2041,13 @@ impl<'a, K, V> ExtractIfInner<'a, K, V> {
20132041
}
20142042

20152043
#[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 {}
2044+
impl<K, V, R, F> FusedIterator for ExtractIf<'_, K, V, R, F>
2045+
where
2046+
K: PartialOrd,
2047+
R: RangeBounds<K>,
2048+
F: FnMut(&K, &mut V) -> bool,
2049+
{
2050+
}
20172051

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

0 commit comments

Comments
 (0)