Skip to content

Commit 83e727b

Browse files
committed
Auto merge of #104455 - the8472:dont-drain-on-drop, r=Amanieu
Don't drain-on-drop in DrainFilter impls of various collections. This removes drain-on-drop behavior from various unstable DrainFilter impls (not yet for HashSet/Map) because that behavior [is problematic](rust-lang/rust#43244 (comment)) (because it can lead to panic-in-drop when user closures panic) and may become forbidden if [this draft RFC passes](rust-lang/rfcs#3288). closes #101122 [ACP](rust-lang/libs-team#136) affected tracking issues * #43244 * #70530 * #59618 Related hashbrown update: rust-lang/hashbrown#374
2 parents 599ca56 + 6acd7ee commit 83e727b

File tree

20 files changed

+399
-534
lines changed

20 files changed

+399
-534
lines changed

alloc/benches/btree/map.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -385,15 +385,15 @@ pub fn clone_slim_100_and_clear(b: &mut Bencher) {
385385
#[bench]
386386
pub fn clone_slim_100_and_drain_all(b: &mut Bencher) {
387387
let src = slim_map(100);
388-
b.iter(|| src.clone().drain_filter(|_, _| true).count())
388+
b.iter(|| src.clone().extract_if(|_, _| true).count())
389389
}
390390

391391
#[bench]
392392
pub fn clone_slim_100_and_drain_half(b: &mut Bencher) {
393393
let src = slim_map(100);
394394
b.iter(|| {
395395
let mut map = src.clone();
396-
assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 100 / 2);
396+
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2);
397397
assert_eq!(map.len(), 100 / 2);
398398
})
399399
}
@@ -456,15 +456,15 @@ pub fn clone_slim_10k_and_clear(b: &mut Bencher) {
456456
#[bench]
457457
pub fn clone_slim_10k_and_drain_all(b: &mut Bencher) {
458458
let src = slim_map(10_000);
459-
b.iter(|| src.clone().drain_filter(|_, _| true).count())
459+
b.iter(|| src.clone().extract_if(|_, _| true).count())
460460
}
461461

462462
#[bench]
463463
pub fn clone_slim_10k_and_drain_half(b: &mut Bencher) {
464464
let src = slim_map(10_000);
465465
b.iter(|| {
466466
let mut map = src.clone();
467-
assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 10_000 / 2);
467+
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 10_000 / 2);
468468
assert_eq!(map.len(), 10_000 / 2);
469469
})
470470
}
@@ -527,15 +527,15 @@ pub fn clone_fat_val_100_and_clear(b: &mut Bencher) {
527527
#[bench]
528528
pub fn clone_fat_val_100_and_drain_all(b: &mut Bencher) {
529529
let src = fat_val_map(100);
530-
b.iter(|| src.clone().drain_filter(|_, _| true).count())
530+
b.iter(|| src.clone().extract_if(|_, _| true).count())
531531
}
532532

533533
#[bench]
534534
pub fn clone_fat_val_100_and_drain_half(b: &mut Bencher) {
535535
let src = fat_val_map(100);
536536
b.iter(|| {
537537
let mut map = src.clone();
538-
assert_eq!(map.drain_filter(|i, _| i % 2 == 0).count(), 100 / 2);
538+
assert_eq!(map.extract_if(|i, _| i % 2 == 0).count(), 100 / 2);
539539
assert_eq!(map.len(), 100 / 2);
540540
})
541541
}

alloc/benches/btree/set.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ pub fn clone_100_and_clear(b: &mut Bencher) {
6969
#[bench]
7070
pub fn clone_100_and_drain_all(b: &mut Bencher) {
7171
let src = slim_set(100);
72-
b.iter(|| src.clone().drain_filter(|_| true).count())
72+
b.iter(|| src.clone().extract_if(|_| true).count())
7373
}
7474

7575
#[bench]
7676
pub fn clone_100_and_drain_half(b: &mut Bencher) {
7777
let src = slim_set(100);
7878
b.iter(|| {
7979
let mut set = src.clone();
80-
assert_eq!(set.drain_filter(|i| i % 2 == 0).count(), 100 / 2);
80+
assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 100 / 2);
8181
assert_eq!(set.len(), 100 / 2);
8282
})
8383
}
@@ -140,15 +140,15 @@ pub fn clone_10k_and_clear(b: &mut Bencher) {
140140
#[bench]
141141
pub fn clone_10k_and_drain_all(b: &mut Bencher) {
142142
let src = slim_set(10_000);
143-
b.iter(|| src.clone().drain_filter(|_| true).count())
143+
b.iter(|| src.clone().extract_if(|_| true).count())
144144
}
145145

146146
#[bench]
147147
pub fn clone_10k_and_drain_half(b: &mut Bencher) {
148148
let src = slim_set(10_000);
149149
b.iter(|| {
150150
let mut set = src.clone();
151-
assert_eq!(set.drain_filter(|i| i % 2 == 0).count(), 10_000 / 2);
151+
assert_eq!(set.extract_if(|i| i % 2 == 0).count(), 10_000 / 2);
152152
assert_eq!(set.len(), 10_000 / 2);
153153
})
154154
}

alloc/benches/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Disabling on android for the time being
22
// See https://github.com/rust-lang/rust/issues/73535#event-3477699747
33
#![cfg(not(target_os = "android"))]
4-
#![feature(btree_drain_filter)]
4+
#![feature(btree_extract_if)]
55
#![feature(iter_next_chunk)]
66
#![feature(repr_simd)]
77
#![feature(slice_partition_dedup)]

alloc/src/collections/btree/map.rs

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
11321132
K: Ord,
11331133
F: FnMut(&K, &mut V) -> bool,
11341134
{
1135-
self.drain_filter(|k, v| !f(k, v));
1135+
self.extract_if(|k, v| !f(k, v)).for_each(drop);
11361136
}
11371137

11381138
/// Moves all elements from `other` into `self`, leaving `other` empty.
@@ -1395,48 +1395,45 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13951395
/// The iterator also lets you mutate the value of each element in the
13961396
/// closure, regardless of whether you choose to keep or remove it.
13971397
///
1398-
/// If the iterator is only partially consumed or not consumed at all, each
1399-
/// of the remaining elements is still subjected to the closure, which may
1400-
/// change its value and, by returning `true`, have the element removed and
1401-
/// dropped.
1398+
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
1399+
/// or the iteration short-circuits, then the remaining elements will be retained.
1400+
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
14021401
///
1403-
/// It is unspecified how many more elements will be subjected to the
1404-
/// closure if a panic occurs in the closure, or a panic occurs while
1405-
/// dropping an element, or if the `DrainFilter` value is leaked.
1402+
/// [`retain`]: BTreeMap::retain
14061403
///
14071404
/// # Examples
14081405
///
14091406
/// Splitting a map into even and odd keys, reusing the original map:
14101407
///
14111408
/// ```
1412-
/// #![feature(btree_drain_filter)]
1409+
/// #![feature(btree_extract_if)]
14131410
/// use std::collections::BTreeMap;
14141411
///
14151412
/// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
1416-
/// let evens: BTreeMap<_, _> = map.drain_filter(|k, _v| k % 2 == 0).collect();
1413+
/// let evens: BTreeMap<_, _> = map.extract_if(|k, _v| k % 2 == 0).collect();
14171414
/// let odds = map;
14181415
/// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]);
14191416
/// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
14201417
/// ```
1421-
#[unstable(feature = "btree_drain_filter", issue = "70530")]
1422-
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F, A>
1418+
#[unstable(feature = "btree_extract_if", issue = "70530")]
1419+
pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A>
14231420
where
14241421
K: Ord,
14251422
F: FnMut(&K, &mut V) -> bool,
14261423
{
1427-
let (inner, alloc) = self.drain_filter_inner();
1428-
DrainFilter { pred, inner, alloc }
1424+
let (inner, alloc) = self.extract_if_inner();
1425+
ExtractIf { pred, inner, alloc }
14291426
}
14301427

1431-
pub(super) fn drain_filter_inner(&mut self) -> (DrainFilterInner<'_, K, V>, A)
1428+
pub(super) fn extract_if_inner(&mut self) -> (ExtractIfInner<'_, K, V>, A)
14321429
where
14331430
K: Ord,
14341431
{
14351432
if let Some(root) = self.root.as_mut() {
14361433
let (root, dormant_root) = DormantMutRef::new(root);
14371434
let front = root.borrow_mut().first_leaf_edge();
14381435
(
1439-
DrainFilterInner {
1436+
ExtractIfInner {
14401437
length: &mut self.length,
14411438
dormant_root: Some(dormant_root),
14421439
cur_leaf_edge: Some(front),
@@ -1445,7 +1442,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
14451442
)
14461443
} else {
14471444
(
1448-
DrainFilterInner {
1445+
ExtractIfInner {
14491446
length: &mut self.length,
14501447
dormant_root: None,
14511448
cur_leaf_edge: None,
@@ -1899,9 +1896,10 @@ impl<K, V> Default for Values<'_, K, V> {
18991896
}
19001897
}
19011898

1902-
/// An iterator produced by calling `drain_filter` on BTreeMap.
1903-
#[unstable(feature = "btree_drain_filter", issue = "70530")]
1904-
pub struct DrainFilter<
1899+
/// An iterator produced by calling `extract_if` on BTreeMap.
1900+
#[unstable(feature = "btree_extract_if", issue = "70530")]
1901+
#[must_use = "iterators are lazy and do nothing unless consumed"]
1902+
pub struct ExtractIf<
19051903
'a,
19061904
K,
19071905
V,
@@ -1911,13 +1909,13 @@ pub struct DrainFilter<
19111909
F: 'a + FnMut(&K, &mut V) -> bool,
19121910
{
19131911
pred: F,
1914-
inner: DrainFilterInner<'a, K, V>,
1912+
inner: ExtractIfInner<'a, K, V>,
19151913
/// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`.
19161914
alloc: A,
19171915
}
1918-
/// Most of the implementation of DrainFilter are generic over the type
1919-
/// of the predicate, thus also serving for BTreeSet::DrainFilter.
1920-
pub(super) struct DrainFilterInner<'a, K, V> {
1916+
/// Most of the implementation of ExtractIf are generic over the type
1917+
/// of the predicate, thus also serving for BTreeSet::ExtractIf.
1918+
pub(super) struct ExtractIfInner<'a, K, V> {
19211919
/// Reference to the length field in the borrowed map, updated live.
19221920
length: &'a mut usize,
19231921
/// Buried reference to the root field in the borrowed map.
@@ -1929,30 +1927,20 @@ pub(super) struct DrainFilterInner<'a, K, V> {
19291927
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
19301928
}
19311929

1932-
#[unstable(feature = "btree_drain_filter", issue = "70530")]
1933-
impl<K, V, F, A: Allocator + Clone> Drop for DrainFilter<'_, K, V, F, A>
1934-
where
1935-
F: FnMut(&K, &mut V) -> bool,
1936-
{
1937-
fn drop(&mut self) {
1938-
self.for_each(drop);
1939-
}
1940-
}
1941-
1942-
#[unstable(feature = "btree_drain_filter", issue = "70530")]
1943-
impl<K, V, F> fmt::Debug for DrainFilter<'_, K, V, F>
1930+
#[unstable(feature = "btree_extract_if", issue = "70530")]
1931+
impl<K, V, F> fmt::Debug for ExtractIf<'_, K, V, F>
19441932
where
19451933
K: fmt::Debug,
19461934
V: fmt::Debug,
19471935
F: FnMut(&K, &mut V) -> bool,
19481936
{
19491937
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1950-
f.debug_tuple("DrainFilter").field(&self.inner.peek()).finish()
1938+
f.debug_tuple("ExtractIf").field(&self.inner.peek()).finish()
19511939
}
19521940
}
19531941

1954-
#[unstable(feature = "btree_drain_filter", issue = "70530")]
1955-
impl<K, V, F, A: Allocator + Clone> Iterator for DrainFilter<'_, K, V, F, A>
1942+
#[unstable(feature = "btree_extract_if", issue = "70530")]
1943+
impl<K, V, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, F, A>
19561944
where
19571945
F: FnMut(&K, &mut V) -> bool,
19581946
{
@@ -1967,14 +1955,14 @@ where
19671955
}
19681956
}
19691957

1970-
impl<'a, K, V> DrainFilterInner<'a, K, V> {
1958+
impl<'a, K, V> ExtractIfInner<'a, K, V> {
19711959
/// Allow Debug implementations to predict the next element.
19721960
pub(super) fn peek(&self) -> Option<(&K, &V)> {
19731961
let edge = self.cur_leaf_edge.as_ref()?;
19741962
edge.reborrow().next_kv().ok().map(Handle::into_kv)
19751963
}
19761964

1977-
/// Implementation of a typical `DrainFilter::next` method, given the predicate.
1965+
/// Implementation of a typical `ExtractIf::next` method, given the predicate.
19781966
pub(super) fn next<F, A: Allocator + Clone>(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)>
19791967
where
19801968
F: FnMut(&K, &mut V) -> bool,
@@ -2001,7 +1989,7 @@ impl<'a, K, V> DrainFilterInner<'a, K, V> {
20011989
None
20021990
}
20031991

2004-
/// Implementation of a typical `DrainFilter::size_hint` method.
1992+
/// Implementation of a typical `ExtractIf::size_hint` method.
20051993
pub(super) fn size_hint(&self) -> (usize, Option<usize>) {
20061994
// In most of the btree iterators, `self.length` is the number of elements
20071995
// yet to be visited. Here, it includes elements that were visited and that
@@ -2011,8 +1999,8 @@ impl<'a, K, V> DrainFilterInner<'a, K, V> {
20111999
}
20122000
}
20132001

2014-
#[unstable(feature = "btree_drain_filter", issue = "70530")]
2015-
impl<K, V, F> FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
2002+
#[unstable(feature = "btree_extract_if", issue = "70530")]
2003+
impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
20162004

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

0 commit comments

Comments
 (0)