Rollup merge of #123107 - avandesa:vec_pop_if, r=joboet

Implement `Vec::pop_if`

This PR adds `Vec::pop_if` to the public API, behind the `vec_pop_if` feature.

```rust
impl<T> Vec<T> {
    pub fn pop_if<F>(&mut self, f: F) -> Option<T>
        where F: FnOnce(&mut T) -> bool;
}
```

Tracking issue: #122741

## Open questions

- [ ] Should the first unit test be split up?
- [ ] I don't see any guidance on ordering of methods in impl blocks, should I move the method elsewhere?
This commit is contained in:
Matthias Krüger 2024-03-27 05:21:18 +01:00 committed by GitHub
commit 19a40ec5bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 57 additions and 0 deletions

View File

@ -170,6 +170,7 @@
#![feature(unicode_internals)]
#![feature(unsize)]
#![feature(utf8_chunks)]
#![feature(vec_pop_if)]
// tidy-alphabetical-end
//
// Language features:

View File

@ -2058,6 +2058,31 @@ impl<T, A: Allocator> Vec<T, A> {
}
}
/// Removes and returns the last element in a vector if the predicate
/// returns `true`, or [`None`] if the predicate returns false or the vector
/// is empty.
///
/// # Examples
///
/// ```
/// #![feature(vec_pop_if)]
///
/// let mut vec = vec![1, 2, 3, 4];
/// let pred = |x: &mut i32| *x % 2 == 0;
///
/// assert_eq!(vec.pop_if(pred), Some(4));
/// assert_eq!(vec, [1, 2, 3]);
/// assert_eq!(vec.pop_if(pred), None);
/// ```
#[unstable(feature = "vec_pop_if", issue = "122741")]
pub fn pop_if<F>(&mut self, f: F) -> Option<T>
where
F: FnOnce(&mut T) -> bool,
{
let last = self.last_mut()?;
if f(last) { self.pop() } else { None }
}
/// Moves all the elements of `other` into `self`, leaving `other` empty.
///
/// # Panics

View File

@ -43,6 +43,7 @@
#![feature(strict_provenance)]
#![feature(drain_keep_rest)]
#![feature(local_waker)]
#![feature(vec_pop_if)]
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]

View File

@ -2644,6 +2644,36 @@ fn test_vec_from_array_mut_ref() {
assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]);
}
#[test]
fn test_pop_if() {
let mut v = vec![1, 2, 3, 4];
let pred = |x: &mut i32| *x % 2 == 0;
assert_eq!(v.pop_if(pred), Some(4));
assert_eq!(v, [1, 2, 3]);
assert_eq!(v.pop_if(pred), None);
assert_eq!(v, [1, 2, 3]);
}
#[test]
fn test_pop_if_empty() {
let mut v = Vec::<i32>::new();
assert_eq!(v.pop_if(|_| true), None);
assert!(v.is_empty());
}
#[test]
fn test_pop_if_mutates() {
let mut v = vec![1];
let pred = |x: &mut i32| {
*x += 1;
false
};
assert_eq!(v.pop_if(pred), None);
assert_eq!(v, [2]);
}
/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments
/// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but
/// `vec.insert(usize::MAX, val)` once slipped by!