Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slice retain #71832

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
#![feature(alloc_layout_extra)]
#![feature(try_trait)]
#![feature(associated_type_bounds)]
#![feature(slice_retain)]

// Allow testing this library

Expand Down
20 changes: 3 additions & 17 deletions src/liballoc/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1103,26 +1103,12 @@ impl<T> Vec<T> {
/// assert_eq!(vec, [2, 3, 5]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn retain<F>(&mut self, mut f: F)
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&T) -> bool,
{
let len = self.len();
let mut del = 0;
{
let v = &mut **self;

for i in 0..len {
if !f(&v[i]) {
del += 1;
} else if del > 0 {
v.swap(i - del, i);
}
}
}
if del > 0 {
self.truncate(len - del);
}
let retained_len = self.as_mut_slice().retain(f).len();
self.truncate(retained_len);
}

/// Removes all but the first of consecutive elements in the vector that resolve to the same
Expand Down
45 changes: 45 additions & 0 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2063,6 +2063,51 @@ impl<T> [T] {
self.partition_dedup_by(|a, b| key(a) == key(b))
}

/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
/// This method operates in place, visiting each element exactly once in the
/// original order, and preserves the order of the retained elements.
///
/// # Examples
///
/// ```
/// #![feature(slice_retain)]
///
/// let mut slice = [1, 2, 3, 4];
/// let retained = slice.retain(|&x| x % 2 == 0);
/// assert_eq!(retained, [2, 4]);
/// ```
///
/// The exact order may be useful for tracking external state, like an index.
///
/// ```
/// #![feature(slice_retain)]
///
/// let mut slice = [1, 2, 3, 4, 5];
/// let keep = [false, true, true, false, true];
/// let mut i = 0;
/// let retained = slice.retain(|_| (keep[i], i += 1).0);
/// assert_eq!(retained, [2, 3, 5]);
/// ```
#[unstable(feature = "slice_retain", issue = "71831")]
#[must_use]
pub fn retain<F>(&mut self, mut f: F) -> &mut Self
where
F: FnMut(&T) -> bool,
{
let len = self.len();
let mut del = 0;
for i in 0..len {
if !f(&self[i]) {
del += 1;
} else if del > 0 {
self.swap(i - del, i);
}
}
self.split_at_mut(len - del).0
}

/// Rotates the slice in-place such that the first `mid` elements of the
/// slice move to the end while the last `self.len() - mid` elements move to
/// the front. After calling `rotate_left`, the element previously at index
Expand Down
1 change: 1 addition & 0 deletions src/libcore/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#![feature(leading_trailing_ones)]
#![feature(const_forget)]
#![feature(option_unwrap_none)]
#![feature(slice_retain)]

extern crate test;

Expand Down
11 changes: 11 additions & 0 deletions src/libcore/tests/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1635,6 +1635,17 @@ fn test_slice_partition_dedup_partialeq() {
assert_eq!(duplicates, [Foo(0, 5), Foo(1, 9)]);
}

#[test]
fn test_slice_retain() {
let mut slice = [1, 2, 2, 3, 1, 4];
let retained = slice.retain(|&x| x == 1);
assert_eq!(retained, &[1, 1]);

let mut slice = [1, 2, 2, 3, 1, 4];
let retained = slice.retain(|&x| x % 2 == 0);
assert_eq!(retained, &[2, 2, 4]);
}

#[test]
fn test_copy_within() {
// Start to end, with a RangeTo.
Expand Down