FROMGIT: rust: alloc: add Vec::retain
This adds a common Vec method called `retain` that removes all elements that don't match a certain condition. Rust Binder uses it to find all processes that match a given pid. The stdlib retain method takes &T rather than &mut T and has a separate retain_mut for the &mut T case. However, this is considered an API mistake that can't be fixed now due to backwards compatibility. There's no reason for us to repeat that mistake. Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Benno Lossin <lossin@kernel.org> Link: https://lore.kernel.org/r/20250502-vec-methods-v5-5-06d20ad9366f@google.com Signed-off-by: Danilo Krummrich <dakr@kernel.org> Bug: 414994413 (cherry picked from commit 9f140894e72735f034fdc0e963d0550ef03c6f44 https://github.com/Rust-for-Linux/linux.git alloc-next) Change-Id: I1a126b3a847142eaa90794789280abb91e000b58 Signed-off-by: Alice Ryhl <aliceryhl@google.com>
This commit is contained in:
committed by
Matthew Maurer
parent
1e01dcf3be
commit
e1da60354a
@@ -610,6 +610,29 @@ where
|
||||
elements: elems.iter_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes all elements that don't match the provided closure.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut v = kernel::kvec![1, 2, 3, 4]?;
|
||||
/// v.retain(|i| *i % 2 == 0);
|
||||
/// assert_eq!(v, [2, 4]);
|
||||
/// # Ok::<(), Error>(())
|
||||
/// ```
|
||||
pub fn retain(&mut self, mut f: impl FnMut(&mut T) -> bool) {
|
||||
let mut num_kept = 0;
|
||||
let mut next_to_check = 0;
|
||||
while let Some(to_check) = self.get_mut(next_to_check) {
|
||||
if f(to_check) {
|
||||
self.swap(num_kept, next_to_check);
|
||||
num_kept += 1;
|
||||
}
|
||||
next_to_check += 1;
|
||||
}
|
||||
self.truncate(num_kept);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone, A: Allocator> Vec<T, A> {
|
||||
@@ -1132,3 +1155,52 @@ impl<'vec, T> Drop for DrainAll<'vec, T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macros::kunit_tests(rust_kvec_kunit)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn test_kvec_retain() {
|
||||
/// Verify correctness for one specific function.
|
||||
#[expect(clippy::needless_range_loop)]
|
||||
fn verify(c: &[bool]) {
|
||||
let mut vec1: KVec<usize> = KVec::with_capacity(c.len(), GFP_KERNEL).unwrap();
|
||||
let mut vec2: KVec<usize> = KVec::with_capacity(c.len(), GFP_KERNEL).unwrap();
|
||||
|
||||
for i in 0..c.len() {
|
||||
vec1.push_within_capacity(i).unwrap();
|
||||
if c[i] {
|
||||
vec2.push_within_capacity(i).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
vec1.retain(|i| c[*i]);
|
||||
|
||||
assert_eq!(vec1, vec2);
|
||||
}
|
||||
|
||||
/// Add one to a binary integer represented as a boolean array.
|
||||
fn add(value: &mut [bool]) {
|
||||
let mut carry = true;
|
||||
for v in value {
|
||||
let new_v = carry != *v;
|
||||
carry = carry && *v;
|
||||
*v = new_v;
|
||||
}
|
||||
}
|
||||
|
||||
// This boolean array represents a function from index to boolean. We check that `retain`
|
||||
// behaves correctly for all possible boolean arrays of every possible length less than
|
||||
// ten.
|
||||
let mut func = KVec::with_capacity(10, GFP_KERNEL).unwrap();
|
||||
for len in 0..10 {
|
||||
for _ in 0u32..1u32 << len {
|
||||
verify(&func);
|
||||
add(&mut func);
|
||||
}
|
||||
func.push_within_capacity(false).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user