Skip to content

Commit d8d7174

Browse files
committed
Auto merge of #32987 - xosmig:binary_heap_extension, r=apasel422
collections: add append for binary heap
2 parents b5de94f + faeba73 commit d8d7174

File tree

3 files changed

+121
-5
lines changed

3 files changed

+121
-5
lines changed

src/libcollections/binary_heap.rs

+88-5
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,15 @@
153153

154154
use core::iter::FromIterator;
155155
use core::mem::swap;
156+
use core::mem::size_of;
156157
use core::ptr;
157158
use core::fmt;
158159

159160
use slice;
160161
use vec::{self, Vec};
161162

163+
use super::SpecExtend;
164+
162165
/// A priority queue implemented with a binary heap.
163166
///
164167
/// This will be a max-heap.
@@ -738,6 +741,71 @@ impl<T: Ord> BinaryHeap<T> {
738741
pub fn clear(&mut self) {
739742
self.drain();
740743
}
744+
745+
fn rebuild(&mut self) {
746+
let mut n = self.len() / 2;
747+
while n > 0 {
748+
n -= 1;
749+
self.sift_down(n);
750+
}
751+
}
752+
753+
/// Moves all the elements of `other` into `self`, leaving `other` empty.
754+
///
755+
/// # Examples
756+
///
757+
/// Basic usage:
758+
///
759+
/// ```
760+
/// #![feature(binary_heap_append)]
761+
///
762+
/// use std::collections::BinaryHeap;
763+
///
764+
/// let v = vec![-10, 1, 2, 3, 3];
765+
/// let mut a = BinaryHeap::from(v);
766+
///
767+
/// let v = vec![-20, 5, 43];
768+
/// let mut b = BinaryHeap::from(v);
769+
///
770+
/// a.append(&mut b);
771+
///
772+
/// assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
773+
/// assert!(b.is_empty());
774+
/// ```
775+
#[unstable(feature = "binary_heap_append",
776+
reason = "needs to be audited",
777+
issue = "32526")]
778+
pub fn append(&mut self, other: &mut Self) {
779+
if self.len() < other.len() {
780+
swap(self, other);
781+
}
782+
783+
if other.is_empty() {
784+
return;
785+
}
786+
787+
#[inline(always)]
788+
fn log2_fast(x: usize) -> usize {
789+
8 * size_of::<usize>() - (x.leading_zeros() as usize) - 1
790+
}
791+
792+
// `rebuild` takes O(len1 + len2) operations
793+
// and about 2 * (len1 + len2) comparisons in the worst case
794+
// while `extend` takes O(len2 * log_2(len1)) operations
795+
// and about 1 * len2 * log_2(len1) comparisons in the worst case,
796+
// assuming len1 >= len2.
797+
#[inline]
798+
fn better_to_rebuild(len1: usize, len2: usize) -> bool {
799+
2 * (len1 + len2) < len2 * log2_fast(len1)
800+
}
801+
802+
if better_to_rebuild(self.len(), other.len()) {
803+
self.data.append(&mut other.data);
804+
self.rebuild();
805+
} else {
806+
self.extend(other.drain());
807+
}
808+
}
741809
}
742810

743811
/// Hole represents a hole in a slice i.e. an index without valid value
@@ -917,11 +985,7 @@ impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
917985
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
918986
fn from(vec: Vec<T>) -> BinaryHeap<T> {
919987
let mut heap = BinaryHeap { data: vec };
920-
let mut n = heap.len() / 2;
921-
while n > 0 {
922-
n -= 1;
923-
heap.sift_down(n);
924-
}
988+
heap.rebuild();
925989
heap
926990
}
927991
}
@@ -980,7 +1044,26 @@ impl<'a, T> IntoIterator for &'a BinaryHeap<T> where T: Ord {
9801044

9811045
#[stable(feature = "rust1", since = "1.0.0")]
9821046
impl<T: Ord> Extend<T> for BinaryHeap<T> {
1047+
#[inline]
9831048
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1049+
<Self as SpecExtend<I>>::spec_extend(self, iter);
1050+
}
1051+
}
1052+
1053+
impl<T: Ord, I: IntoIterator<Item = T>> SpecExtend<I> for BinaryHeap<T> {
1054+
default fn spec_extend(&mut self, iter: I) {
1055+
self.extend_desugared(iter.into_iter());
1056+
}
1057+
}
1058+
1059+
impl<T: Ord> SpecExtend<BinaryHeap<T>> for BinaryHeap<T> {
1060+
fn spec_extend(&mut self, ref mut other: BinaryHeap<T>) {
1061+
self.append(other);
1062+
}
1063+
}
1064+
1065+
impl<T: Ord> BinaryHeap<T> {
1066+
fn extend_desugared<I: IntoIterator<Item = T>>(&mut self, iter: I) {
9841067
let iterator = iter.into_iter();
9851068
let (lower, _) = iterator.size_hint();
9861069

src/libcollectionstest/binary_heap.rs

+32
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,35 @@ fn test_extend_ref() {
242242
assert_eq!(a.len(), 5);
243243
assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
244244
}
245+
246+
#[test]
247+
fn test_append() {
248+
let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
249+
let mut b = BinaryHeap::from(vec![-20, 5, 43]);
250+
251+
a.append(&mut b);
252+
253+
assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
254+
assert!(b.is_empty());
255+
}
256+
257+
#[test]
258+
fn test_append_to_empty() {
259+
let mut a = BinaryHeap::new();
260+
let mut b = BinaryHeap::from(vec![-20, 5, 43]);
261+
262+
a.append(&mut b);
263+
264+
assert_eq!(a.into_sorted_vec(), [-20, 5, 43]);
265+
assert!(b.is_empty());
266+
}
267+
268+
#[test]
269+
fn test_extend_specialization() {
270+
let mut a = BinaryHeap::from(vec![-10, 1, 2, 3, 3]);
271+
let b = BinaryHeap::from(vec![-20, 5, 43]);
272+
273+
a.extend(b);
274+
275+
assert_eq!(a.into_sorted_vec(), [-20, -10, 1, 2, 3, 3, 5, 43]);
276+
}

src/libcollectionstest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#![deny(warnings)]
1212

1313
#![feature(binary_heap_extras)]
14+
#![feature(binary_heap_append)]
1415
#![feature(box_syntax)]
1516
#![feature(btree_range)]
1617
#![feature(collections)]

0 commit comments

Comments
 (0)