about summary refs log tree commit diff
path: root/src/libstd/priority_queue.rs
diff options
context:
space:
mode:
authorDaniel Micay <danielmicay@gmail.com>2012-12-15 13:24:10 -0500
committerBrian Anderson <banderson@mozilla.com>2012-12-16 19:27:06 -0800
commitb3463ea65773972e4b5ec9ba4ef35b5f9e595284 (patch)
tree10b7289166711edeadf5638cca0db7bfaf11e394 /src/libstd/priority_queue.rs
parent6c433f22a152f6825f3610382176aaa191ebf7cb (diff)
downloadrust-b3463ea65773972e4b5ec9ba4ef35b5f9e595284.tar.gz
rust-b3463ea65773972e4b5ec9ba4ef35b5f9e595284.zip
priority_queue: replace copies with moves
Diffstat (limited to 'src/libstd/priority_queue.rs')
-rw-r--r--src/libstd/priority_queue.rs34
1 files changed, 24 insertions, 10 deletions
diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs
index 4f29c1ea970..c62b3897c30 100644
--- a/src/libstd/priority_queue.rs
+++ b/src/libstd/priority_queue.rs
@@ -1,12 +1,18 @@
 
 /// A priority queue implemented with a binary heap
 use core::cmp::Ord;
+use ptr::addr_of;
 
-pub struct PriorityQueue <T: Copy Ord>{
+#[abi = "rust-intrinsic"]
+extern "C" mod rusti {
+    fn move_val_init<T>(dst: &mut T, -src: T);
+}
+
+pub struct PriorityQueue <T: Ord>{
     priv data: ~[T],
 }
 
-impl <T: Copy Ord> PriorityQueue<T> {
+impl <T: Ord> PriorityQueue<T> {
     /// Returns the greatest item in the queue - fails if empty
     pure fn top(&self) -> &self/T { &self.data[0] }
 
@@ -97,26 +103,33 @@ impl <T: Copy Ord> PriorityQueue<T> {
         q
     }
 
-    priv fn siftup(&mut self, start: uint, pos: uint) {
+    // The implementations of siftup and siftdown use unsafe blocks in order to
+    // move an element out of the vector (leaving behind a junk element), shift
+    // along the others and move it back into the vector over the junk element.
+    // This reduces the constant factor compared to using swaps, which involves
+    // twice as many moves.
+
+    priv fn siftup(&mut self, start: uint, pos: uint) unsafe {
         let mut pos = pos;
-        let new = self.data[pos];
+        let new = move *addr_of(&self.data[pos]);
 
         while pos > start {
             let parent = (pos - 1) >> 1;
             if new > self.data[parent] {
-                self.data[pos] = self.data[parent];
+                rusti::move_val_init(&mut self.data[pos],
+                                     move *addr_of(&self.data[parent]));
                 pos = parent;
                 loop
             }
             break
         }
-        self.data[pos] = new;
+        rusti::move_val_init(&mut self.data[pos], move new);
     }
 
-    priv fn siftdown_range(&mut self, pos: uint, end: uint) {
+    priv fn siftdown_range(&mut self, pos: uint, end: uint) unsafe {
         let mut pos = pos;
         let start = pos;
-        let new = self.data[pos];
+        let new = move *addr_of(&self.data[pos]);
 
         let mut child = 2 * pos + 1;
         while child < end {
@@ -124,11 +137,12 @@ impl <T: Copy Ord> PriorityQueue<T> {
             if right < end && !(self.data[child] > self.data[right]) {
                 child = right;
             }
-            self.data[pos] = self.data[child];
+            rusti::move_val_init(&mut self.data[pos],
+                                 move *addr_of(&self.data[child]));
             pos = child;
             child = 2 * pos + 1;
         }
-        self.data[pos] = new;
+        rusti::move_val_init(&mut self.data[pos], move new);
         self.siftup(start, pos);
     }