remove drain-on-drop behavior from BTree{Set,Map}::DrainFilter and add #[must_use]

This commit is contained in:
The 8472 2022-11-15 19:51:24 +01:00
parent c0df1c8c43
commit b687e84aeb
4 changed files with 40 additions and 58 deletions

View File

@ -1132,7 +1132,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
K: Ord,
F: FnMut(&K, &mut V) -> bool,
{
self.drain_filter(|k, v| !f(k, v));
self.drain_filter(|k, v| !f(k, v)).for_each(drop);
}
/// Moves all elements from `other` into `self`, leaving `other` empty.
@ -1395,14 +1395,11 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
/// The iterator also lets you mutate the value of each element in the
/// closure, regardless of whether you choose to keep or remove it.
///
/// If the iterator is only partially consumed or not consumed at all, each
/// of the remaining elements is still subjected to the closure, which may
/// change its value and, by returning `true`, have the element removed and
/// dropped.
/// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating
/// or the iteration short-circuits, then the remaining elements will be retained.
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
///
/// It is unspecified how many more elements will be subjected to the
/// closure if a panic occurs in the closure, or a panic occurs while
/// dropping an element, or if the `DrainFilter` value is leaked.
/// [`retain`]: BTreeMap::retain
///
/// # Examples
///
@ -1901,6 +1898,7 @@ impl<K, V> Default for Values<'_, K, V> {
/// An iterator produced by calling `drain_filter` on BTreeMap.
#[unstable(feature = "btree_drain_filter", issue = "70530")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct DrainFilter<
'a,
K,
@ -1929,16 +1927,6 @@ pub(super) struct DrainFilterInner<'a, K, V> {
cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
}
#[unstable(feature = "btree_drain_filter", issue = "70530")]
impl<K, V, F, A: Allocator + Clone> Drop for DrainFilter<'_, K, V, F, A>
where
F: FnMut(&K, &mut V) -> bool,
{
fn drop(&mut self) {
self.for_each(drop);
}
}
#[unstable(feature = "btree_drain_filter", issue = "70530")]
impl<K, V, F> fmt::Debug for DrainFilter<'_, K, V, F>
where

View File

@ -947,7 +947,7 @@ mod test_drain_filter {
#[test]
fn empty() {
let mut map: BTreeMap<i32, i32> = BTreeMap::new();
map.drain_filter(|_, _| unreachable!("there's nothing to decide on"));
map.drain_filter(|_, _| unreachable!("there's nothing to decide on")).for_each(drop);
assert_eq!(map.height(), None);
map.check();
}
@ -1008,7 +1008,7 @@ mod test_drain_filter {
fn underfull_keeping_all() {
let pairs = (0..3).map(|i| (i, i));
let mut map = BTreeMap::from_iter(pairs);
map.drain_filter(|_, _| false);
map.drain_filter(|_, _| false).for_each(drop);
assert!(map.keys().copied().eq(0..3));
map.check();
}
@ -1018,7 +1018,7 @@ mod test_drain_filter {
let pairs = (0..3).map(|i| (i, i));
for doomed in 0..3 {
let mut map = BTreeMap::from_iter(pairs.clone());
map.drain_filter(|i, _| *i == doomed);
map.drain_filter(|i, _| *i == doomed).for_each(drop);
assert_eq!(map.len(), 2);
map.check();
}
@ -1029,7 +1029,7 @@ mod test_drain_filter {
let pairs = (0..3).map(|i| (i, i));
for sacred in 0..3 {
let mut map = BTreeMap::from_iter(pairs.clone());
map.drain_filter(|i, _| *i != sacred);
map.drain_filter(|i, _| *i != sacred).for_each(drop);
assert!(map.keys().copied().eq(sacred..=sacred));
map.check();
}
@ -1039,7 +1039,7 @@ mod test_drain_filter {
fn underfull_removing_all() {
let pairs = (0..3).map(|i| (i, i));
let mut map = BTreeMap::from_iter(pairs);
map.drain_filter(|_, _| true);
map.drain_filter(|_, _| true).for_each(drop);
assert!(map.is_empty());
map.check();
}
@ -1048,7 +1048,7 @@ mod test_drain_filter {
fn height_0_keeping_all() {
let pairs = (0..node::CAPACITY).map(|i| (i, i));
let mut map = BTreeMap::from_iter(pairs);
map.drain_filter(|_, _| false);
map.drain_filter(|_, _| false).for_each(drop);
assert!(map.keys().copied().eq(0..node::CAPACITY));
map.check();
}
@ -1058,7 +1058,7 @@ mod test_drain_filter {
let pairs = (0..node::CAPACITY).map(|i| (i, i));
for doomed in 0..node::CAPACITY {
let mut map = BTreeMap::from_iter(pairs.clone());
map.drain_filter(|i, _| *i == doomed);
map.drain_filter(|i, _| *i == doomed).for_each(drop);
assert_eq!(map.len(), node::CAPACITY - 1);
map.check();
}
@ -1069,7 +1069,7 @@ mod test_drain_filter {
let pairs = (0..node::CAPACITY).map(|i| (i, i));
for sacred in 0..node::CAPACITY {
let mut map = BTreeMap::from_iter(pairs.clone());
map.drain_filter(|i, _| *i != sacred);
map.drain_filter(|i, _| *i != sacred).for_each(drop);
assert!(map.keys().copied().eq(sacred..=sacred));
map.check();
}
@ -1079,7 +1079,7 @@ mod test_drain_filter {
fn height_0_removing_all() {
let pairs = (0..node::CAPACITY).map(|i| (i, i));
let mut map = BTreeMap::from_iter(pairs);
map.drain_filter(|_, _| true);
map.drain_filter(|_, _| true).for_each(drop);
assert!(map.is_empty());
map.check();
}
@ -1096,7 +1096,7 @@ mod test_drain_filter {
fn height_1_removing_all() {
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
let mut map = BTreeMap::from_iter(pairs);
map.drain_filter(|_, _| true);
map.drain_filter(|_, _| true).for_each(drop);
assert!(map.is_empty());
map.check();
}
@ -1106,7 +1106,7 @@ mod test_drain_filter {
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
for doomed in 0..MIN_INSERTS_HEIGHT_1 {
let mut map = BTreeMap::from_iter(pairs.clone());
map.drain_filter(|i, _| *i == doomed);
map.drain_filter(|i, _| *i == doomed).for_each(drop);
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_1 - 1);
map.check();
}
@ -1117,7 +1117,7 @@ mod test_drain_filter {
let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i));
for sacred in 0..MIN_INSERTS_HEIGHT_1 {
let mut map = BTreeMap::from_iter(pairs.clone());
map.drain_filter(|i, _| *i != sacred);
map.drain_filter(|i, _| *i != sacred).for_each(drop);
assert!(map.keys().copied().eq(sacred..=sacred));
map.check();
}
@ -1128,7 +1128,7 @@ mod test_drain_filter {
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
for doomed in (0..MIN_INSERTS_HEIGHT_2).step_by(12) {
let mut map = BTreeMap::from_iter(pairs.clone());
map.drain_filter(|i, _| *i == doomed);
map.drain_filter(|i, _| *i == doomed).for_each(drop);
assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2 - 1);
map.check();
}
@ -1139,7 +1139,7 @@ mod test_drain_filter {
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
for sacred in (0..MIN_INSERTS_HEIGHT_2).step_by(12) {
let mut map = BTreeMap::from_iter(pairs.clone());
map.drain_filter(|i, _| *i != sacred);
map.drain_filter(|i, _| *i != sacred).for_each(drop);
assert!(map.keys().copied().eq(sacred..=sacred));
map.check();
}
@ -1149,7 +1149,7 @@ mod test_drain_filter {
fn height_2_removing_all() {
let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
let mut map = BTreeMap::from_iter(pairs);
map.drain_filter(|_, _| true);
map.drain_filter(|_, _| true).for_each(drop);
assert!(map.is_empty());
map.check();
}
@ -1165,7 +1165,8 @@ mod test_drain_filter {
map.insert(b.spawn(Panic::InDrop), ());
map.insert(c.spawn(Panic::Never), ());
catch_unwind(move || drop(map.drain_filter(|dummy, _| dummy.query(true)))).unwrap_err();
catch_unwind(move || map.drain_filter(|dummy, _| dummy.query(true)).for_each(drop))
.unwrap_err();
assert_eq!(a.queried(), 1);
assert_eq!(b.queried(), 1);
@ -1186,8 +1187,10 @@ mod test_drain_filter {
map.insert(b.spawn(Panic::InQuery), ());
map.insert(c.spawn(Panic::InQuery), ());
catch_unwind(AssertUnwindSafe(|| drop(map.drain_filter(|dummy, _| dummy.query(true)))))
.unwrap_err();
catch_unwind(AssertUnwindSafe(|| {
map.drain_filter(|dummy, _| dummy.query(true)).for_each(drop)
}))
.unwrap_err();
assert_eq!(a.queried(), 1);
assert_eq!(b.queried(), 1);

View File

@ -999,7 +999,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
T: Ord,
F: FnMut(&T) -> bool,
{
self.drain_filter(|v| !f(v));
self.drain_filter(|v| !f(v)).for_each(drop);
}
/// Moves all elements from `other` into `self`, leaving `other` empty.
@ -1084,14 +1084,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
/// yielded. If the closure returns `false`, or panics, the element remains
/// in the set and will not be yielded.
///
/// If the iterator is only partially consumed or not consumed at all, each
/// of the remaining elements is still subjected to the closure and removed
/// and dropped if it returns `true`.
///
/// It is unspecified how many more elements will be subjected to the
/// closure if a panic occurs in the closure, or if a panic occurs while
/// dropping an element, or if the `DrainFilter` itself is leaked.
/// If the returned `DrainFilter` is not exhausted, e.g. because it is dropped without iterating
/// or the iteration short-circuits, then the remaining elements will be retained.
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
///
/// [`retain`]: BTreeSet::retain
/// # Examples
///
/// Splitting a set into even and odd values, reusing the original set:
@ -1277,6 +1274,7 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet<T, A> {
/// An iterator produced by calling `drain_filter` on BTreeSet.
#[unstable(feature = "btree_drain_filter", issue = "70530")]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct DrainFilter<
'a,
T,
@ -1292,16 +1290,6 @@ pub struct DrainFilter<
alloc: A,
}
#[unstable(feature = "btree_drain_filter", issue = "70530")]
impl<T, F, A: Allocator + Clone> Drop for DrainFilter<'_, T, F, A>
where
F: FnMut(&T) -> bool,
{
fn drop(&mut self) {
self.for_each(drop);
}
}
#[unstable(feature = "btree_drain_filter", issue = "70530")]
impl<T, F, A: Allocator + Clone> fmt::Debug for DrainFilter<'_, T, F, A>
where

View File

@ -370,8 +370,8 @@ fn test_drain_filter() {
let mut x = BTreeSet::from([1]);
let mut y = BTreeSet::from([1]);
x.drain_filter(|_| true);
y.drain_filter(|_| false);
x.drain_filter(|_| true).for_each(drop);
y.drain_filter(|_| false).for_each(drop);
assert_eq!(x.len(), 0);
assert_eq!(y.len(), 1);
}
@ -387,7 +387,7 @@ fn test_drain_filter_drop_panic_leak() {
set.insert(b.spawn(Panic::InDrop));
set.insert(c.spawn(Panic::Never));
catch_unwind(move || drop(set.drain_filter(|dummy| dummy.query(true)))).ok();
catch_unwind(move || set.drain_filter(|dummy| dummy.query(true)).for_each(drop)).ok();
assert_eq!(a.queried(), 1);
assert_eq!(b.queried(), 1);
@ -408,7 +408,10 @@ fn test_drain_filter_pred_panic_leak() {
set.insert(b.spawn(Panic::InQuery));
set.insert(c.spawn(Panic::InQuery));
catch_unwind(AssertUnwindSafe(|| drop(set.drain_filter(|dummy| dummy.query(true))))).ok();
catch_unwind(AssertUnwindSafe(|| {
set.drain_filter(|dummy| dummy.query(true)).for_each(drop)
}))
.ok();
assert_eq!(a.queried(), 1);
assert_eq!(b.queried(), 1);