|
1 | 1 |
|
2 | 2 | /// A priority queue implemented with a binary heap
|
3 | 3 | use core::cmp::Ord;
|
| 4 | +use ptr::addr_of; |
4 | 5 |
|
5 |
| -pub struct PriorityQueue <T: Copy Ord>{ |
| 6 | +#[abi = "rust-intrinsic"] |
| 7 | +extern "C" mod rusti { |
| 8 | + fn move_val_init<T>(dst: &mut T, -src: T); |
| 9 | +} |
| 10 | + |
| 11 | +pub struct PriorityQueue <T: Ord>{ |
6 | 12 | priv data: ~[T],
|
7 | 13 | }
|
8 | 14 |
|
9 |
| -impl <T: Copy Ord> PriorityQueue<T> { |
| 15 | +impl <T: Ord> PriorityQueue<T> { |
10 | 16 | /// Returns the greatest item in the queue - fails if empty
|
11 | 17 | pure fn top(&self) -> &self/T { &self.data[0] }
|
12 | 18 |
|
@@ -97,38 +103,46 @@ impl <T: Copy Ord> PriorityQueue<T> {
|
97 | 103 | q
|
98 | 104 | }
|
99 | 105 |
|
100 |
| - priv fn siftup(&mut self, start: uint, pos: uint) { |
| 106 | + // The implementations of siftup and siftdown use unsafe blocks in order to |
| 107 | + // move an element out of the vector (leaving behind a junk element), shift |
| 108 | + // along the others and move it back into the vector over the junk element. |
| 109 | + // This reduces the constant factor compared to using swaps, which involves |
| 110 | + // twice as many moves. |
| 111 | + |
| 112 | + priv fn siftup(&mut self, start: uint, pos: uint) unsafe { |
101 | 113 | let mut pos = pos;
|
102 |
| - let new = self.data[pos]; |
| 114 | + let new = move *addr_of(&self.data[pos]); |
103 | 115 |
|
104 | 116 | while pos > start {
|
105 | 117 | let parent = (pos - 1) >> 1;
|
106 | 118 | if new > self.data[parent] {
|
107 |
| - self.data[pos] = self.data[parent]; |
| 119 | + rusti::move_val_init(&mut self.data[pos], |
| 120 | + move *addr_of(&self.data[parent])); |
108 | 121 | pos = parent;
|
109 | 122 | loop
|
110 | 123 | }
|
111 | 124 | break
|
112 | 125 | }
|
113 |
| - self.data[pos] = new; |
| 126 | + rusti::move_val_init(&mut self.data[pos], move new); |
114 | 127 | }
|
115 | 128 |
|
116 |
| - priv fn siftdown_range(&mut self, pos: uint, end: uint) { |
| 129 | + priv fn siftdown_range(&mut self, pos: uint, end: uint) unsafe { |
117 | 130 | let mut pos = pos;
|
118 | 131 | let start = pos;
|
119 |
| - let new = self.data[pos]; |
| 132 | + let new = move *addr_of(&self.data[pos]); |
120 | 133 |
|
121 | 134 | let mut child = 2 * pos + 1;
|
122 | 135 | while child < end {
|
123 | 136 | let right = child + 1;
|
124 | 137 | if right < end && !(self.data[child] > self.data[right]) {
|
125 | 138 | child = right;
|
126 | 139 | }
|
127 |
| - self.data[pos] = self.data[child]; |
| 140 | + rusti::move_val_init(&mut self.data[pos], |
| 141 | + move *addr_of(&self.data[child])); |
128 | 142 | pos = child;
|
129 | 143 | child = 2 * pos + 1;
|
130 | 144 | }
|
131 |
| - self.data[pos] = new; |
| 145 | + rusti::move_val_init(&mut self.data[pos], move new); |
132 | 146 | self.siftup(start, pos);
|
133 | 147 | }
|
134 | 148 |
|
|
0 commit comments