Implement Vec::pop_if

This commit is contained in:
Alex van de Sandt 2024-03-26 15:54:22 -04:00
parent 47ecded352
commit 07d3806eb1
4 changed files with 57 additions and 0 deletions

View file

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

View file

@ -2058,6 +2058,31 @@ pub fn pop(&mut self) -> Option<T> {
}
}
/// 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!