about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMartin Hafskjold Thoresen <martinhath@gmail.com>2017-01-14 13:58:41 +0100
committerMartin Hafskjold Thoresen <martinhath@gmail.com>2017-01-14 13:58:41 +0100
commitfb3483c827e1ef8ad73b200fb73f1dd03994e510 (patch)
tree4016201c6bcd189b5fd294d40687d6fc575e0486
parent7d82d95af9c54c3947f6c6e21a6d632d9ee468de (diff)
downloadrust-fb3483c827e1ef8ad73b200fb73f1dd03994e510.tar.gz
rust-fb3483c827e1ef8ad73b200fb73f1dd03994e510.zip
Add initial impl of placement-in for `BinaryHeap`
-rw-r--r--src/libcollections/binary_heap.rs77
-rw-r--r--src/libcollectionstest/binary_heap.rs21
2 files changed, 97 insertions, 1 deletions
diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs
index 7d245f79f69..8fcc7e0d4da 100644
--- a/src/libcollections/binary_heap.rs
+++ b/src/libcollections/binary_heap.rs
@@ -151,7 +151,7 @@
 #![allow(missing_docs)]
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use core::ops::{Deref, DerefMut};
+use core::ops::{Deref, DerefMut, Place, Placer, InPlace};
 use core::iter::{FromIterator, FusedIterator};
 use core::mem::{swap, size_of};
 use core::ptr;
@@ -688,6 +688,22 @@ impl<T: Ord> BinaryHeap<T> {
         }
     }
 
+    fn sift_up_ind(&mut self, start: usize, pos: usize) -> usize {
+        unsafe {
+            // Take out the value at `pos` and create a hole.
+            let mut hole = Hole::new(&mut self.data, pos);
+
+            while hole.pos() > start {
+                let parent = (hole.pos() - 1) / 2;
+                if hole.element() <= hole.get(parent) {
+                    return hole.pos();
+                }
+                hole.move_to(parent);
+            }
+            hole.pos()
+        }
+    }
+
     /// Take an element at `pos` and move it down the heap,
     /// while its children are larger.
     fn sift_down_range(&mut self, pos: usize, end: usize) {
@@ -889,6 +905,19 @@ impl<T: Ord> BinaryHeap<T> {
     }
 }
 
+impl<T> BinaryHeap<T>
+where T: Clone + Ord {
+    /// kek
+    #[unstable(feature = "collection_placement",
+               reason = "placement protocol is subject to change",
+               issue = "30172")]
+    pub fn place(&mut self) -> PlaceIn<T> {
+        PlaceIn {
+            heap: self,
+        }
+    }
+}
+
 /// Hole represents a hole in a slice i.e. an index without valid value
 /// (because it was moved from or duplicated).
 /// In drop, `Hole` will restore the slice by filling the hole
@@ -1189,3 +1218,49 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
         self.extend(iter.into_iter().cloned());
     }
 }
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+pub struct PlaceIn<'a, T: 'a>
+where T: Clone + Ord {
+    heap: &'a mut BinaryHeap<T>,
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> Place<T> for PlaceIn<'a, T>
+where T: Clone + Ord {
+    fn pointer(&mut self) -> *mut T {
+        self.heap.data.place_back().pointer()
+    }
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> Placer<T> for PlaceIn<'a, T>
+where T: Clone + Ord {
+    type Place = PlaceIn<'a, T>;
+
+    fn make_place(self) -> Self {
+        let _ = self.heap.data.place_back().make_place();
+        self
+    }
+}
+
+#[unstable(feature = "collection_placement",
+           reason = "placement protocol is subject to change",
+           issue = "30172")]
+impl<'a, T> InPlace<T> for PlaceIn<'a, T>
+where T: Clone + Ord {
+    type Owner = &'a T;
+
+    unsafe fn finalize(self) -> &'a T {
+        let len = self.heap.len();
+        let _ = self.heap.data.place_back().finalize();
+        let i = self.heap.sift_up_ind(0, len);
+        &mut self.heap.data[i]
+    }
+}
diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollectionstest/binary_heap.rs
index 1df341d1fc2..a0846f57082 100644
--- a/src/libcollectionstest/binary_heap.rs
+++ b/src/libcollectionstest/binary_heap.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::panic;
 use std::collections::BinaryHeap;
 use std::collections::binary_heap::{Drain, PeekMut};
 
@@ -310,6 +311,26 @@ fn test_extend_specialization() {
     assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
 }
 
+#[test]
+fn test_placement() {
+    let mut a = BinaryHeap::new();
+    a.place() <- 2;
+    a.place() <- 4;
+    a.place() <- 3;
+    assert_eq!(a.peek(), Some(&4));
+    assert_eq!(a.len(), 3);
+    a.place() <- 1;
+    assert_eq!(a.into_sorted_vec(), vec![1, 2, 3, 4]);
+}
+
+#[test]
+fn test_placement_panic() {
+    let mut heap = BinaryHeap::from(vec![1, 2, 3]);
+    fn mkpanic() -> usize { panic!() }
+    let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { heap.place() <- mkpanic(); }));
+    assert_eq!(heap.len(), 3);
+}
+
 #[allow(dead_code)]
 fn assert_covariance() {
     fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {