diff options
Diffstat (limited to 'library/alloc')
| -rw-r--r-- | library/alloc/Cargo.toml | 3 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/map.rs | 76 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/map/tests.rs | 74 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/set.rs | 42 | ||||
| -rw-r--r-- | library/alloc/src/collections/btree/set/tests.rs | 12 | ||||
| -rw-r--r-- | library/alloc/src/collections/linked_list.rs | 12 | ||||
| -rw-r--r-- | library/alloc/src/collections/vec_deque/mod.rs | 33 | ||||
| -rw-r--r-- | library/alloc/src/ffi/c_str.rs | 2 | ||||
| -rw-r--r-- | library/alloc/src/lib.rs | 2 | ||||
| -rw-r--r-- | library/alloc/src/slice.rs | 13 | ||||
| -rw-r--r-- | library/alloc/src/str.rs | 5 | ||||
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 46 | ||||
| -rw-r--r-- | library/alloc/src/vec/peek_mut.rs | 55 |
13 files changed, 279 insertions, 96 deletions
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 9d0d957226d..017c790ecac 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.159", features = ['rustc-dep-of-std'] } +compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["rustc-dep-of-std"] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] @@ -32,7 +32,6 @@ optimize_for_size = ["core/optimize_for_size"] [lints.rust.unexpected_cfgs] level = "warn" check-cfg = [ - 'cfg(bootstrap)', 'cfg(no_global_oom_handling)', 'cfg(no_rc)', 'cfg(no_sync)', diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 5ca32ed741a..17c16e4aaff 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1151,7 +1151,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { K: Ord, F: FnMut(&K, &mut V) -> bool, { - self.extract_if(|k, v| !f(k, v)).for_each(drop); + self.extract_if(.., |k, v| !f(k, v)).for_each(drop); } /// Moves all elements from `other` into `self`, leaving `other` empty. @@ -1397,11 +1397,13 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { } } - /// Creates an iterator that visits all elements (key-value pairs) in - /// ascending key order and uses a closure to determine if an element should - /// be removed. If the closure returns `true`, the element is removed from - /// the map and yielded. If the closure returns `false`, or panics, the - /// element remains in the map and will not be yielded. + /// Creates an iterator that visits elements (key-value pairs) in the specified range in + /// ascending key order and uses a closure to determine if an element + /// should be removed. + /// + /// If the closure returns `true`, the element is removed from the map and + /// yielded. If the closure returns `false`, or panics, the element remains + /// in the map and will not be yielded. /// /// The iterator also lets you mutate the value of each element in the /// closure, regardless of whether you choose to keep or remove it. @@ -1414,40 +1416,49 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { /// /// # Examples /// - /// Splitting a map into even and odd keys, reusing the original map: - /// /// ``` /// #![feature(btree_extract_if)] /// use std::collections::BTreeMap; /// + /// // Splitting a map into even and odd keys, reusing the original map: /// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect(); - /// let evens: BTreeMap<_, _> = map.extract_if(|k, _v| k % 2 == 0).collect(); + /// let evens: BTreeMap<_, _> = map.extract_if(.., |k, _v| k % 2 == 0).collect(); /// let odds = map; /// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]); /// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]); + /// + /// // Splitting a map into low and high halves, reusing the original map: + /// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect(); + /// let low: BTreeMap<_, _> = map.extract_if(0..4, |_k, _v| true).collect(); + /// let high = map; + /// assert_eq!(low.keys().copied().collect::<Vec<_>>(), [0, 1, 2, 3]); + /// assert_eq!(high.keys().copied().collect::<Vec<_>>(), [4, 5, 6, 7]); /// ``` #[unstable(feature = "btree_extract_if", issue = "70530")] - pub fn extract_if<F>(&mut self, pred: F) -> ExtractIf<'_, K, V, F, A> + 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, { - let (inner, alloc) = self.extract_if_inner(); + let (inner, alloc) = self.extract_if_inner(range); ExtractIf { pred, inner, alloc } } - pub(super) fn extract_if_inner(&mut self) -> (ExtractIfInner<'_, K, V>, A) + pub(super) fn extract_if_inner<R>(&mut self, range: R) -> (ExtractIfInner<'_, K, V, R>, A) where K: Ord, + R: RangeBounds<K>, { if let Some(root) = self.root.as_mut() { let (root, dormant_root) = DormantMutRef::new(root); - let front = root.borrow_mut().first_leaf_edge(); + let first = root.borrow_mut().lower_bound(SearchBound::from_range(range.start_bound())); ( ExtractIfInner { length: &mut self.length, dormant_root: Some(dormant_root), - cur_leaf_edge: Some(front), + cur_leaf_edge: Some(first), + range, }, (*self.alloc).clone(), ) @@ -1457,6 +1468,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { length: &mut self.length, dormant_root: None, cur_leaf_edge: None, + range, }, (*self.alloc).clone(), ) @@ -1915,18 +1927,19 @@ pub struct ExtractIf< 'a, K, V, + R, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, > { pred: F, - inner: ExtractIfInner<'a, K, V>, + inner: ExtractIfInner<'a, K, V, R>, /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`. alloc: A, } /// Most of the implementation of ExtractIf are generic over the type /// of the predicate, thus also serving for BTreeSet::ExtractIf. -pub(super) struct ExtractIfInner<'a, K, V> { +pub(super) struct ExtractIfInner<'a, K, V, R> { /// Reference to the length field in the borrowed map, updated live. length: &'a mut usize, /// Buried reference to the root field in the borrowed map. @@ -1936,10 +1949,13 @@ pub(super) struct ExtractIfInner<'a, K, V> { /// Empty if the map has no root, if iteration went beyond the last leaf edge, /// or if a panic occurred in the predicate. cur_leaf_edge: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>, + /// Range over which iteration was requested. We don't need the left side, but we + /// can't extract the right side without requiring K: Clone. + range: R, } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<K, V, F, A> fmt::Debug for ExtractIf<'_, K, V, F, A> +impl<K, V, R, F, A> fmt::Debug for ExtractIf<'_, K, V, R, F, A> where K: fmt::Debug, V: fmt::Debug, @@ -1951,8 +1967,10 @@ where } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<K, V, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, F, A> +impl<K, V, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, R, F, A> where + K: PartialOrd, + R: RangeBounds<K>, F: FnMut(&K, &mut V) -> bool, { type Item = (K, V); @@ -1966,7 +1984,7 @@ where } } -impl<'a, K, V> ExtractIfInner<'a, K, V> { +impl<'a, K, V, R> ExtractIfInner<'a, K, V, R> { /// Allow Debug implementations to predict the next element. pub(super) fn peek(&self) -> Option<(&K, &V)> { let edge = self.cur_leaf_edge.as_ref()?; @@ -1976,10 +1994,22 @@ impl<'a, K, V> ExtractIfInner<'a, K, V> { /// Implementation of a typical `ExtractIf::next` method, given the predicate. pub(super) fn next<F, A: Allocator + Clone>(&mut self, pred: &mut F, alloc: A) -> Option<(K, V)> where + K: PartialOrd, + R: RangeBounds<K>, F: FnMut(&K, &mut V) -> bool, { while let Ok(mut kv) = self.cur_leaf_edge.take()?.next_kv() { let (k, v) = kv.kv_mut(); + + // On creation, we navigated directly to the left bound, so we need only check the + // right bound here to decide whether to stop. + match self.range.end_bound() { + Bound::Included(ref end) if (*k).le(end) => (), + Bound::Excluded(ref end) if (*k).lt(end) => (), + Bound::Unbounded => (), + _ => return None, + } + if pred(k, v) { *self.length -= 1; let (kv, pos) = kv.remove_kv_tracking( @@ -2011,7 +2041,13 @@ impl<'a, K, V> ExtractIfInner<'a, K, V> { } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<K, V, F> FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} +impl<K, V, R, F> FusedIterator for ExtractIf<'_, K, V, R, F> +where + K: PartialOrd, + R: RangeBounds<K>, + F: FnMut(&K, &mut V) -> bool, +{ +} #[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for Range<'a, K, V> { diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 5975134382e..79879d31d3d 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -944,7 +944,7 @@ mod test_extract_if { #[test] fn empty() { let mut map: BTreeMap<i32, i32> = BTreeMap::new(); - map.extract_if(|_, _| unreachable!("there's nothing to decide on")).for_each(drop); + map.extract_if(.., |_, _| unreachable!("there's nothing to decide on")).for_each(drop); assert_eq!(map.height(), None); map.check(); } @@ -954,7 +954,7 @@ mod test_extract_if { fn consumed_keeping_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - assert!(map.extract_if(|_, _| false).eq(iter::empty())); + assert!(map.extract_if(.., |_, _| false).eq(iter::empty())); map.check(); } @@ -963,18 +963,42 @@ mod test_extract_if { fn consumed_removing_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs.clone()); - assert!(map.extract_if(|_, _| true).eq(pairs)); + assert!(map.extract_if(.., |_, _| true).eq(pairs)); assert!(map.is_empty()); map.check(); } + #[test] + fn consumed_removing_some() { + let pairs = (0..3).map(|i| (i, i)); + let map = BTreeMap::from_iter(pairs); + for x in 0..3 { + for y in 0..3 { + let mut map = map.clone(); + assert!(map.extract_if(x..y, |_, _| true).eq((x..y).map(|i| (i, i)))); + for i in 0..3 { + assert_ne!(map.contains_key(&i), (x..y).contains(&i)); + } + } + } + for x in 0..3 { + for y in 0..2 { + let mut map = map.clone(); + assert!(map.extract_if(x..=y, |_, _| true).eq((x..=y).map(|i| (i, i)))); + for i in 0..3 { + assert_ne!(map.contains_key(&i), (x..=y).contains(&i)); + } + } + } + } + // Explicitly consumes the iterator and modifies values through it. #[test] fn mutating_and_keeping() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); assert!( - map.extract_if(|_, v| { + map.extract_if(.., |_, v| { *v += 6; false }) @@ -991,7 +1015,7 @@ mod test_extract_if { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); assert!( - map.extract_if(|_, v| { + map.extract_if(.., |_, v| { *v += 6; true }) @@ -1005,7 +1029,7 @@ mod test_extract_if { fn underfull_keeping_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.extract_if(|_, _| false).for_each(drop); + map.extract_if(.., |_, _| false).for_each(drop); assert!(map.keys().copied().eq(0..3)); map.check(); } @@ -1015,7 +1039,7 @@ mod test_extract_if { let pairs = (0..3).map(|i| (i, i)); for doomed in 0..3 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.extract_if(|i, _| *i == doomed).for_each(drop); + map.extract_if(.., |i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), 2); map.check(); } @@ -1026,7 +1050,7 @@ mod test_extract_if { let pairs = (0..3).map(|i| (i, i)); for sacred in 0..3 { let mut map = BTreeMap::from_iter(pairs.clone()); - map.extract_if(|i, _| *i != sacred).for_each(drop); + map.extract_if(.., |i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1036,7 +1060,7 @@ mod test_extract_if { fn underfull_removing_all() { let pairs = (0..3).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.extract_if(|_, _| true).for_each(drop); + map.extract_if(.., |_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1045,7 +1069,7 @@ mod test_extract_if { fn height_0_keeping_all() { let pairs = (0..node::CAPACITY).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.extract_if(|_, _| false).for_each(drop); + map.extract_if(.., |_, _| false).for_each(drop); assert!(map.keys().copied().eq(0..node::CAPACITY)); map.check(); } @@ -1055,7 +1079,7 @@ mod test_extract_if { let pairs = (0..node::CAPACITY).map(|i| (i, i)); for doomed in 0..node::CAPACITY { let mut map = BTreeMap::from_iter(pairs.clone()); - map.extract_if(|i, _| *i == doomed).for_each(drop); + map.extract_if(.., |i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), node::CAPACITY - 1); map.check(); } @@ -1066,7 +1090,7 @@ mod test_extract_if { let pairs = (0..node::CAPACITY).map(|i| (i, i)); for sacred in 0..node::CAPACITY { let mut map = BTreeMap::from_iter(pairs.clone()); - map.extract_if(|i, _| *i != sacred).for_each(drop); + map.extract_if(.., |i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1076,7 +1100,7 @@ mod test_extract_if { fn height_0_removing_all() { let pairs = (0..node::CAPACITY).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.extract_if(|_, _| true).for_each(drop); + map.extract_if(.., |_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1084,7 +1108,7 @@ mod test_extract_if { #[test] fn height_0_keeping_half() { let mut map = BTreeMap::from_iter((0..16).map(|i| (i, i))); - assert_eq!(map.extract_if(|i, _| *i % 2 == 0).count(), 8); + assert_eq!(map.extract_if(.., |i, _| *i % 2 == 0).count(), 8); assert_eq!(map.len(), 8); map.check(); } @@ -1093,7 +1117,7 @@ mod test_extract_if { fn height_1_removing_all() { let pairs = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.extract_if(|_, _| true).for_each(drop); + map.extract_if(.., |_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1103,7 +1127,7 @@ mod test_extract_if { 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.extract_if(|i, _| *i == doomed).for_each(drop); + map.extract_if(.., |i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), MIN_INSERTS_HEIGHT_1 - 1); map.check(); } @@ -1114,7 +1138,7 @@ mod test_extract_if { 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.extract_if(|i, _| *i != sacred).for_each(drop); + map.extract_if(.., |i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1125,7 +1149,7 @@ mod test_extract_if { 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.extract_if(|i, _| *i == doomed).for_each(drop); + map.extract_if(.., |i, _| *i == doomed).for_each(drop); assert_eq!(map.len(), MIN_INSERTS_HEIGHT_2 - 1); map.check(); } @@ -1136,7 +1160,7 @@ mod test_extract_if { 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.extract_if(|i, _| *i != sacred).for_each(drop); + map.extract_if(.., |i, _| *i != sacred).for_each(drop); assert!(map.keys().copied().eq(sacred..=sacred)); map.check(); } @@ -1146,7 +1170,7 @@ mod test_extract_if { fn height_2_removing_all() { let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)); let mut map = BTreeMap::from_iter(pairs); - map.extract_if(|_, _| true).for_each(drop); + map.extract_if(.., |_, _| true).for_each(drop); assert!(map.is_empty()); map.check(); } @@ -1162,7 +1186,7 @@ mod test_extract_if { map.insert(b.spawn(Panic::InDrop), ()); map.insert(c.spawn(Panic::Never), ()); - catch_unwind(move || map.extract_if(|dummy, _| dummy.query(true)).for_each(drop)) + catch_unwind(move || map.extract_if(.., |dummy, _| dummy.query(true)).for_each(drop)) .unwrap_err(); assert_eq!(a.queried(), 1); @@ -1185,7 +1209,7 @@ mod test_extract_if { map.insert(c.spawn(Panic::InQuery), ()); catch_unwind(AssertUnwindSafe(|| { - map.extract_if(|dummy, _| dummy.query(true)).for_each(drop) + map.extract_if(.., |dummy, _| dummy.query(true)).for_each(drop) })) .unwrap_err(); @@ -1214,7 +1238,7 @@ mod test_extract_if { map.insert(c.spawn(Panic::InQuery), ()); { - let mut it = map.extract_if(|dummy, _| dummy.query(true)); + let mut it = map.extract_if(.., |dummy, _| dummy.query(true)); catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); // Iterator behavior after a panic is explicitly unspecified, // so this is just the current implementation: @@ -1658,7 +1682,7 @@ fn assert_sync() { } fn extract_if<T: Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Sync + '_ { - v.extract_if(|_, _| false) + v.extract_if(.., |_, _| false) } fn iter<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ { @@ -1727,7 +1751,7 @@ fn assert_send() { } fn extract_if<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ { - v.extract_if(|_, _| false) + v.extract_if(.., |_, _| false) } fn iter<T: Send + Sync>(v: &BTreeMap<T, T>) -> impl Send + '_ { diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 343934680b8..aa9e5fce1d4 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1109,7 +1109,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { T: Ord, F: FnMut(&T) -> bool, { - self.extract_if(|v| !f(v)).for_each(drop); + self.extract_if(.., |v| !f(v)).for_each(drop); } /// Moves all elements from `other` into `self`, leaving `other` empty. @@ -1187,7 +1187,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { BTreeSet { map: self.map.split_off(value) } } - /// Creates an iterator that visits all elements in ascending order and + /// Creates an iterator that visits elements in the specified range in ascending order and /// uses a closure to determine if an element should be removed. /// /// If the closure returns `true`, the element is removed from the set and @@ -1201,25 +1201,32 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { /// [`retain`]: BTreeSet::retain /// # Examples /// - /// Splitting a set into even and odd values, reusing the original set: - /// /// ``` /// #![feature(btree_extract_if)] /// use std::collections::BTreeSet; /// + /// // Splitting a set into even and odd values, reusing the original set: /// let mut set: BTreeSet<i32> = (0..8).collect(); - /// let evens: BTreeSet<_> = set.extract_if(|v| v % 2 == 0).collect(); + /// let evens: BTreeSet<_> = set.extract_if(.., |v| v % 2 == 0).collect(); /// let odds = set; /// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![0, 2, 4, 6]); /// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7]); + /// + /// // Splitting a set into low and high halves, reusing the original set: + /// let mut set: BTreeSet<i32> = (0..8).collect(); + /// let low: BTreeSet<_> = set.extract_if(0..4, |_v| true).collect(); + /// let high = set; + /// assert_eq!(low.into_iter().collect::<Vec<_>>(), [0, 1, 2, 3]); + /// assert_eq!(high.into_iter().collect::<Vec<_>>(), [4, 5, 6, 7]); /// ``` #[unstable(feature = "btree_extract_if", issue = "70530")] - pub fn extract_if<'a, F>(&'a mut self, pred: F) -> ExtractIf<'a, T, F, A> + pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, T, R, F, A> where T: Ord, - F: 'a + FnMut(&T) -> bool, + R: RangeBounds<T>, + F: FnMut(&T) -> bool, { - let (inner, alloc) = self.map.extract_if_inner(); + let (inner, alloc) = self.map.extract_if_inner(range); ExtractIf { pred, inner, alloc } } @@ -1554,17 +1561,18 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet<T, A> { pub struct ExtractIf< 'a, T, + R, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, > { pred: F, - inner: super::map::ExtractIfInner<'a, T, SetValZST>, + inner: super::map::ExtractIfInner<'a, T, SetValZST, R>, /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`. alloc: A, } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<T, F, A> fmt::Debug for ExtractIf<'_, T, F, A> +impl<T, R, F, A> fmt::Debug for ExtractIf<'_, T, R, F, A> where T: fmt::Debug, A: Allocator + Clone, @@ -1577,9 +1585,11 @@ where } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<'a, T, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, F, A> +impl<T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A> where - F: 'a + FnMut(&T) -> bool, + T: PartialOrd, + R: RangeBounds<T>, + F: FnMut(&T) -> bool, { type Item = T; @@ -1595,7 +1605,13 @@ where } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl<T, F, A: Allocator + Clone> FusedIterator for ExtractIf<'_, T, F, A> where F: FnMut(&T) -> bool {} +impl<T, R, F, A: Allocator + Clone> FusedIterator for ExtractIf<'_, T, R, F, A> +where + T: PartialOrd, + R: RangeBounds<T>, + F: FnMut(&T) -> bool, +{ +} #[stable(feature = "rust1", since = "1.0.0")] impl<T: Ord, A: Allocator + Clone> Extend<T> for BTreeSet<T, A> { diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index d538ef707eb..85c9a98c461 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -368,8 +368,8 @@ fn test_extract_if() { let mut x = BTreeSet::from([1]); let mut y = BTreeSet::from([1]); - x.extract_if(|_| true).for_each(drop); - y.extract_if(|_| false).for_each(drop); + x.extract_if(.., |_| true).for_each(drop); + y.extract_if(.., |_| false).for_each(drop); assert_eq!(x.len(), 0); assert_eq!(y.len(), 1); } @@ -385,7 +385,7 @@ fn test_extract_if_drop_panic_leak() { set.insert(b.spawn(Panic::InDrop)); set.insert(c.spawn(Panic::Never)); - catch_unwind(move || set.extract_if(|dummy| dummy.query(true)).for_each(drop)).ok(); + catch_unwind(move || set.extract_if(.., |dummy| dummy.query(true)).for_each(drop)).ok(); assert_eq!(a.queried(), 1); assert_eq!(b.queried(), 1); @@ -406,7 +406,7 @@ fn test_extract_if_pred_panic_leak() { set.insert(b.spawn(Panic::InQuery)); set.insert(c.spawn(Panic::InQuery)); - catch_unwind(AssertUnwindSafe(|| set.extract_if(|dummy| dummy.query(true)).for_each(drop))) + catch_unwind(AssertUnwindSafe(|| set.extract_if(.., |dummy| dummy.query(true)).for_each(drop))) .ok(); assert_eq!(a.queried(), 1); @@ -605,7 +605,7 @@ fn assert_sync() { } fn extract_if<T: Sync + Ord>(v: &mut BTreeSet<T>) -> impl Sync + '_ { - v.extract_if(|_| false) + v.extract_if(.., |_| false) } fn difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ { @@ -644,7 +644,7 @@ fn assert_send() { } fn extract_if<T: Send + Ord>(v: &mut BTreeSet<T>) -> impl Send + '_ { - v.extract_if(|_| false) + v.extract_if(.., |_| false) } fn difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ { diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 00e2805d11f..d03c1969b5b 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1124,20 +1124,20 @@ impl<T, A: Allocator> LinkedList<T, A> { /// Creates an iterator which uses a closure to determine if an element should be removed. /// - /// If the closure returns true, then the element is removed and yielded. - /// If the closure returns false, the element will remain in the list and will not be yielded - /// by the iterator. + /// If the closure returns `true`, the element is removed from the list and + /// yielded. If the closure returns `false`, or panics, the element remains + /// in the list and will not be yielded. /// /// 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 `extract_if().for_each(drop)` if you do not need the returned iterator. /// - /// Note that `extract_if` lets you mutate every element in the filter closure, regardless of - /// whether you choose to keep or remove it. + /// The iterator also lets you mutate the value of each element in the + /// closure, regardless of whether you choose to keep or remove it. /// /// # Examples /// - /// Splitting a list into evens and odds, reusing the original list: + /// Splitting a list into even and odd values, reusing the original list: /// /// ``` /// use std::collections::LinkedList; diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 712f38a76c0..08b1828ff00 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1312,6 +1312,8 @@ impl<T, A: Allocator> VecDeque<T, A> { /// /// If [`make_contiguous`] was previously called, all elements of the /// deque will be in the first slice and the second slice will be empty. + /// Otherwise, the exact split point depends on implementation details + /// and is not guaranteed. /// /// [`make_contiguous`]: VecDeque::make_contiguous /// @@ -1326,12 +1328,18 @@ impl<T, A: Allocator> VecDeque<T, A> { /// deque.push_back(1); /// deque.push_back(2); /// - /// assert_eq!(deque.as_slices(), (&[0, 1, 2][..], &[][..])); + /// let expected = [0, 1, 2]; + /// let (front, back) = deque.as_slices(); + /// assert_eq!(&expected[..front.len()], front); + /// assert_eq!(&expected[front.len()..], back); /// /// deque.push_front(10); /// deque.push_front(9); /// - /// assert_eq!(deque.as_slices(), (&[9, 10][..], &[0, 1, 2][..])); + /// let expected = [9, 10, 0, 1, 2]; + /// let (front, back) = deque.as_slices(); + /// assert_eq!(&expected[..front.len()], front); + /// assert_eq!(&expected[front.len()..], back); /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] @@ -1347,6 +1355,8 @@ impl<T, A: Allocator> VecDeque<T, A> { /// /// If [`make_contiguous`] was previously called, all elements of the /// deque will be in the first slice and the second slice will be empty. + /// Otherwise, the exact split point depends on implementation details + /// and is not guaranteed. /// /// [`make_contiguous`]: VecDeque::make_contiguous /// @@ -1363,9 +1373,22 @@ impl<T, A: Allocator> VecDeque<T, A> { /// deque.push_front(10); /// deque.push_front(9); /// - /// deque.as_mut_slices().0[0] = 42; - /// deque.as_mut_slices().1[0] = 24; - /// assert_eq!(deque.as_slices(), (&[42, 10][..], &[24, 1][..])); + /// // Since the split point is not guaranteed, we may need to update + /// // either slice. + /// let mut update_nth = |index: usize, val: u32| { + /// let (front, back) = deque.as_mut_slices(); + /// if index > front.len() - 1 { + /// back[index - front.len()] = val; + /// } else { + /// front[index] = val; + /// } + /// }; + /// + /// update_nth(0, 42); + /// update_nth(2, 24); + /// + /// let v: Vec<_> = deque.into(); + /// assert_eq!(v, [42, 10, 24, 1]); /// ``` #[inline] #[stable(feature = "deque_extras_15", since = "1.5.0")] diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 8b448a18402..48849bf7536 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -714,6 +714,8 @@ impl ops::Deref for CString { } } +/// Delegates to the [`CStr`] implementation of [`fmt::Debug`], +/// showing invalid UTF-8 as hex escapes. #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for CString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index abda5aefab6..f416732a8d6 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -66,7 +66,6 @@ )] #![doc(cfg_hide( not(test), - not(any(test, bootstrap)), no_global_oom_handling, not(no_global_oom_handling), not(no_rc), @@ -132,7 +131,6 @@ #![feature(local_waker)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array_transpose)] -#![feature(nonnull_provenance)] #![feature(panic_internals)] #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 7c5d22e1ee9..b4da56578c8 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -69,7 +69,7 @@ use crate::boxed::Box; use crate::vec::Vec; impl<T> [T] { - /// Sorts the slice, preserving initial order of equal elements. + /// Sorts the slice in ascending order, preserving initial order of equal elements. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) /// worst-case. @@ -137,7 +137,8 @@ impl<T> [T] { stable_sort(self, T::lt); } - /// Sorts the slice with a comparison function, preserving initial order of equal elements. + /// Sorts the slice in ascending order with a comparison function, preserving initial order of + /// equal elements. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) /// worst-case. @@ -197,7 +198,8 @@ impl<T> [T] { stable_sort(self, |a, b| compare(a, b) == Less); } - /// Sorts the slice with a key extraction function, preserving initial order of equal elements. + /// Sorts the slice in ascending order with a key extraction function, preserving initial order + /// of equal elements. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) /// worst-case, where the key function is *O*(*m*). @@ -252,7 +254,8 @@ impl<T> [T] { stable_sort(self, |a, b| f(a).lt(&f(b))); } - /// Sorts the slice with a key extraction function, preserving initial order of equal elements. + /// Sorts the slice in ascending order with a key extraction function, preserving initial order + /// of equal elements. /// /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* /// log(*n*)) worst-case, where the key function is *O*(*m*). @@ -490,8 +493,6 @@ impl<T> [T] { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); /// ``` diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 8766fd904b0..22cdd8ecde0 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -246,8 +246,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "this is old"; /// @@ -303,8 +301,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "foo foo 123 foo"; /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); @@ -320,6 +316,7 @@ impl str { /// ``` #[cfg(not(no_global_oom_handling))] #[rustc_allow_incoherent_impl] + #[doc(alias = "replace_first")] #[must_use = "this returns the replaced string as a new allocation, \ without modifying the original"] #[stable(feature = "str_replacen", since = "1.16.0")] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 59879f23d78..5bd82560da7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -109,6 +109,11 @@ mod in_place_collect; mod partial_eq; +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub use self::peek_mut::PeekMut; + +mod peek_mut; + #[cfg(not(no_global_oom_handling))] use self::spec_from_elem::SpecFromElem; @@ -729,6 +734,33 @@ impl<T> Vec<T> { pub unsafe fn from_parts(ptr: NonNull<T>, length: usize, capacity: usize) -> Self { unsafe { Self::from_parts_in(ptr, length, capacity, Global) } } + + /// Returns a mutable reference to the last item in the vector, or + /// `None` if it is empty. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(vec_peek_mut)] + /// let mut vec = Vec::new(); + /// assert!(vec.peek_mut().is_none()); + /// + /// vec.push(1); + /// vec.push(5); + /// vec.push(2); + /// assert_eq!(vec.last(), Some(&2)); + /// if let Some(mut val) = vec.peek_mut() { + /// *val = 0; + /// } + /// assert_eq!(vec.last(), Some(&0)); + /// ``` + #[inline] + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> { + PeekMut::new(self) + } } impl<T, A: Allocator> Vec<T, A> { @@ -3648,11 +3680,11 @@ impl<T, A: Allocator> Vec<T, A> { Splice { drain: self.drain(range), replace_with: replace_with.into_iter() } } - /// Creates an iterator which uses a closure to determine if element in the range should be removed. + /// Creates an iterator which uses a closure to determine if an element in the range should be removed. /// - /// If the closure returns true, then the element is removed and yielded. - /// If the closure returns false, the element will remain in the vector and will not be yielded - /// by the iterator. + /// If the closure returns `true`, the element is removed from the vector + /// and yielded. If the closure returns `false`, or panics, the element + /// remains in the vector and will not be yielded. /// /// Only elements that fall in the provided range are considered for extraction, but any elements /// after the range will still have to be moved if any element has been extracted. @@ -3692,8 +3724,8 @@ impl<T, A: Allocator> Vec<T, A> { /// But `extract_if` is easier to use. `extract_if` is also more efficient, /// because it can backshift the elements of the array in bulk. /// - /// Note that `extract_if` also lets you mutate the elements passed to the filter closure, - /// regardless of whether you choose to keep or remove them. + /// The iterator also lets you mutate the value of each element in the + /// closure, regardless of whether you choose to keep or remove it. /// /// # Panics /// @@ -3701,7 +3733,7 @@ impl<T, A: Allocator> Vec<T, A> { /// /// # Examples /// - /// Splitting an array into evens and odds, reusing the original allocation: + /// Splitting a vector into even and odd values, reusing the original vector: /// /// ``` /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; diff --git a/library/alloc/src/vec/peek_mut.rs b/library/alloc/src/vec/peek_mut.rs new file mode 100644 index 00000000000..c0dd941ed39 --- /dev/null +++ b/library/alloc/src/vec/peek_mut.rs @@ -0,0 +1,55 @@ +use core::ops::{Deref, DerefMut}; + +use super::Vec; +use crate::fmt; + +/// Structure wrapping a mutable reference to the last item in a +/// `Vec`. +/// +/// This `struct` is created by the [`peek_mut`] method on [`Vec`]. See +/// its documentation for more. +/// +/// [`peek_mut`]: Vec::peek_mut +#[unstable(feature = "vec_peek_mut", issue = "122742")] +pub struct PeekMut<'a, T> { + vec: &'a mut Vec<T>, +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<T: fmt::Debug> fmt::Debug for PeekMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PeekMut").field(self.deref()).finish() + } +} + +impl<'a, T> PeekMut<'a, T> { + pub(crate) fn new(vec: &'a mut Vec<T>) -> Option<Self> { + if vec.is_empty() { None } else { Some(Self { vec }) } + } + + /// Removes the peeked value from the vector and returns it. + #[unstable(feature = "vec_peek_mut", issue = "122742")] + pub fn pop(self) -> T { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.pop().unwrap_unchecked() } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> Deref for PeekMut<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked(self.vec.len() - 1) } + } +} + +#[unstable(feature = "vec_peek_mut", issue = "122742")] +impl<'a, T> DerefMut for PeekMut<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + let idx = self.vec.len() - 1; + // SAFETY: PeekMut is only constructed if the vec is non-empty + unsafe { self.vec.get_unchecked_mut(idx) } + } +} |
