summaryrefslogtreecommitdiffstats
path: root/library/std/src/collections
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /library/std/src/collections
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/std/src/collections')
-rw-r--r--library/std/src/collections/hash/map.rs60
-rw-r--r--library/std/src/collections/hash/map/tests.rs26
-rw-r--r--library/std/src/collections/hash/set.rs53
-rw-r--r--library/std/src/collections/hash/set/tests.rs42
4 files changed, 103 insertions, 78 deletions
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index c722bad2e..a083b6560 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -623,28 +623,27 @@ impl<K, V, S> HashMap<K, V, S> {
/// If the closure returns false, or panics, the element remains in the map and will not be
/// yielded.
///
- /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of
+ /// Note that `extract_if` lets you mutate every value in the filter 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 will still be subjected to the closure and removed and dropped if it returns true.
+ /// If the returned `ExtractIf` 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`]: HashMap::retain
///
/// # Examples
///
/// Splitting a map into even and odd keys, reusing the original map:
///
/// ```
- /// #![feature(hash_drain_filter)]
+ /// #![feature(hash_extract_if)]
/// use std::collections::HashMap;
///
/// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
- /// let drained: HashMap<i32, i32> = map.drain_filter(|k, _v| k % 2 == 0).collect();
+ /// let extracted: HashMap<i32, i32> = map.extract_if(|k, _v| k % 2 == 0).collect();
///
- /// let mut evens = drained.keys().copied().collect::<Vec<_>>();
+ /// let mut evens = extracted.keys().copied().collect::<Vec<_>>();
/// let mut odds = map.keys().copied().collect::<Vec<_>>();
/// evens.sort();
/// odds.sort();
@@ -654,12 +653,12 @@ impl<K, V, S> HashMap<K, V, S> {
/// ```
#[inline]
#[rustc_lint_query_instability]
- #[unstable(feature = "hash_drain_filter", issue = "59618")]
- pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
+ #[unstable(feature = "hash_extract_if", issue = "59618")]
+ pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
- DrainFilter { base: self.base.drain_filter(pred) }
+ ExtractIf { base: self.base.extract_if(pred) }
}
/// Retains only the elements specified by the predicate.
@@ -1578,28 +1577,29 @@ impl<'a, K, V> Drain<'a, K, V> {
/// A draining, filtering iterator over the entries of a `HashMap`.
///
-/// This `struct` is created by the [`drain_filter`] method on [`HashMap`].
+/// This `struct` is created by the [`extract_if`] method on [`HashMap`].
///
-/// [`drain_filter`]: HashMap::drain_filter
+/// [`extract_if`]: HashMap::extract_if
///
/// # Example
///
/// ```
-/// #![feature(hash_drain_filter)]
+/// #![feature(hash_extract_if)]
///
/// use std::collections::HashMap;
///
/// let mut map = HashMap::from([
/// ("a", 1),
/// ]);
-/// let iter = map.drain_filter(|_k, v| *v % 2 == 0);
+/// let iter = map.extract_if(|_k, v| *v % 2 == 0);
/// ```
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-pub struct DrainFilter<'a, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+pub struct ExtractIf<'a, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
- base: base::DrainFilter<'a, K, V, F>,
+ base: base::ExtractIf<'a, K, V, F>,
}
/// A mutable iterator over the values of a `HashMap`.
@@ -2479,8 +2479,8 @@ where
}
}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, V, F> Iterator for DrainFilter<'_, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, V, F> Iterator for ExtractIf<'_, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
@@ -2496,16 +2496,16 @@ where
}
}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, V, F> FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("DrainFilter").finish_non_exhaustive()
+ f.debug_struct("ExtractIf").finish_non_exhaustive()
}
}
@@ -2543,12 +2543,12 @@ impl<'a, K, V> Entry<'a, K, V> {
/// ```
/// use std::collections::HashMap;
///
- /// let mut map: HashMap<&str, String> = HashMap::new();
- /// let s = "hoho".to_string();
+ /// let mut map = HashMap::new();
+ /// let value = "hoho";
///
- /// map.entry("poneyland").or_insert_with(|| s);
+ /// map.entry("poneyland").or_insert_with(|| value);
///
- /// assert_eq!(map["poneyland"], "hoho".to_string());
+ /// assert_eq!(map["poneyland"], "hoho");
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 6b89518e2..91a3776e7 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -944,7 +944,7 @@ fn test_raw_entry() {
}
}
-mod test_drain_filter {
+mod test_extract_if {
use super::*;
use crate::panic::{catch_unwind, AssertUnwindSafe};
@@ -968,7 +968,7 @@ mod test_drain_filter {
#[test]
fn empty() {
let mut map: HashMap<i32, i32> = HashMap::new();
- map.drain_filter(|_, _| unreachable!("there's nothing to decide on"));
+ map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop);
assert!(map.is_empty());
}
@@ -976,7 +976,7 @@ mod test_drain_filter {
fn consuming_nothing() {
let pairs = (0..3).map(|i| (i, i));
let mut map: HashMap<_, _> = pairs.collect();
- assert!(map.drain_filter(|_, _| false).eq_sorted(crate::iter::empty()));
+ assert!(map.extract_if(|_, _| false).eq_sorted(crate::iter::empty()));
assert_eq!(map.len(), 3);
}
@@ -984,7 +984,7 @@ mod test_drain_filter {
fn consuming_all() {
let pairs = (0..3).map(|i| (i, i));
let mut map: HashMap<_, _> = pairs.clone().collect();
- assert!(map.drain_filter(|_, _| true).eq_sorted(pairs));
+ assert!(map.extract_if(|_, _| true).eq_sorted(pairs));
assert!(map.is_empty());
}
@@ -993,7 +993,7 @@ mod test_drain_filter {
let pairs = (0..3).map(|i| (i, i));
let mut map: HashMap<_, _> = pairs.collect();
assert!(
- map.drain_filter(|_, v| {
+ map.extract_if(|_, v| {
*v += 6;
false
})
@@ -1008,7 +1008,7 @@ mod test_drain_filter {
let pairs = (0..3).map(|i| (i, i));
let mut map: HashMap<_, _> = pairs.collect();
assert!(
- map.drain_filter(|_, v| {
+ map.extract_if(|_, v| {
*v += 6;
true
})
@@ -1034,14 +1034,15 @@ mod test_drain_filter {
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
catch_unwind(move || {
- drop(map.drain_filter(|_, _| {
+ map.extract_if(|_, _| {
PREDS.fetch_add(1, Ordering::SeqCst);
true
- }))
+ })
+ .for_each(drop)
})
.unwrap_err();
- assert_eq!(PREDS.load(Ordering::SeqCst), 3);
+ assert_eq!(PREDS.load(Ordering::SeqCst), 2);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
}
@@ -1060,10 +1061,11 @@ mod test_drain_filter {
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
catch_unwind(AssertUnwindSafe(|| {
- drop(map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
+ map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
0 => true,
_ => panic!(),
- }))
+ })
+ .for_each(drop)
}))
.unwrap_err();
@@ -1088,7 +1090,7 @@ mod test_drain_filter {
let mut map = (0..3).map(|i| (i, D)).collect::<HashMap<_, _>>();
{
- let mut it = map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
+ let mut it = map.extract_if(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) {
0 => true,
_ => panic!(),
});
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index ac906e682..ec59634df 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -262,25 +262,24 @@ impl<T, S> HashSet<T, S> {
/// If the closure returns false, the value will remain in the list and will not be yielded
/// by the iterator.
///
- /// If the iterator is only partially consumed or not consumed at all, each of the remaining
- /// values will still be subjected to the closure and removed and dropped if it returns true.
+ /// If the returned `ExtractIf` 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 values will be subjected to the closure
- /// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the
- /// `DrainFilter` itself is leaked.
+ /// [`retain`]: HashSet::retain
///
/// # Examples
///
/// Splitting a set into even and odd values, reusing the original set:
///
/// ```
- /// #![feature(hash_drain_filter)]
+ /// #![feature(hash_extract_if)]
/// use std::collections::HashSet;
///
/// let mut set: HashSet<i32> = (0..8).collect();
- /// let drained: HashSet<i32> = set.drain_filter(|v| v % 2 == 0).collect();
+ /// let extracted: HashSet<i32> = set.extract_if(|v| v % 2 == 0).collect();
///
- /// let mut evens = drained.into_iter().collect::<Vec<_>>();
+ /// let mut evens = extracted.into_iter().collect::<Vec<_>>();
/// let mut odds = set.into_iter().collect::<Vec<_>>();
/// evens.sort();
/// odds.sort();
@@ -290,12 +289,12 @@ impl<T, S> HashSet<T, S> {
/// ```
#[inline]
#[rustc_lint_query_instability]
- #[unstable(feature = "hash_drain_filter", issue = "59618")]
- pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
+ #[unstable(feature = "hash_extract_if", issue = "59618")]
+ pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, T, F>
where
F: FnMut(&T) -> bool,
{
- DrainFilter { base: self.base.drain_filter(pred) }
+ ExtractIf { base: self.base.extract_if(pred) }
}
/// Retains only the elements specified by the predicate.
@@ -868,7 +867,9 @@ where
/// Returns whether the value was newly inserted. That is:
///
/// - If the set did not previously contain this value, `true` is returned.
- /// - If the set already contained this value, `false` is returned.
+ /// - If the set already contained this value, `false` is returned,
+ /// and the set is not modified: original value is not replaced,
+ /// and the value passed as argument is dropped.
///
/// # Examples
///
@@ -1310,27 +1311,27 @@ pub struct Drain<'a, K: 'a> {
/// A draining, filtering iterator over the items of a `HashSet`.
///
-/// This `struct` is created by the [`drain_filter`] method on [`HashSet`].
+/// This `struct` is created by the [`extract_if`] method on [`HashSet`].
///
-/// [`drain_filter`]: HashSet::drain_filter
+/// [`extract_if`]: HashSet::extract_if
///
/// # Examples
///
/// ```
-/// #![feature(hash_drain_filter)]
+/// #![feature(hash_extract_if)]
///
/// use std::collections::HashSet;
///
/// let mut a = HashSet::from([1, 2, 3]);
///
-/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0);
+/// let mut extract_ifed = a.extract_if(|v| v % 2 == 0);
/// ```
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-pub struct DrainFilter<'a, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+pub struct ExtractIf<'a, K, F>
where
F: FnMut(&K) -> bool,
{
- base: base::DrainFilter<'a, K, F>,
+ base: base::ExtractIf<'a, K, F>,
}
/// A lazy iterator producing elements in the intersection of `HashSet`s.
@@ -1576,8 +1577,8 @@ impl<K: fmt::Debug> fmt::Debug for Drain<'_, K> {
}
}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, F> Iterator for DrainFilter<'_, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, F> Iterator for ExtractIf<'_, K, F>
where
F: FnMut(&K) -> bool,
{
@@ -1593,16 +1594,16 @@ where
}
}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<K, F> FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {}
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<K, F> FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {}
-#[unstable(feature = "hash_drain_filter", issue = "59618")]
-impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F>
+#[unstable(feature = "hash_extract_if", issue = "59618")]
+impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F>
where
F: FnMut(&K) -> bool,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("DrainFilter").finish_non_exhaustive()
+ f.debug_struct("ExtractIf").finish_non_exhaustive()
}
}
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
index 941a0450c..e0cd80b44 100644
--- a/library/std/src/collections/hash/set/tests.rs
+++ b/library/std/src/collections/hash/set/tests.rs
@@ -3,6 +3,7 @@ use super::HashSet;
use crate::panic::{catch_unwind, AssertUnwindSafe};
use crate::sync::atomic::{AtomicU32, Ordering};
+use crate::sync::Arc;
#[test]
fn test_zero_capacities() {
@@ -418,18 +419,18 @@ fn test_retain() {
}
#[test]
-fn test_drain_filter() {
+fn test_extract_if() {
let mut x: HashSet<_> = [1].iter().copied().collect();
let mut y: HashSet<_> = [1].iter().copied().collect();
- x.drain_filter(|_| true);
- y.drain_filter(|_| false);
+ x.extract_if(|_| true).for_each(drop);
+ y.extract_if(|_| false).for_each(drop);
assert_eq!(x.len(), 0);
assert_eq!(y.len(), 1);
}
#[test]
-fn test_drain_filter_drop_panic_leak() {
+fn test_extract_if_drop_panic_leak() {
static PREDS: AtomicU32 = AtomicU32::new(0);
static DROPS: AtomicU32 = AtomicU32::new(0);
@@ -446,19 +447,20 @@ fn test_drain_filter_drop_panic_leak() {
let mut set = (0..3).map(|i| D(i)).collect::<HashSet<_>>();
catch_unwind(move || {
- drop(set.drain_filter(|_| {
+ set.extract_if(|_| {
PREDS.fetch_add(1, Ordering::SeqCst);
true
- }))
+ })
+ .for_each(drop)
})
.ok();
- assert_eq!(PREDS.load(Ordering::SeqCst), 3);
+ assert_eq!(PREDS.load(Ordering::SeqCst), 2);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
}
#[test]
-fn test_drain_filter_pred_panic_leak() {
+fn test_extract_if_pred_panic_leak() {
static PREDS: AtomicU32 = AtomicU32::new(0);
static DROPS: AtomicU32 = AtomicU32::new(0);
@@ -473,10 +475,11 @@ fn test_drain_filter_pred_panic_leak() {
let mut set: HashSet<_> = (0..3).map(|_| D).collect();
catch_unwind(AssertUnwindSafe(|| {
- drop(set.drain_filter(|_| match PREDS.fetch_add(1, Ordering::SeqCst) {
+ set.extract_if(|_| match PREDS.fetch_add(1, Ordering::SeqCst) {
0 => true,
_ => panic!(),
- }))
+ })
+ .for_each(drop)
}))
.ok();
@@ -502,3 +505,22 @@ fn const_with_hasher() {
const X: HashSet<(), ()> = HashSet::with_hasher(());
assert_eq!(X.len(), 0);
}
+
+#[test]
+fn test_insert_does_not_overwrite_the_value() {
+ let first_value = Arc::new(17);
+ let second_value = Arc::new(17);
+
+ let mut set = HashSet::new();
+ let inserted = set.insert(first_value.clone());
+ assert!(inserted);
+
+ let inserted = set.insert(second_value);
+ assert!(!inserted);
+
+ assert!(
+ Arc::ptr_eq(set.iter().next().unwrap(), &first_value),
+ "Insert must not overwrite the value, so the contained value pointer \
+ must be the same as first value pointer we inserted"
+ );
+}