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

[hashmap] Adds drain: a way to sneak out the elements while clearing a map. #19946

Merged
merged 1 commit into from
Dec 21, 2014
Merged
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
41 changes: 40 additions & 1 deletion src/libcollections/binary_heap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,18 @@ impl<T: Ord> BinaryHeap<T> {
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn is_empty(&self) -> bool { self.len() == 0 }

/// Clears the queue, returning an iterator over the removed elements.
#[inline]
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
Drain {
iter: self.data.drain(),
}
}

/// Drops all items from the queue.
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn clear(&mut self) { self.data.truncate(0) }
pub fn clear(&mut self) { self.drain(); }
}

/// `BinaryHeap` iterator.
Expand Down Expand Up @@ -598,6 +607,26 @@ impl<T> DoubleEndedIterator<T> for MoveItems<T> {

impl<T> ExactSizeIterator<T> for MoveItems<T> {}

/// An iterator that drains a `BinaryHeap`.
pub struct Drain<'a, T: 'a> {
iter: vec::Drain<'a, T>,
}

impl<'a, T: 'a> Iterator<T> for Drain<'a, T> {
#[inline]
fn next(&mut self) -> Option<T> { self.iter.next() }

#[inline]
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
}

impl<'a, T: 'a> DoubleEndedIterator<T> for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> { self.iter.next_back() }
}

impl<'a, T: 'a> ExactSizeIterator<T> for Drain<'a, T> {}

impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
fn from_iter<Iter: Iterator<T>>(iter: Iter) -> BinaryHeap<T> {
let vec: Vec<T> = iter.collect();
Expand Down Expand Up @@ -822,4 +851,14 @@ mod tests {
assert_eq!(q.pop().unwrap(), x);
}
}

#[test]
fn test_drain() {
let mut q: BinaryHeap<_> =
[9u, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();

assert_eq!(q.drain().take(5).count(), 5);

assert!(q.is_empty());
}
}
130 changes: 126 additions & 4 deletions src/libcollections/ring_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,27 @@ impl<T> RingBuf<T> {
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn is_empty(&self) -> bool { self.len() == 0 }

/// Creates a draining iterator that clears the `RingBuf` and iterates over
/// the removed items from start to end.
///
/// # Examples
///
/// ```
/// use std::collections::RingBuf;
///
/// let mut v = RingBuf::new();
/// v.push_back(1i);
/// assert_eq!(v.drain().next(), Some(1));
/// assert!(v.is_empty());
/// ```
#[inline]
#[unstable = "matches collection reform specification, waiting for dust to settle"]
pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
Drain {
inner: self,
}
}

/// Clears the buffer, removing all values.
///
/// # Examples
Expand All @@ -456,10 +477,9 @@ impl<T> RingBuf<T> {
/// assert!(v.is_empty());
/// ```
#[unstable = "matches collection reform specification, waiting for dust to settle"]
#[inline]
pub fn clear(&mut self) {
while self.pop_front().is_some() {}
self.head = 0;
self.tail = 0;
self.drain();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3

}

/// Provides a reference to the front element, or `None` if the sequence is
Expand Down Expand Up @@ -1177,9 +1197,44 @@ impl<T> DoubleEndedIterator<T> for MoveItems<T> {
}
}


impl<T> ExactSizeIterator<T> for MoveItems<T> {}

/// A draining RingBuf iterator
pub struct Drain<'a, T: 'a> {
inner: &'a mut RingBuf<T>,
}

#[unsafe_destructor]
impl<'a, T: 'a> Drop for Drain<'a, T> {
fn drop(&mut self) {
for _ in *self {}
self.inner.head = 0;
self.inner.tail = 0;
}
}

impl<'a, T: 'a> Iterator<T> for Drain<'a, T> {
#[inline]
fn next(&mut self) -> Option<T> {
self.inner.pop_front()
}

#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
let len = self.inner.len();
(len, Some(len))
}
}

impl<'a, T: 'a> DoubleEndedIterator<T> for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
self.inner.pop_back()
}
}

impl<'a, T: 'a> ExactSizeIterator<T> for Drain<'a, T> {}

impl<A: PartialEq> PartialEq for RingBuf<A> {
fn eq(&self, other: &RingBuf<A>) -> bool {
self.len() == other.len() &&
Expand Down Expand Up @@ -1789,6 +1844,73 @@ mod tests {
}
}

#[test]
fn test_drain() {

// Empty iter
{
let mut d: RingBuf<int> = RingBuf::new();

{
let mut iter = d.drain();

assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.next(), None);
assert_eq!(iter.size_hint(), (0, Some(0)));
}

assert!(d.is_empty());
}

// simple iter
{
let mut d = RingBuf::new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this isn't a collect?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, symmetry with the other tests.

for i in range(0i, 5) {
d.push_back(i);
}

assert_eq!(d.drain().collect::<Vec<int>>(), [0, 1, 2, 3, 4]);
assert!(d.is_empty());
}

// wrapped iter
{
let mut d = RingBuf::new();
for i in range(0i, 5) {
d.push_back(i);
}
for i in range(6, 9) {
d.push_front(i);
}

assert_eq!(d.drain().collect::<Vec<int>>(), [8,7,6,0,1,2,3,4]);
assert!(d.is_empty());
}

// partially used
{
let mut d = RingBuf::new();
for i in range(0i, 5) {
d.push_back(i);
}
for i in range(6, 9) {
d.push_front(i);
}

{
let mut it = d.drain();
assert_eq!(it.size_hint(), (8, Some(8)));
assert_eq!(it.next(), Some(8));
assert_eq!(it.size_hint(), (7, Some(7)));
assert_eq!(it.next_back(), Some(4));
assert_eq!(it.size_hint(), (6, Some(6)));
assert_eq!(it.next(), Some(7));
assert_eq!(it.size_hint(), (5, Some(5)));
}
assert!(d.is_empty());
}
}

#[test]
fn test_from_iter() {
use std::iter;
Expand Down
Loading