about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2016-12-30 21:18:17 -0800
committerSteven Fackler <sfackler@gmail.com>2017-01-01 19:18:07 -0800
commitf2cb47adf95171e48a9f918aae00193a7d36c7c0 (patch)
treec0e544501aa9ecdef3de767d662f030907504f28
parent6c9bb42ecc48ffb5a3c8b61e220b11adc3a46384 (diff)
downloadrust-f2cb47adf95171e48a9f918aae00193a7d36c7c0.tar.gz
rust-f2cb47adf95171e48a9f918aae00193a7d36c7c0.zip
Add PeekMut::pop
A fairly common workflow is to put a bunch of stuff into a binary heap
and then mutate the top value until its empty. This both makes that a
bit more convenient (no need to save a boolean off and pop after to
avoid borrowck issues), and a bit more efficient since you only shift
once.
-rw-r--r--src/libcollections/binary_heap.rs23
-rw-r--r--src/libcollectionstest/binary_heap.rs15
-rw-r--r--src/libcollectionstest/lib.rs1
3 files changed, 34 insertions, 5 deletions
diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs
index c5d5ad27d23..c53b34d589b 100644
--- a/src/libcollections/binary_heap.rs
+++ b/src/libcollections/binary_heap.rs
@@ -153,8 +153,7 @@
 
 use core::ops::{Deref, DerefMut};
 use core::iter::{FromIterator, FusedIterator};
-use core::mem::swap;
-use core::mem::size_of;
+use core::mem::{swap, size_of};
 use core::ptr;
 use core::fmt;
 
@@ -226,12 +225,15 @@ pub struct BinaryHeap<T> {
 #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 pub struct PeekMut<'a, T: 'a + Ord> {
     heap: &'a mut BinaryHeap<T>,
+    sift: bool,
 }
 
 #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
 impl<'a, T: Ord> Drop for PeekMut<'a, T> {
     fn drop(&mut self) {
-        self.heap.sift_down(0);
+        if self.sift {
+            self.heap.sift_down(0);
+        }
     }
 }
 
@@ -250,6 +252,16 @@ impl<'a, T: Ord> DerefMut for PeekMut<'a, T> {
     }
 }
 
+impl<'a, T: Ord> PeekMut<'a, T> {
+    /// Removes the peeked value from the heap and returns it.
+    #[unstable(feature = "binary_heap_peek_mut_pop", issue = "0")]
+    pub fn pop(mut this: PeekMut<'a, T>) -> T {
+        let value = this.heap.pop().unwrap();
+        this.sift = false;
+        value
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: Clone> Clone for BinaryHeap<T> {
     fn clone(&self) -> Self {
@@ -385,7 +397,10 @@ impl<T: Ord> BinaryHeap<T> {
         if self.is_empty() {
             None
         } else {
-            Some(PeekMut { heap: self })
+            Some(PeekMut {
+                heap: self,
+                sift: true,
+            })
         }
     }
 
diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollectionstest/binary_heap.rs
index 9cd63d87931..1df341d1fc2 100644
--- a/src/libcollectionstest/binary_heap.rs
+++ b/src/libcollectionstest/binary_heap.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use std::collections::BinaryHeap;
-use std::collections::binary_heap::Drain;
+use std::collections::binary_heap::{Drain, PeekMut};
 
 #[test]
 fn test_iterator() {
@@ -95,6 +95,19 @@ fn test_peek_mut() {
 }
 
 #[test]
+fn test_peek_mut_pop() {
+    let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
+    let mut heap = BinaryHeap::from(data);
+    assert_eq!(heap.peek(), Some(&10));
+    {
+        let mut top = heap.peek_mut().unwrap();
+        *top -= 2;
+        assert_eq!(PeekMut::pop(top), 8);
+    }
+    assert_eq!(heap.peek(), Some(&9));
+}
+
+#[test]
 fn test_push() {
     let mut heap = BinaryHeap::from(vec![2, 4, 9]);
     assert_eq!(heap.len(), 3);
diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs
index d4fb5ea03ad..ee555ee351e 100644
--- a/src/libcollectionstest/lib.rs
+++ b/src/libcollectionstest/lib.rs
@@ -11,6 +11,7 @@
 #![deny(warnings)]
 
 #![feature(binary_heap_extras)]
+#![feature(binary_heap_peek_mut_pop)]
 #![feature(box_syntax)]
 #![feature(btree_range)]
 #![feature(collections)]