diff --git a/Cargo.lock b/Cargo.lock index ef6b0a5959f..4eafda94037 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,6 +65,12 @@ dependencies = [ "rand_xorshift", ] +[[package]] +name = "allocator-api2" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f263788a35611fba42eb41ff811c5d0360c58b97402570312a350736e2542e" + [[package]] name = "ammonia" version = "3.2.0" @@ -1522,6 +1528,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ff8ae62cd3a9102e5637afc8452c55acf3844001bd5374e0b0bd7b6616c038" dependencies = [ "ahash 0.8.2", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "allocator-api2", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -4633,7 +4648,7 @@ dependencies = [ "core", "dlmalloc", "fortanix-sgx-abi", - "hashbrown 0.13.1", + "hashbrown 0.14.0", "hermit-abi 0.3.0", "libc", "miniz_oxide", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 4b52894c509..e6b05183886 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -21,7 +21,7 @@ libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-o compiler_builtins = { version = "0.1.92" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.13", default-features = false, features = ['rustc-dep-of-std'] } +hashbrown = { version = "0.14", default-features = false, features = ['rustc-dep-of-std'] } std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index c722bad2e4f..f3316d97c5f 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -623,28 +623,27 @@ pub fn drain(&mut self) -> Drain<'_, K, V> { /// 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 = (0..8).map(|x| (x, x)).collect(); - /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// let extracted: HashMap = map.extract_if(|k, _v| k % 2 == 0).collect(); /// - /// let mut evens = drained.keys().copied().collect::>(); + /// let mut evens = extracted.keys().copied().collect::>(); /// let mut odds = map.keys().copied().collect::>(); /// evens.sort(); /// odds.sort(); @@ -654,12 +653,12 @@ pub fn drain(&mut self) -> Drain<'_, K, V> { /// ``` #[inline] #[rustc_lint_query_instability] - #[unstable(feature = "hash_drain_filter", issue = "59618")] - pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, K, V, F> + #[unstable(feature = "hash_extract_if", issue = "59618")] + pub fn extract_if(&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 @@ pub(super) fn iter(&self) -> Iter<'_, 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl Iterator for DrainFilter<'_, K, V, F> +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl Iterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, { @@ -2496,16 +2496,16 @@ fn size_hint(&self) -> (usize, Option) { } } -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl 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() } } diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 6b89518e2e2..91a3776e7be 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 @@ fn eq_sorted>(self, other: I) -> bool { #[test] fn empty() { let mut map: HashMap = 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 @@ fn empty() { 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 @@ fn consuming_nothing() { 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 @@ fn mutating_and_keeping() { 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 @@ fn mutating_and_removing() { 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 @@ fn drop(&mut self) { let mut map = (0..3).map(|i| (i, D)).collect::>(); 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 @@ fn drop(&mut self) { let mut map = (0..3).map(|i| (i, D)).collect::>(); 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 @@ fn drop(&mut self) { let mut map = (0..3).map(|i| (i, D)).collect::>(); { - 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 ac906e682d5..5bf542629f0 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -262,25 +262,24 @@ pub fn drain(&mut self) -> Drain<'_, T> { /// 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 = (0..8).collect(); - /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// let extracted: HashSet = set.extract_if(|v| v % 2 == 0).collect(); /// - /// let mut evens = drained.into_iter().collect::>(); + /// let mut evens = extracted.into_iter().collect::>(); /// let mut odds = set.into_iter().collect::>(); /// evens.sort(); /// odds.sort(); @@ -290,12 +289,12 @@ pub fn drain(&mut self) -> Drain<'_, T> { /// ``` #[inline] #[rustc_lint_query_instability] - #[unstable(feature = "hash_drain_filter", issue = "59618")] - pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, T, F> + #[unstable(feature = "hash_extract_if", issue = "59618")] + pub fn extract_if(&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. @@ -1310,27 +1309,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 +1575,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl Iterator for DrainFilter<'_, K, F> +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl Iterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool, { @@ -1593,16 +1592,16 @@ fn size_hint(&self) -> (usize, Option) { } } -#[unstable(feature = "hash_drain_filter", issue = "59618")] -impl FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {} +#[unstable(feature = "hash_extract_if", issue = "59618")] +impl 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 941a0450cc7..7ac9eae67a0 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -418,18 +418,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 +446,20 @@ fn drop(&mut self) { let mut set = (0..3).map(|i| D(i)).collect::>(); 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 +474,11 @@ fn drop(&mut self) { 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(); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 9979dfbd56a..ac2056bcc85 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -108,6 +108,7 @@ "adler", "ahash", "aho-corasick", + "allocator-api2", // FIXME: only appears in Cargo.lock due to https://github.com/rust-lang/cargo/issues/10801 "annotate-snippets", "ansi_term", "ar_archive_writer",