Skip to content

Commit de41d84

Browse files
committed
Introduce LinkedList::remove_if
1 parent 2f47a9e commit de41d84

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

src/liballoc/linked_list.rs

+79
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,28 @@ impl<T> LinkedList<T> {
220220
node
221221
})
222222
}
223+
224+
/// Unlinks the specified node from the current list.
225+
///
226+
/// Warning: this will not check that the provided node belongs to the current list.
227+
#[inline]
228+
unsafe fn unlink_node(&mut self, mut node: Shared<Node<T>>) {
229+
let node = node.as_mut();
230+
231+
match node.prev {
232+
Some(mut prev) => prev.as_mut().next = node.next.clone(),
233+
// this node is the head node
234+
None => self.head = node.next.clone(),
235+
};
236+
237+
match node.next {
238+
Some(mut next) => next.as_mut().prev = node.prev.clone(),
239+
// this node is the tail node
240+
None => self.tail = node.prev.clone(),
241+
};
242+
243+
self.len -= 1;
244+
}
223245
}
224246

225247
#[stable(feature = "rust1", since = "1.0.0")]
@@ -722,6 +744,50 @@ impl<T> LinkedList<T> {
722744
second_part
723745
}
724746

747+
/// Removes any element matching the given predicate. Returns the elements which were removed
748+
/// in a new list.
749+
///
750+
/// This operation should compute in O(n) time.
751+
///
752+
/// # Examples
753+
///
754+
/// ```
755+
/// #![feature(linked_list_remove_if)]
756+
///
757+
/// use std::collections::LinkedList;
758+
///
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);
765+
/// ```
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
771+
{
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;
779+
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+
}
786+
}
787+
788+
deleted
789+
}
790+
725791
/// Returns a place for insertion at the front of the list.
726792
///
727793
/// Using this method with placement syntax is equivalent to
@@ -1502,4 +1568,17 @@ mod tests {
15021568
}
15031569
assert_eq!(i, v.len());
15041570
}
1571+
1572+
#[test]
1573+
fn remove_if_test() {
1574+
let mut m: LinkedList<u32> = LinkedList::new();
1575+
m.extend(&[1, 2, 3, 4, 5, 6]);
1576+
let deleted = m.remove_if(|v| *v < 4);
1577+
1578+
check_links(&m);
1579+
check_links(&deleted);
1580+
1581+
assert_eq!(deleted.into_iter().collect::<Vec<_>>(), &[1, 2, 3]);
1582+
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[4, 5, 6]);
1583+
}
15051584
}

0 commit comments

Comments
 (0)