Skip to content

Commit 60aa834

Browse files
committed
Implement LinkedList::drain_filter
Relates to rust-lang/rfcs#2140 - drain_filter for all collections `drain_filter` is implemented instead of `LinkedList::remove_if` based on review feedback.
1 parent de41d84 commit 60aa834

File tree

2 files changed

+283
-35
lines changed

2 files changed

+283
-35
lines changed

src/liballoc/linked_list.rs

+95-35
Original file line numberDiff line numberDiff line change
@@ -744,48 +744,47 @@ impl<T> LinkedList<T> {
744744
second_part
745745
}
746746

747-
/// Removes any element matching the given predicate. Returns the elements which were removed
748-
/// in a new list.
747+
/// Creates an iterator which uses a closure to determine if an element should be removed.
749748
///
750-
/// This operation should compute in O(n) time.
749+
/// If the closure returns true, then the element is removed and yielded.
750+
/// If the closure returns false, it will try again, and call the closure on the next element,
751+
/// seeing if it passes the test.
752+
///
753+
/// Note that `drain_filter` lets you mutate every element in the filter closure, regardless of
754+
/// whether you choose to keep or remove it.
751755
///
752756
/// # Examples
753757
///
754-
/// ```
755-
/// #![feature(linked_list_remove_if)]
758+
/// Splitting a list into evens and odds, reusing the original list:
756759
///
760+
/// ```
761+
/// #![feature(drain_filter)]
757762
/// use std::collections::LinkedList;
758763
///
759-
/// let mut d = LinkedList::new();
760-
/// d.push_back(1);
761-
/// d.push_back(2);
762-
/// d.push_back(3);
763-
/// assert_eq!(d.remove_if(|v| *v < 3).len(), 2);
764-
/// assert_eq!(d.len(), 1);
764+
/// let mut numbers: LinkedList<u32> = LinkedList::new();
765+
/// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]);
766+
///
767+
/// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<LinkedList<_>>();
768+
/// let odds = numbers;
769+
///
770+
/// assert_eq!(evens.into_iter().collect::<Vec<_>>(), vec![2, 4, 6, 8, 14]);
771+
/// assert_eq!(odds.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 9, 11, 13, 15]);
765772
/// ```
766-
#[unstable(feature = "linked_list_remove_if",
767-
reason = "experimental method",
768-
issue = "0")]
769-
pub fn remove_if<P>(&mut self, predicate: P) -> LinkedList<T>
770-
where P: Fn(&T) -> bool
773+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
774+
pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<T, F>
775+
where F: FnMut(&mut T) -> bool
771776
{
772-
let mut deleted = LinkedList::new();
773-
774-
let mut it = self.head;
775-
776-
while let Some(node) = it {
777-
unsafe {
778-
it = node.as_ref().next;
777+
// avoid borrow issues.
778+
let it = self.head;
779+
let old_len = self.len;
779780

780-
if predicate(&node.as_ref().element) {
781-
self.unlink_node(node);
782-
// move the unlinked node into the deleted list.
783-
deleted.push_back_node(Box::from_raw(node.as_ptr()));
784-
}
785-
}
781+
DrainFilter {
782+
list: self,
783+
it: it,
784+
pred: filter,
785+
idx: 0,
786+
old_len: old_len,
786787
}
787-
788-
deleted
789788
}
790789

791790
/// Returns a place for insertion at the front of the list.
@@ -1033,6 +1032,56 @@ impl<'a, T> IterMut<'a, T> {
10331032
}
10341033
}
10351034

1035+
/// An iterator produced by calling `drain_filter` on LinkedList.
1036+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
1037+
pub struct DrainFilter<'a, T: 'a, F: 'a>
1038+
where F: FnMut(&mut T) -> bool,
1039+
{
1040+
list: &'a mut LinkedList<T>,
1041+
it: Option<Shared<Node<T>>>,
1042+
pred: F,
1043+
idx: usize,
1044+
old_len: usize,
1045+
}
1046+
1047+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
1048+
impl<'a, T, F> Iterator for DrainFilter<'a, T, F>
1049+
where F: FnMut(&mut T) -> bool,
1050+
{
1051+
type Item = T;
1052+
1053+
fn next(&mut self) -> Option<T> {
1054+
while let Some(mut node) = self.it {
1055+
unsafe {
1056+
self.it = node.as_ref().next;
1057+
self.idx += 1;
1058+
1059+
if (self.pred)(&mut node.as_mut().element) {
1060+
self.list.unlink_node(node);
1061+
return Some(Box::from_raw(node.as_ptr()).element);
1062+
}
1063+
}
1064+
}
1065+
1066+
None
1067+
}
1068+
1069+
fn size_hint(&self) -> (usize, Option<usize>) {
1070+
(0, Some(self.old_len - self.idx))
1071+
}
1072+
}
1073+
1074+
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
1075+
impl<'a, T: 'a + fmt::Debug, F> fmt::Debug for DrainFilter<'a, T, F>
1076+
where F: FnMut(&mut T) -> bool
1077+
{
1078+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1079+
f.debug_tuple("DrainFilter")
1080+
.field(&self.list)
1081+
.finish()
1082+
}
1083+
}
1084+
10361085
#[stable(feature = "rust1", since = "1.0.0")]
10371086
impl<T> Iterator for IntoIter<T> {
10381087
type Item = T;
@@ -1570,15 +1619,26 @@ mod tests {
15701619
}
15711620

15721621
#[test]
1573-
fn remove_if_test() {
1622+
fn drain_filter_test() {
15741623
let mut m: LinkedList<u32> = LinkedList::new();
15751624
m.extend(&[1, 2, 3, 4, 5, 6]);
1576-
let deleted = m.remove_if(|v| *v < 4);
1625+
let deleted = m.drain_filter(|v| *v < 4).collect::<Vec<_>>();
15771626

15781627
check_links(&m);
1579-
check_links(&deleted);
15801628

1581-
assert_eq!(deleted.into_iter().collect::<Vec<_>>(), &[1, 2, 3]);
1629+
assert_eq!(deleted, &[1, 2, 3]);
15821630
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[4, 5, 6]);
15831631
}
1632+
1633+
#[test]
1634+
fn drain_to_empty_test() {
1635+
let mut m: LinkedList<u32> = LinkedList::new();
1636+
m.extend(&[1, 2, 3, 4, 5, 6]);
1637+
let deleted = m.drain_filter(|_| true).collect::<Vec<_>>();
1638+
1639+
check_links(&m);
1640+
1641+
assert_eq!(deleted, &[1, 2, 3, 4, 5, 6]);
1642+
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[]);
1643+
}
15841644
}

src/liballoc/tests/linked_list.rs

+188
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,191 @@ fn test_contains() {
366366

367367
assert!(!l.contains(&3));
368368
}
369+
370+
#[test]
371+
fn drain_filter_empty() {
372+
let mut list: LinkedList<i32> = LinkedList::new();
373+
374+
{
375+
let mut iter = list.drain_filter(|_| true);
376+
assert_eq!(iter.size_hint(), (0, Some(0)));
377+
assert_eq!(iter.next(), None);
378+
assert_eq!(iter.size_hint(), (0, Some(0)));
379+
assert_eq!(iter.next(), None);
380+
assert_eq!(iter.size_hint(), (0, Some(0)));
381+
}
382+
383+
assert_eq!(list.len(), 0);
384+
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
385+
}
386+
387+
#[test]
388+
fn drain_filter_zst() {
389+
let mut list: LinkedList<_> = vec![(), (), (), (), ()].into_iter().collect();
390+
let initial_len = list.len();
391+
let mut count = 0;
392+
393+
{
394+
let mut iter = list.drain_filter(|_| true);
395+
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
396+
while let Some(_) = iter.next() {
397+
count += 1;
398+
assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
399+
}
400+
assert_eq!(iter.size_hint(), (0, Some(0)));
401+
assert_eq!(iter.next(), None);
402+
assert_eq!(iter.size_hint(), (0, Some(0)));
403+
}
404+
405+
assert_eq!(count, initial_len);
406+
assert_eq!(list.len(), 0);
407+
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
408+
}
409+
410+
#[test]
411+
fn drain_filter_false() {
412+
let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
413+
414+
let initial_len = list.len();
415+
let mut count = 0;
416+
417+
{
418+
let mut iter = list.drain_filter(|_| false);
419+
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
420+
for _ in iter.by_ref() {
421+
count += 1;
422+
}
423+
assert_eq!(iter.size_hint(), (0, Some(0)));
424+
assert_eq!(iter.next(), None);
425+
assert_eq!(iter.size_hint(), (0, Some(0)));
426+
}
427+
428+
assert_eq!(count, 0);
429+
assert_eq!(list.len(), initial_len);
430+
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
431+
}
432+
433+
#[test]
434+
fn drain_filter_true() {
435+
let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
436+
437+
let initial_len = list.len();
438+
let mut count = 0;
439+
440+
{
441+
let mut iter = list.drain_filter(|_| true);
442+
assert_eq!(iter.size_hint(), (0, Some(initial_len)));
443+
while let Some(_) = iter.next() {
444+
count += 1;
445+
assert_eq!(iter.size_hint(), (0, Some(initial_len - count)));
446+
}
447+
assert_eq!(iter.size_hint(), (0, Some(0)));
448+
assert_eq!(iter.next(), None);
449+
assert_eq!(iter.size_hint(), (0, Some(0)));
450+
}
451+
452+
assert_eq!(count, initial_len);
453+
assert_eq!(list.len(), 0);
454+
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![]);
455+
}
456+
457+
#[test]
458+
fn drain_filter_complex() {
459+
460+
{ // [+xxx++++++xxxxx++++x+x++]
461+
let mut list = vec![
462+
1,
463+
2, 4, 6,
464+
7, 9, 11, 13, 15, 17,
465+
18, 20, 22, 24, 26,
466+
27, 29, 31, 33,
467+
34,
468+
35,
469+
36,
470+
37, 39
471+
].into_iter().collect::<LinkedList<_>>();
472+
473+
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
474+
assert_eq!(removed.len(), 10);
475+
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
476+
477+
assert_eq!(list.len(), 14);
478+
assert_eq!(
479+
list.into_iter().collect::<Vec<_>>(),
480+
vec![1, 7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
481+
);
482+
}
483+
484+
{ // [xxx++++++xxxxx++++x+x++]
485+
let mut list = vec![
486+
2, 4, 6,
487+
7, 9, 11, 13, 15, 17,
488+
18, 20, 22, 24, 26,
489+
27, 29, 31, 33,
490+
34,
491+
35,
492+
36,
493+
37, 39
494+
].into_iter().collect::<LinkedList<_>>();
495+
496+
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
497+
assert_eq!(removed.len(), 10);
498+
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
499+
500+
assert_eq!(list.len(), 13);
501+
assert_eq!(
502+
list.into_iter().collect::<Vec<_>>(),
503+
vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35, 37, 39]
504+
);
505+
}
506+
507+
{ // [xxx++++++xxxxx++++x+x]
508+
let mut list = vec![
509+
2, 4, 6,
510+
7, 9, 11, 13, 15, 17,
511+
18, 20, 22, 24, 26,
512+
27, 29, 31, 33,
513+
34,
514+
35,
515+
36
516+
].into_iter().collect::<LinkedList<_>>();
517+
518+
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
519+
assert_eq!(removed.len(), 10);
520+
assert_eq!(removed, vec![2, 4, 6, 18, 20, 22, 24, 26, 34, 36]);
521+
522+
assert_eq!(list.len(), 11);
523+
assert_eq!(
524+
list.into_iter().collect::<Vec<_>>(),
525+
vec![7, 9, 11, 13, 15, 17, 27, 29, 31, 33, 35]
526+
);
527+
}
528+
529+
{ // [xxxxxxxxxx+++++++++++]
530+
let mut list = vec![
531+
2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
532+
1, 3, 5, 7, 9, 11, 13, 15, 17, 19
533+
].into_iter().collect::<LinkedList<_>>();
534+
535+
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
536+
assert_eq!(removed.len(), 10);
537+
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
538+
539+
assert_eq!(list.len(), 10);
540+
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
541+
}
542+
543+
{ // [+++++++++++xxxxxxxxxx]
544+
let mut list = vec![
545+
1, 3, 5, 7, 9, 11, 13, 15, 17, 19,
546+
2, 4, 6, 8, 10, 12, 14, 16, 18, 20
547+
].into_iter().collect::<LinkedList<_>>();
548+
549+
let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
550+
assert_eq!(removed.len(), 10);
551+
assert_eq!(removed, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20]);
552+
553+
assert_eq!(list.len(), 10);
554+
assert_eq!(list.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19]);
555+
}
556+
}

0 commit comments

Comments
 (0)