From 4957e343f5543bf8be6f5a02bfff5861385647f5 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 9 Dec 2012 20:02:33 -0500 Subject: [PATCH 01/11] add priority queue implementation (binary heap) --- src/libstd/priority_queue.rs | 253 +++++++++++++++++++++++++++++++++++ src/libstd/std.rc | 1 + 2 files changed, 254 insertions(+) create mode 100644 src/libstd/priority_queue.rs diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs new file mode 100644 index 0000000000000..c744ba1ca5cea --- /dev/null +++ b/src/libstd/priority_queue.rs @@ -0,0 +1,253 @@ + +/// A priority queue implemented with a binary heap +use core::cmp::Ord; + +pub struct PriorityQueue { + priv data: ~[T], +} + +impl PriorityQueue { + /// Returns the greatest item in the queue - fails if empty + pure fn top(&self) -> T { self.data[0] } + + /// Returns the greatest item in the queue - None if empty + pure fn maybe_top(&self) -> Option { + if self.is_empty() { None } else { Some(self.top()) } + } + + /// Returns the length of the queue + pure fn len(&self) -> uint { self.data.len() } + + /// Returns true if a queue contains no elements + pure fn is_empty(&self) -> bool { self.data.is_empty() } + + /// Returns true if a queue contains some elements + pure fn is_not_empty(&self) -> bool { self.data.is_not_empty() } + + /// Returns the number of elements the queue can hold without reallocating + pure fn capacity(&self) -> uint { vec::capacity(&self.data) } + + fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) } + + fn reserve_at_least(&mut self, n: uint) { + vec::reserve_at_least(&mut self.data, n) + } + + /// Drop all items from the queue + fn clear(&mut self) { self.data.truncate(0) } + + /// Pop the greatest item from the queue - fails if empty + fn pop(&mut self) -> T { + let last = self.data.pop(); + if self.is_not_empty() { + let ret = self.data[0]; + self.data[0] = last; + self.siftup(0); + ret + } else { last } + } + + /// Pop the greatest item from the queue - None if empty + fn maybe_pop(&mut self) -> Option { + if self.is_empty() { None } else { Some(self.pop()) } + } + + /// Push an item onto the queue + fn push(&mut self, item: T) { + self.data.push(item); + self.siftdown(0, self.len() - 1); + } + + /// Optimized version of a push followed by a pop + fn push_pop(&mut self, item: T) -> T { + let mut item = item; + if self.is_not_empty() && self.data[0] > item { + item <-> self.data[0]; + self.siftup(0); + } + item + } + + /// Optimized version of a pop followed by a push - fails if empty + fn replace(&mut self, item: T) -> T { + let ret = self.data[0]; + self.data[0] = item; + self.siftup(0); + ret + } + + priv fn siftdown(&mut self, startpos: uint, pos: uint) { + let mut pos = pos; + let newitem = self.data[pos]; + + while pos > startpos { + let parentpos = (pos - 1) >> 1; + let parent = self.data[parentpos]; + if newitem > parent { + self.data[pos] = parent; + pos = parentpos; + loop + } + break + } + self.data[pos] = newitem; + } + + priv fn siftup_range(&mut self, pos: uint, endpos: uint) { + let mut pos = pos; + let startpos = pos; + let newitem = self.data[pos]; + + let mut childpos = 2 * pos + 1; + while childpos < endpos { + let rightpos = childpos + 1; + if rightpos < endpos && + !(self.data[childpos] > self.data[rightpos]) { + childpos = rightpos; + } + self.data[pos] = self.data[childpos]; + pos = childpos; + childpos = 2 * pos + 1; + } + self.data[pos] = newitem; + self.siftdown(startpos, pos); + } + + priv fn siftup(&mut self, pos: uint) { + self.siftup_range(pos, self.len()); + } +} + +/// Consume the PriorityQueue and return the underlying vector +pub pure fn to_vec(q: PriorityQueue) -> ~[T] { + let PriorityQueue{data: v} = q; + v +} + +/// Consume the PriorityQueue and return a vector in sorted (ascending) order +pub pure fn to_sorted_vec(q: PriorityQueue) -> ~[T] { + let mut q = q; + let mut end = q.len() - 1; + while end > 0 { + q.data[end] <-> q.data[0]; + end -= 1; + unsafe { q.siftup_range(0, end) } // purity-checking workaround + } + to_vec(q) +} + +pub pure fn from_vec(xs: ~[T]) -> PriorityQueue { + let mut q = PriorityQueue{data: xs,}; + let mut n = q.len() / 2; + while n > 0 { + n -= 1; + unsafe { q.siftup(n) }; // purity-checking workaround + } + q +} + +#[cfg(test)] +mod tests { + use sort::merge_sort; + use core::cmp::le; + + #[test] + fn test_top_and_pop() { + let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; + let mut sorted = merge_sort(data, le); + let mut heap = from_vec(data); + while heap.is_not_empty() { + assert heap.top() == sorted.last(); + assert heap.pop() == sorted.pop(); + } + } + + #[test] + fn test_push() { + let mut heap = from_vec(~[2, 4, 9]); + assert heap.len() == 3; + assert heap.top() == 9; + heap.push(11); + assert heap.len() == 4; + assert heap.top() == 11; + heap.push(5); + assert heap.len() == 5; + assert heap.top() == 11; + heap.push(27); + assert heap.len() == 6; + assert heap.top() == 27; + heap.push(3); + assert heap.len() == 7; + assert heap.top() == 27; + heap.push(103); + assert heap.len() == 8; + assert heap.top() == 103; + } + + #[test] + fn test_push_pop() { + let mut heap = from_vec(~[5, 5, 2, 1, 3]); + assert heap.len() == 5; + assert heap.push_pop(6) == 6; + assert heap.len() == 5; + assert heap.push_pop(0) == 5; + assert heap.len() == 5; + assert heap.push_pop(4) == 5; + assert heap.len() == 5; + assert heap.push_pop(1) == 4; + assert heap.len() == 5; + } + + #[test] + fn test_replace() { + let mut heap = from_vec(~[5, 5, 2, 1, 3]); + assert heap.len() == 5; + assert heap.replace(6) == 5; + assert heap.len() == 5; + assert heap.replace(0) == 6; + assert heap.len() == 5; + assert heap.replace(4) == 5; + assert heap.len() == 5; + assert heap.replace(1) == 4; + assert heap.len() == 5; + } + + #[test] + fn test_to_sorted_vec() { + let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; + assert to_sorted_vec(from_vec(data)) == merge_sort(data, le); + } + + #[test] + #[should_fail] + fn test_empty_pop() { let mut heap = from_vec::(~[]); heap.pop(); } + + #[test] + fn test_empty_maybe_pop() { + let mut heap = from_vec::(~[]); + assert heap.maybe_pop().is_none(); + } + + #[test] + #[should_fail] + fn test_empty_top() { from_vec::(~[]).top(); } + + #[test] + fn test_empty_maybe_top() { + assert from_vec::(~[]).maybe_top().is_none(); + } + + #[test] + #[should_fail] + fn test_empty_replace() { + let mut heap = from_vec::(~[]); + heap.replace(5); + } + + #[test] + fn test_to_vec() { + let data = ~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]; + let heap = from_vec(copy data); + assert merge_sort(to_vec(heap), le) == merge_sort(data, le); + } +} diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 65916aa599274..f5363ca23c503 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -73,6 +73,7 @@ pub mod deque; pub mod fun_treemap; pub mod list; pub mod map; +pub mod priority_queue; pub mod rope; pub mod smallintmap; pub mod sort; From c48ba6304b4b86a69af17243379b5780c42bc4a2 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 10 Dec 2012 15:36:01 -0500 Subject: [PATCH 02/11] priority_queue: make to_vec/to_sorted_vec methods --- src/libstd/priority_queue.rs | 37 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index c744ba1ca5cea..31d6e04ae6267 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -76,6 +76,21 @@ impl PriorityQueue { ret } + /// Consume the PriorityQueue and return the underlying vector + pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v } + + /// Consume the PriorityQueue and return a vector in sorted (ascending) order + pure fn to_sorted_vec(self) -> ~[T] { + let mut q = self; + let mut end = q.len() - 1; + while end > 0 { + q.data[end] <-> q.data[0]; + end -= 1; + unsafe { q.siftup_range(0, end) } // purity-checking workaround + } + q.to_vec() + } + priv fn siftdown(&mut self, startpos: uint, pos: uint) { let mut pos = pos; let newitem = self.data[pos]; @@ -118,24 +133,6 @@ impl PriorityQueue { } } -/// Consume the PriorityQueue and return the underlying vector -pub pure fn to_vec(q: PriorityQueue) -> ~[T] { - let PriorityQueue{data: v} = q; - v -} - -/// Consume the PriorityQueue and return a vector in sorted (ascending) order -pub pure fn to_sorted_vec(q: PriorityQueue) -> ~[T] { - let mut q = q; - let mut end = q.len() - 1; - while end > 0 { - q.data[end] <-> q.data[0]; - end -= 1; - unsafe { q.siftup_range(0, end) } // purity-checking workaround - } - to_vec(q) -} - pub pure fn from_vec(xs: ~[T]) -> PriorityQueue { let mut q = PriorityQueue{data: xs,}; let mut n = q.len() / 2; @@ -215,7 +212,7 @@ mod tests { #[test] fn test_to_sorted_vec() { let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; - assert to_sorted_vec(from_vec(data)) == merge_sort(data, le); + assert from_vec(data).to_sorted_vec() == merge_sort(data, le); } #[test] @@ -248,6 +245,6 @@ mod tests { fn test_to_vec() { let data = ~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]; let heap = from_vec(copy data); - assert merge_sort(to_vec(heap), le) == merge_sort(data, le); + assert merge_sort(heap.to_vec(), le) == merge_sort(data, le); } } From d89da37b0a8d7505ea5d9ce6cb74daea72142efc Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 10 Dec 2012 15:46:41 -0500 Subject: [PATCH 03/11] priority_queue: make from_vec a static method --- src/libstd/priority_queue.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 31d6e04ae6267..b92f5f57a5ff8 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -91,6 +91,16 @@ impl PriorityQueue { q.to_vec() } + static pub pure fn from_vec(xs: ~[T]) -> PriorityQueue { + let mut q = PriorityQueue{data: xs,}; + let mut n = q.len() / 2; + while n > 0 { + n -= 1; + unsafe { q.siftup(n) }; // purity-checking workaround + } + q + } + priv fn siftdown(&mut self, startpos: uint, pos: uint) { let mut pos = pos; let newitem = self.data[pos]; @@ -133,20 +143,11 @@ impl PriorityQueue { } } -pub pure fn from_vec(xs: ~[T]) -> PriorityQueue { - let mut q = PriorityQueue{data: xs,}; - let mut n = q.len() / 2; - while n > 0 { - n -= 1; - unsafe { q.siftup(n) }; // purity-checking workaround - } - q -} - #[cfg(test)] mod tests { use sort::merge_sort; use core::cmp::le; + use PriorityQueue::from_vec; #[test] fn test_top_and_pop() { From 99119096ef0b195c8a531e9d28025cec51850911 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 11 Dec 2012 09:47:36 -0500 Subject: [PATCH 04/11] priority_queue: replace some copies with swaps --- src/libstd/priority_queue.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index b92f5f57a5ff8..ab274970ab3c3 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -38,13 +38,9 @@ impl PriorityQueue { /// Pop the greatest item from the queue - fails if empty fn pop(&mut self) -> T { - let last = self.data.pop(); - if self.is_not_empty() { - let ret = self.data[0]; - self.data[0] = last; - self.siftup(0); - ret - } else { last } + let mut item = self.data.pop(); + if self.is_not_empty() { item <-> self.data[0]; self.siftup(0); } + item } /// Pop the greatest item from the queue - None if empty @@ -70,10 +66,10 @@ impl PriorityQueue { /// Optimized version of a pop followed by a push - fails if empty fn replace(&mut self, item: T) -> T { - let ret = self.data[0]; - self.data[0] = item; + let mut item = item; + item <-> self.data[0]; self.siftup(0); - ret + item } /// Consume the PriorityQueue and return the underlying vector From 45119c38acd442d4a7c56ef424888705e4f0124e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 11 Dec 2012 10:57:37 -0500 Subject: [PATCH 05/11] priority_queue: fix to_sorted_vec off-by-one error --- src/libstd/priority_queue.rs | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index ab274970ab3c3..35d238b4d7cc1 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -78,10 +78,10 @@ impl PriorityQueue { /// Consume the PriorityQueue and return a vector in sorted (ascending) order pure fn to_sorted_vec(self) -> ~[T] { let mut q = self; - let mut end = q.len() - 1; - while end > 0 { - q.data[end] <-> q.data[0]; + let mut end = q.len(); + while end > 1 { end -= 1; + q.data[end] <-> q.data[0]; unsafe { q.siftup_range(0, end) } // purity-checking workaround } q.to_vec() @@ -206,10 +206,27 @@ mod tests { assert heap.len() == 5; } + fn check_to_vec(data: ~[int]) { + let heap = from_vec(data); + assert merge_sort(heap.to_vec(), le) == merge_sort(data, le); + assert heap.to_sorted_vec() == merge_sort(data, le); + } + #[test] - fn test_to_sorted_vec() { - let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; - assert from_vec(data).to_sorted_vec() == merge_sort(data, le); + fn test_to_vec() { + check_to_vec(~[]); + check_to_vec(~[5]); + check_to_vec(~[3, 2]); + check_to_vec(~[2, 3]); + check_to_vec(~[5, 1, 2]); + check_to_vec(~[1, 100, 2, 3]); + check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]); + check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); + check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]); + check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]); + check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]); + check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]); } #[test] @@ -237,11 +254,4 @@ mod tests { let mut heap = from_vec::(~[]); heap.replace(5); } - - #[test] - fn test_to_vec() { - let data = ~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]; - let heap = from_vec(copy data); - assert merge_sort(heap.to_vec(), le) == merge_sort(data, le); - } } From 407b413f5319e34dd54bd4f88c6b9adc64ddc432 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 11 Dec 2012 12:19:20 -0500 Subject: [PATCH 06/11] priority_queue: avoid copy with top and maybe_top --- src/libstd/priority_queue.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 35d238b4d7cc1..d73722dc55b9b 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -8,10 +8,10 @@ pub struct PriorityQueue { impl PriorityQueue { /// Returns the greatest item in the queue - fails if empty - pure fn top(&self) -> T { self.data[0] } + pure fn top(&self) -> &self/T { &self.data[0] } /// Returns the greatest item in the queue - None if empty - pure fn maybe_top(&self) -> Option { + pure fn maybe_top(&self) -> Option<&self/T> { if self.is_empty() { None } else { Some(self.top()) } } @@ -151,7 +151,7 @@ mod tests { let mut sorted = merge_sort(data, le); let mut heap = from_vec(data); while heap.is_not_empty() { - assert heap.top() == sorted.last(); + assert *heap.top() == sorted.last(); assert heap.pop() == sorted.pop(); } } @@ -160,22 +160,22 @@ mod tests { fn test_push() { let mut heap = from_vec(~[2, 4, 9]); assert heap.len() == 3; - assert heap.top() == 9; + assert *heap.top() == 9; heap.push(11); assert heap.len() == 4; - assert heap.top() == 11; + assert *heap.top() == 11; heap.push(5); assert heap.len() == 5; - assert heap.top() == 11; + assert *heap.top() == 11; heap.push(27); assert heap.len() == 6; - assert heap.top() == 27; + assert *heap.top() == 27; heap.push(3); assert heap.len() == 7; - assert heap.top() == 27; + assert *heap.top() == 27; heap.push(103); assert heap.len() == 8; - assert heap.top() == 103; + assert *heap.top() == 103; } #[test] @@ -241,11 +241,12 @@ mod tests { #[test] #[should_fail] - fn test_empty_top() { from_vec::(~[]).top(); } + fn test_empty_top() { let empty = from_vec::(~[]); empty.top(); } #[test] fn test_empty_maybe_top() { - assert from_vec::(~[]).maybe_top().is_none(); + let empty = from_vec::(~[]); + assert empty.maybe_top().is_none(); } #[test] From b5aaa3c6f80cc1545a624e795f46c251cf865c14 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 11 Dec 2012 17:34:50 -0500 Subject: [PATCH 07/11] priority_queue: fix siftup/siftdown naming --- src/libstd/priority_queue.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index d73722dc55b9b..fba9a8577a870 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -39,7 +39,7 @@ impl PriorityQueue { /// Pop the greatest item from the queue - fails if empty fn pop(&mut self) -> T { let mut item = self.data.pop(); - if self.is_not_empty() { item <-> self.data[0]; self.siftup(0); } + if self.is_not_empty() { item <-> self.data[0]; self.siftdown(0); } item } @@ -51,7 +51,7 @@ impl PriorityQueue { /// Push an item onto the queue fn push(&mut self, item: T) { self.data.push(item); - self.siftdown(0, self.len() - 1); + self.siftup(0, self.len() - 1); } /// Optimized version of a push followed by a pop @@ -59,7 +59,7 @@ impl PriorityQueue { let mut item = item; if self.is_not_empty() && self.data[0] > item { item <-> self.data[0]; - self.siftup(0); + self.siftdown(0); } item } @@ -68,7 +68,7 @@ impl PriorityQueue { fn replace(&mut self, item: T) -> T { let mut item = item; item <-> self.data[0]; - self.siftup(0); + self.siftdown(0); item } @@ -82,7 +82,7 @@ impl PriorityQueue { while end > 1 { end -= 1; q.data[end] <-> q.data[0]; - unsafe { q.siftup_range(0, end) } // purity-checking workaround + unsafe { q.siftdown_range(0, end) } // purity-checking workaround } q.to_vec() } @@ -92,12 +92,12 @@ impl PriorityQueue { let mut n = q.len() / 2; while n > 0 { n -= 1; - unsafe { q.siftup(n) }; // purity-checking workaround + unsafe { q.siftdown(n) }; // purity-checking workaround } q } - priv fn siftdown(&mut self, startpos: uint, pos: uint) { + priv fn siftup(&mut self, startpos: uint, pos: uint) { let mut pos = pos; let newitem = self.data[pos]; @@ -114,7 +114,7 @@ impl PriorityQueue { self.data[pos] = newitem; } - priv fn siftup_range(&mut self, pos: uint, endpos: uint) { + priv fn siftdown_range(&mut self, pos: uint, endpos: uint) { let mut pos = pos; let startpos = pos; let newitem = self.data[pos]; @@ -131,11 +131,11 @@ impl PriorityQueue { childpos = 2 * pos + 1; } self.data[pos] = newitem; - self.siftdown(startpos, pos); + self.siftup(startpos, pos); } - priv fn siftup(&mut self, pos: uint) { - self.siftup_range(pos, self.len()); + priv fn siftdown(&mut self, pos: uint) { + self.siftdown_range(pos, self.len()); } } From ccdfeca1e0775218625a382f17075b5768a10e3c Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 15 Dec 2012 11:15:25 -0500 Subject: [PATCH 08/11] priority_queue: fix test compilation --- src/libstd/priority_queue.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index fba9a8577a870..13cc5d854762a 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -143,7 +143,7 @@ impl PriorityQueue { mod tests { use sort::merge_sort; use core::cmp::le; - use PriorityQueue::from_vec; + use priority_queue::PriorityQueue::from_vec; #[test] fn test_top_and_pop() { From 78c8d31f1657a4f60525b2418941798bbe55306f Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 15 Dec 2012 12:14:07 -0500 Subject: [PATCH 09/11] priority_queue: clean up naming --- src/libstd/priority_queue.rs | 48 +++++++++++++++++------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 13cc5d854762a..4f29c1ea97034 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -97,41 +97,39 @@ impl PriorityQueue { q } - priv fn siftup(&mut self, startpos: uint, pos: uint) { + priv fn siftup(&mut self, start: uint, pos: uint) { let mut pos = pos; - let newitem = self.data[pos]; - - while pos > startpos { - let parentpos = (pos - 1) >> 1; - let parent = self.data[parentpos]; - if newitem > parent { - self.data[pos] = parent; - pos = parentpos; + let new = self.data[pos]; + + while pos > start { + let parent = (pos - 1) >> 1; + if new > self.data[parent] { + self.data[pos] = self.data[parent]; + pos = parent; loop } break } - self.data[pos] = newitem; + self.data[pos] = new; } - priv fn siftdown_range(&mut self, pos: uint, endpos: uint) { + priv fn siftdown_range(&mut self, pos: uint, end: uint) { let mut pos = pos; - let startpos = pos; - let newitem = self.data[pos]; - - let mut childpos = 2 * pos + 1; - while childpos < endpos { - let rightpos = childpos + 1; - if rightpos < endpos && - !(self.data[childpos] > self.data[rightpos]) { - childpos = rightpos; + let start = pos; + let new = self.data[pos]; + + let mut child = 2 * pos + 1; + while child < end { + let right = child + 1; + if right < end && !(self.data[child] > self.data[right]) { + child = right; } - self.data[pos] = self.data[childpos]; - pos = childpos; - childpos = 2 * pos + 1; + self.data[pos] = self.data[child]; + pos = child; + child = 2 * pos + 1; } - self.data[pos] = newitem; - self.siftup(startpos, pos); + self.data[pos] = new; + self.siftup(start, pos); } priv fn siftdown(&mut self, pos: uint) { From 07d91b2cb05fdad425b770776ec4bc8bf6c59911 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 15 Dec 2012 13:24:10 -0500 Subject: [PATCH 10/11] priority_queue: replace copies with moves --- src/libstd/priority_queue.rs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 4f29c1ea97034..c62b3897c30af 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 { +#[abi = "rust-intrinsic"] +extern "C" mod rusti { + fn move_val_init(dst: &mut T, -src: T); +} + +pub struct PriorityQueue { priv data: ~[T], } -impl PriorityQueue { +impl PriorityQueue { /// Returns the greatest item in the queue - fails if empty pure fn top(&self) -> &self/T { &self.data[0] } @@ -97,26 +103,33 @@ impl PriorityQueue { 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 PriorityQueue { 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); } From d25b0aac50133e848547c7653ae6798b10e5f550 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 15 Dec 2012 14:29:38 -0500 Subject: [PATCH 11/11] priority_queue: add docstring for from_vec --- src/libstd/priority_queue.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index c62b3897c30af..bb9d5f5261f64 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -93,6 +93,7 @@ impl PriorityQueue { q.to_vec() } + /// Create a PriorityQueue from a vector (heapify) static pub pure fn from_vec(xs: ~[T]) -> PriorityQueue { let mut q = PriorityQueue{data: xs,}; let mut n = q.len() / 2;