Skip to content

Commit 1e60a47

Browse files
committed
Auto merge of #43245 - Gankro:drain-filter, r=sfackler
Add Vec::drain_filter This implements the API proposed in #43244. So I spent like half a day figuring out how to implement this in some awesome super-optimized unsafe way, which had me very confident this was worth putting into the stdlib. Then I looked at the impl for `retain`, and was like "oh dang". I compared the two and they basically ended up being the same speed. And the `retain` impl probably translates to DoubleEndedIter a lot more cleanly if we ever want that. So now I'm not totally confident this needs to go in the stdlib, but I've got two implementations and an amazingly robust test suite, so I figured I might as well toss it over the fence for discussion.
2 parents f25c228 + 1af4226 commit 1e60a47

File tree

3 files changed

+281
-0
lines changed

3 files changed

+281
-0
lines changed

src/liballoc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#![feature(inclusive_range_syntax)]
1717
#![feature(collection_placement)]
1818
#![feature(const_fn)]
19+
#![feature(drain_filter)]
1920
#![feature(exact_size_is_empty)]
2021
#![feature(iterator_step_by)]
2122
#![feature(pattern)]

src/liballoc/tests/vec.rs

+167
Original file line numberDiff line numberDiff line change
@@ -801,3 +801,170 @@ fn overaligned_allocations() {
801801
assert!(v.as_ptr() as usize & 0xff == 0);
802802
}
803803
}
804+
805+
#[test]
806+
fn drain_filter_empty() {
807+
let mut vec: Vec<i32> = vec![];
808+
809+
{
810+
let mut iter = vec.drain_filter(|_| true);
811+
assert_eq!(iter.size_hint(), (0, Some(0)));
812+
assert_eq!(iter.next(), None);
813+
assert_eq!(iter.size_hint(), (0, Some(0)));
814+
assert_eq!(iter.next(), None);
815+
assert_eq!(iter.size_hint(), (0, Some(0)));
816+
}
817+
assert_eq!(vec.len(), 0);
818+
assert_eq!(vec, vec![]);
819+
}
820+
821+
#[test]
822+
fn drain_filter_zst() {
823+
let mut vec = vec![(), (), (), (), ()];
824+
let initial_len = vec.len();
825+
let mut count = 0;
826+
{
827+
let mut iter = vec.drain_filter(|_| true);
828+
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
829+
while let Some(_) = iter.next() {
830+
count += 1;
831+
assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
832+
}
833+
assert_eq!(iter.size_hint(), (0, Some(0)));
834+
assert_eq!(iter.next(), None);
835+
assert_eq!(iter.size_hint(), (0, Some(0)));
836+
}
837+
838+
assert_eq!(count, initial_len);
839+
assert_eq!(vec.len(), 0);
840+
assert_eq!(vec, vec![]);
841+
}
842+
843+
#[test]
844+
fn drain_filter_false() {
845+
let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
846+
847+
let initial_len = vec.len();
848+
let mut count = 0;
849+
{
850+
let mut iter = vec.drain_filter(|_| false);
851+
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
852+
for _ in iter.by_ref() {
853+
count += 1;
854+
}
855+
assert_eq!(iter.size_hint(), (0, Some(0)));
856+
assert_eq!(iter.next(), None);
857+
assert_eq!(iter.size_hint(), (0, Some(0)));
858+
}
859+
860+
assert_eq!(count, 0);
861+
assert_eq!(vec.len(), initial_len);
862+
assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
863+
}
864+
865+
#[test]
866+
fn drain_filter_true() {
867+
let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
868+
869+
let initial_len = vec.len();
870+
let mut count = 0;
871+
{
872+
let mut iter = vec.drain_filter(|_| true);
873+
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
874+
while let Some(_) = iter.next() {
875+
count += 1;
876+
assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
877+
}
878+
assert_eq!(iter.size_hint(), (0, Some(0)));
879+
assert_eq!(iter.next(), None);
880+
assert_eq!(iter.size_hint(), (0, Some(0)));
881+
}
882+
883+
assert_eq!(count, initial_len);
884+
assert_eq!(vec.len(), 0);
885+
assert_eq!(vec, vec![]);
886+
}
887+
888+
#[test]
889+
fn drain_filter_complex() {
890+
891+
{ // [+xxx++++++xxxxx++++x+x++]
892+
let mut vec = vec![1,
893+
2, 4, 6,
894+
7, 9, 11, 13, 15, 17,
895+
18, 20, 22, 24, 26,
896+
27, 29, 31, 33,
897+
34,
898+
35,
899+
36,
900+
37, 39];
901+
902+
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
903+
assert_eq!(removed.len(), 10);
904+
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
905+
906+
assert_eq!(vec.len(), 14);
907+
assert_eq!(vec, vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]);
908+
}
909+
910+
{ // [xxx++++++xxxxx++++x+x++]
911+
let mut vec = vec![2, 4, 6,
912+
7, 9, 11, 13, 15, 17,
913+
18, 20, 22, 24, 26,
914+
27, 29, 31, 33,
915+
34,
916+
35,
917+
36,
918+
37, 39];
919+
920+
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
921+
assert_eq!(removed.len(), 10);
922+
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
923+
924+
assert_eq!(vec.len(), 13);
925+
assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]);
926+
}
927+
928+
{ // [xxx++++++xxxxx++++x+x]
929+
let mut vec = vec![2, 4, 6,
930+
7, 9, 11, 13, 15, 17,
931+
18, 20, 22, 24, 26,
932+
27, 29, 31, 33,
933+
34,
934+
35,
935+
36];
936+
937+
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
938+
assert_eq!(removed.len(), 10);
939+
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
940+
941+
assert_eq!(vec.len(), 11);
942+
assert_eq!(vec, vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]);
943+
}
944+
945+
{ // [xxxxxxxxxx+++++++++++]
946+
let mut vec = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
947+
1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
948+
949+
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
950+
assert_eq!(removed.len(), 10);
951+
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
952+
953+
assert_eq!(vec.len(), 10);
954+
assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
955+
}
956+
957+
{ // [+++++++++++xxxxxxxxxx]
958+
let mut vec = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19,
959+
2, 4, 6, 8, 10, 12, 14, 16, 18, 20];
960+
961+
let removed = vec.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
962+
assert_eq!(removed.len(), 10);
963+
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
964+
965+
assert_eq!(vec.len(), 10);
966+
assert_eq!(vec, vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
967+
}
968+
}
969+
970+

src/liballoc/vec.rs

+113
Original file line numberDiff line numberDiff line change
@@ -1960,6 +1960,65 @@ impl<T> Vec<T> {
19601960
}
19611961
}
19621962

1963+
/// Creates an iterator which uses a closure to determine if an element should be removed.
1964+
///
1965+
/// If the closure returns true, then the element is removed and yielded.
1966+
/// If the closure returns false, it will try again, and call the closure
1967+
/// on the next element, seeing if it passes the test.
1968+
///
1969+
/// Using this method is equivalent to the following code:
1970+
///
1971+
/// ```
1972+
/// # let some_predicate = |x: &mut i32| { *x == 2 };
1973+
/// # let mut vec = vec![1, 2, 3, 4, 5];
1974+
/// let mut i = 0;
1975+
/// while i != vec.len() {
1976+
/// if some_predicate(&mut vec[i]) {
1977+
/// let val = vec.remove(i);
1978+
/// // your code here
1979+
/// }
1980+
/// i += 1;
1981+
/// }
1982+
/// ```
1983+
///
1984+
/// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
1985+
/// because it can backshift the elements of the array in bulk.
1986+
///
1987+
/// Note that `drain_filter` also lets you mutate every element in the filter closure,
1988+
/// regardless of whether you choose to keep or remove it.
1989+
///
1990+
///
1991+
/// # Examples
1992+
///
1993+
/// Splitting an array into evens and odds, reusing the original allocation:
1994+
///
1995+
/// ```
1996+
/// #![feature(drain_filter)]
1997+
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
1998+
///
1999+
/// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
2000+
/// let odds = numbers;
2001+
///
2002+
/// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
2003+
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
2004+
/// ```
2005+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
2006+
pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<T, F>
2007+
where F: FnMut(&mut T) -> bool,
2008+
{
2009+
let old_len = self.len();
2010+
2011+
// Guard against us getting leaked (leak amplification)
2012+
unsafe { self.set_len(0); }
2013+
2014+
DrainFilter {
2015+
vec: self,
2016+
idx: 0,
2017+
del: 0,
2018+
old_len,
2019+
pred: filter,
2020+
}
2021+
}
19632022
}
19642023

19652024
/// Extend implementation that copies elements out of references before pushing them onto the Vec.
@@ -2602,3 +2661,57 @@ impl<'a, T> Drain<'a, T> {
26022661
self.tail_start = new_tail_start;
26032662
}
26042663
}
2664+
2665+
/// An iterator produced by calling `drain_filter` on Vec.
2666+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
2667+
#[derive(Debug)]
2668+
pub struct DrainFilter<'a, T: 'a, F>
2669+
where F: FnMut(&mut T) -> bool,
2670+
{
2671+
vec: &'a mut Vec<T>,
2672+
idx: usize,
2673+
del: usize,
2674+
old_len: usize,
2675+
pred: F,
2676+
}
2677+
2678+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
2679+
impl<'a, T, F> Iterator for DrainFilter<'a, T, F>
2680+
where F: FnMut(&mut T) -> bool,
2681+
{
2682+
type Item = T;
2683+
2684+
fn next(&mut self) -> Option<T> {
2685+
unsafe {
2686+
while self.idx != self.old_len {
2687+
let i = self.idx;
2688+
self.idx += 1;
2689+
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
2690+
if (self.pred)(&mut v[i]) {
2691+
self.del += 1;
2692+
return Some(ptr::read(&v[i]));
2693+
} else if self.del > 0 {
2694+
v.swap(i - self.del, i);
2695+
}
2696+
}
2697+
None
2698+
}
2699+
}
2700+
2701+
fn size_hint(&self) -> (usize, Option<usize>) {
2702+
(0, Some(self.old_len - self.idx))
2703+
}
2704+
}
2705+
2706+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
2707+
impl<'a, T, F> Drop for DrainFilter<'a, T, F>
2708+
where F: FnMut(&mut T) -> bool,
2709+
{
2710+
fn drop(&mut self) {
2711+
for _ in self.by_ref() { }
2712+
2713+
unsafe {
2714+
self.vec.set_len(self.old_len - self.del);
2715+
}
2716+
}
2717+
}

0 commit comments

Comments
 (0)