Introduce LinkedList::remove_if

This commit is contained in:
John-John Tedro
2017-11-25 18:35:30 +01:00
parent 2f47a9eb80
commit de41d84ddf

View File

@@ -220,6 +220,28 @@ impl<T> LinkedList<T> {
node
})
}
/// Unlinks the specified node from the current list.
///
/// Warning: this will not check that the provided node belongs to the current list.
#[inline]
unsafe fn unlink_node(&mut self, mut node: Shared<Node<T>>) {
let node = node.as_mut();
match node.prev {
Some(mut prev) => prev.as_mut().next = node.next.clone(),
// this node is the head node
None => self.head = node.next.clone(),
};
match node.next {
Some(mut next) => next.as_mut().prev = node.prev.clone(),
// this node is the tail node
None => self.tail = node.prev.clone(),
};
self.len -= 1;
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -722,6 +744,50 @@ impl<T> LinkedList<T> {
second_part
}
/// Removes any element matching the given predicate. Returns the elements which were removed
/// in a new list.
///
/// This operation should compute in O(n) time.
///
/// # Examples
///
/// ```
/// #![feature(linked_list_remove_if)]
///
/// use std::collections::LinkedList;
///
/// let mut d = LinkedList::new();
/// d.push_back(1);
/// d.push_back(2);
/// d.push_back(3);
/// assert_eq!(d.remove_if(|v| *v < 3).len(), 2);
/// assert_eq!(d.len(), 1);
/// ```
#[unstable(feature = "linked_list_remove_if",
reason = "experimental method",
issue = "0")]
pub fn remove_if<P>(&mut self, predicate: P) -> LinkedList<T>
where P: Fn(&T) -> bool
{
let mut deleted = LinkedList::new();
let mut it = self.head;
while let Some(node) = it {
unsafe {
it = node.as_ref().next;
if predicate(&node.as_ref().element) {
self.unlink_node(node);
// move the unlinked node into the deleted list.
deleted.push_back_node(Box::from_raw(node.as_ptr()));
}
}
}
deleted
}
/// Returns a place for insertion at the front of the list.
///
/// Using this method with placement syntax is equivalent to
@@ -1502,4 +1568,17 @@ mod tests {
}
assert_eq!(i, v.len());
}
#[test]
fn remove_if_test() {
let mut m: LinkedList<u32> = LinkedList::new();
m.extend(&[1, 2, 3, 4, 5, 6]);
let deleted = m.remove_if(|v| *v < 4);
check_links(&m);
check_links(&deleted);
assert_eq!(deleted.into_iter().collect::<Vec<_>>(), &[1, 2, 3]);
assert_eq!(m.into_iter().collect::<Vec<_>>(), &[4, 5, 6]);
}
}