Skip to content

Commit 07d3806

Browse files
committed
Implement Vec::pop_if
1 parent 47ecded commit 07d3806

File tree

4 files changed

+57
-0
lines changed

4 files changed

+57
-0
lines changed

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@
169169
#![feature(unicode_internals)]
170170
#![feature(unsize)]
171171
#![feature(utf8_chunks)]
172+
#![feature(vec_pop_if)]
172173
// tidy-alphabetical-end
173174
//
174175
// Language features:

library/alloc/src/vec/mod.rs

+25
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,31 @@ impl<T, A: Allocator> Vec<T, A> {
20582058
}
20592059
}
20602060

2061+
/// Removes and returns the last element in a vector if the predicate
2062+
/// returns `true`, or [`None`] if the predicate returns false or the vector
2063+
/// is empty.
2064+
///
2065+
/// # Examples
2066+
///
2067+
/// ```
2068+
/// #![feature(vec_pop_if)]
2069+
///
2070+
/// let mut vec = vec![1, 2, 3, 4];
2071+
/// let pred = |x: &mut i32| *x % 2 == 0;
2072+
///
2073+
/// assert_eq!(vec.pop_if(pred), Some(4));
2074+
/// assert_eq!(vec, [1, 2, 3]);
2075+
/// assert_eq!(vec.pop_if(pred), None);
2076+
/// ```
2077+
#[unstable(feature = "vec_pop_if", issue = "122741")]
2078+
pub fn pop_if<F>(&mut self, f: F) -> Option<T>
2079+
where
2080+
F: FnOnce(&mut T) -> bool,
2081+
{
2082+
let last = self.last_mut()?;
2083+
if f(last) { self.pop() } else { None }
2084+
}
2085+
20612086
/// Moves all the elements of `other` into `self`, leaving `other` empty.
20622087
///
20632088
/// # Panics

library/alloc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#![feature(strict_provenance)]
4444
#![feature(drain_keep_rest)]
4545
#![feature(local_waker)]
46+
#![feature(vec_pop_if)]
4647
#![allow(internal_features)]
4748
#![deny(fuzzy_provenance_casts)]
4849
#![deny(unsafe_op_in_unsafe_fn)]

library/alloc/tests/vec.rs

+30
Original file line numberDiff line numberDiff line change
@@ -2644,6 +2644,36 @@ fn test_vec_from_array_mut_ref() {
26442644
assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]);
26452645
}
26462646

2647+
#[test]
2648+
fn test_pop_if() {
2649+
let mut v = vec![1, 2, 3, 4];
2650+
let pred = |x: &mut i32| *x % 2 == 0;
2651+
2652+
assert_eq!(v.pop_if(pred), Some(4));
2653+
assert_eq!(v, [1, 2, 3]);
2654+
2655+
assert_eq!(v.pop_if(pred), None);
2656+
assert_eq!(v, [1, 2, 3]);
2657+
}
2658+
2659+
#[test]
2660+
fn test_pop_if_empty() {
2661+
let mut v = Vec::<i32>::new();
2662+
assert_eq!(v.pop_if(|_| true), None);
2663+
assert!(v.is_empty());
2664+
}
2665+
2666+
#[test]
2667+
fn test_pop_if_mutates() {
2668+
let mut v = vec![1];
2669+
let pred = |x: &mut i32| {
2670+
*x += 1;
2671+
false
2672+
};
2673+
assert_eq!(v.pop_if(pred), None);
2674+
assert_eq!(v, [2]);
2675+
}
2676+
26472677
/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments
26482678
/// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but
26492679
/// `vec.insert(usize::MAX, val)` once slipped by!

0 commit comments

Comments
 (0)