Skip to content

[WIP] Add From<(Vec<T>, C)> for BinaryHeap a.k.a. flexible BinaryHeap #69454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
215 changes: 169 additions & 46 deletions src/liballoc/collections/binary_heap.rs
Original file line number Diff line number Diff line change
@@ -145,7 +145,9 @@
#![allow(missing_docs)]
#![stable(feature = "rust1", since = "1.0.0")]

use core::cmp::Ordering;
use core::fmt;
use core::fmt::Debug;
use core::iter::{FromIterator, FusedIterator, TrustedLen};
use core::mem::{size_of, swap, ManuallyDrop};
use core::ops::{Deref, DerefMut};
@@ -246,8 +248,39 @@ use super::SpecExtend;
/// [peek]: #method.peek
/// [peek\_mut]: #method.peek_mut
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BinaryHeap<T> {
pub struct BinaryHeap<T, C = MaxCmp>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
data: Vec<T>,
cmp: C,
}

/// Default comparator which is used in Max heap.
#[unstable(feature = "binary_heap_max_cmp", issue = "38886")]
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug)]
pub struct MaxCmp;

#[unstable(feature = "binary_heap_max_cmp", issue = "38886")]
impl<T: Ord> FnOnce<(&T, &T)> for MaxCmp {
type Output = Option<Ordering>;
extern "rust-call" fn call_once(self, args: (&T, &T)) -> Self::Output {
args.0.partial_cmp(args.1)
}
}

#[unstable(feature = "binary_heap_max_cmp", issue = "38886")]
impl<T: Ord> FnMut<(&T, &T)> for MaxCmp {
extern "rust-call" fn call_mut(&mut self, args: (&T, &T)) -> Self::Output {
args.0.partial_cmp(args.1)
}
}

#[unstable(feature = "binary_heap_max_cmp", issue = "38886")]
impl<T: Ord> Fn<(&T, &T)> for MaxCmp {
extern "rust-call" fn call(&self, args: (&T, &T)) -> Self::Output {
args.0.partial_cmp(args.1)
}
}

/// Structure wrapping a mutable reference to the greatest item on a
@@ -259,20 +292,29 @@ pub struct BinaryHeap<T> {
/// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut
/// [`BinaryHeap`]: struct.BinaryHeap.html
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
pub struct PeekMut<'a, T: 'a + Ord> {
heap: &'a mut BinaryHeap<T>,
pub struct PeekMut<'a, T: 'a, C = MaxCmp>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
heap: &'a mut BinaryHeap<T, C>,
sift: bool,
}

#[stable(feature = "collection_debug", since = "1.17.0")]
impl<T: Ord + fmt::Debug> fmt::Debug for PeekMut<'_, T> {
impl<T: fmt::Debug, C> fmt::Debug for PeekMut<'_, T, C>
where
C: Fn(&T, &T) -> Option<Ordering> + Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("PeekMut").field(&self.heap.data[0]).finish()
}
}

#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
impl<T: Ord> Drop for PeekMut<'_, T> {
impl<T, C> Drop for PeekMut<'_, T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
fn drop(&mut self) {
if self.sift {
self.heap.sift_down(0);
@@ -281,7 +323,10 @@ impl<T: Ord> Drop for PeekMut<'_, T> {
}

#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
impl<T: Ord> Deref for PeekMut<'_, T> {
impl<T, C> Deref for PeekMut<'_, T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
type Target = T;
fn deref(&self) -> &T {
debug_assert!(!self.heap.is_empty());
@@ -291,28 +336,37 @@ impl<T: Ord> Deref for PeekMut<'_, T> {
}

#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
impl<T: Ord> DerefMut for PeekMut<'_, T> {
impl<T, C> DerefMut for PeekMut<'_, T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
fn deref_mut(&mut self) -> &mut T {
debug_assert!(!self.heap.is_empty());
// SAFE: PeekMut is only instantiated for non-empty heaps
unsafe { self.heap.data.get_unchecked_mut(0) }
}
}

impl<'a, T: Ord> PeekMut<'a, T> {
impl<'a, T: Ord, C> PeekMut<'a, T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
/// Removes the peeked value from the heap and returns it.
#[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")]
pub fn pop(mut this: PeekMut<'a, T>) -> T {
pub fn pop(mut this: PeekMut<'a, T, C>) -> T {
let value = this.heap.pop().unwrap();
this.sift = false;
value
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Clone> Clone for BinaryHeap<T> {
impl<T: Clone, C> Clone for BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering> + Clone,
{
fn clone(&self) -> Self {
BinaryHeap { data: self.data.clone() }
BinaryHeap { data: self.data.clone(), cmp: self.cmp.clone() }
}

fn clone_from(&mut self, source: &Self) {
@@ -330,7 +384,10 @@ impl<T: Ord> Default for BinaryHeap<T> {
}

#[stable(feature = "binaryheap_debug", since = "1.4.0")]
impl<T: fmt::Debug> fmt::Debug for BinaryHeap<T> {
impl<T: fmt::Debug, C> fmt::Debug for BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
@@ -350,7 +407,7 @@ impl<T: Ord> BinaryHeap<T> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> BinaryHeap<T> {
BinaryHeap { data: vec![] }
BinaryHeap { data: vec![], cmp: MaxCmp::default() }
}

/// Creates an empty `BinaryHeap` with a specific capacity.
@@ -369,9 +426,14 @@ impl<T: Ord> BinaryHeap<T> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(capacity: usize) -> BinaryHeap<T> {
BinaryHeap { data: Vec::with_capacity(capacity) }
BinaryHeap { data: Vec::with_capacity(capacity), cmp: MaxCmp::default() }
}
}

impl<T, C> BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
/// Returns a mutable reference to the greatest item in the binary heap, or
/// `None` if it is empty.
///
@@ -401,7 +463,7 @@ impl<T: Ord> BinaryHeap<T> {
///
/// Cost is O(1) in the worst case.
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T, C>> {
if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) }
}

@@ -518,7 +580,8 @@ impl<T: Ord> BinaryHeap<T> {

while hole.pos() > start {
let parent = (hole.pos() - 1) / 2;
if hole.element() <= hole.get(parent) {
let res = (self.cmp)(hole.element(), hole.get(parent));
if res == Some(Ordering::Less) || res == Some(Ordering::Equal) {
break;
}
hole.move_to(parent);
@@ -536,11 +599,14 @@ impl<T: Ord> BinaryHeap<T> {
while child < end {
let right = child + 1;
// compare with the greater of the two children
if right < end && !(hole.get(child) > hole.get(right)) {
if right < end
&& (self.cmp)(hole.get(child), hole.get(right)) != Some(Ordering::Greater)
{
child = right;
}
// if we are already in order, stop.
if hole.element() >= hole.get(child) {
let res = (self.cmp)(hole.element(), hole.get(child));
if res == Some(Ordering::Greater) || res == Some(Ordering::Equal) {
break;
}
hole.move_to(child);
@@ -568,7 +634,9 @@ impl<T: Ord> BinaryHeap<T> {
while child < end {
let right = child + 1;
// compare with the greater of the two children
if right < end && !(hole.get(child) > hole.get(right)) {
if right < end
&& (self.cmp)(hole.get(child), hole.get(right)) != Some(Ordering::Greater)
{
child = right;
}
hole.move_to(child);
@@ -664,12 +732,15 @@ impl<T: Ord> BinaryHeap<T> {
/// ```
#[inline]
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
pub fn drain_sorted(&mut self) -> DrainSorted<'_, T, C> {
DrainSorted { inner: self }
}
}

impl<T> BinaryHeap<T> {
impl<T, C> BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
/// Returns an iterator visiting all values in the underlying vector, in
/// arbitrary order.
///
@@ -706,7 +777,7 @@ impl<T> BinaryHeap<T> {
/// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
/// ```
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
pub fn into_iter_sorted(self) -> IntoIterSorted<T, C> {
IntoIterSorted { inner: self }
}

@@ -1147,12 +1218,18 @@ impl<T> FusedIterator for IntoIter<T> {}

#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
#[derive(Clone, Debug)]
pub struct IntoIterSorted<T> {
inner: BinaryHeap<T>,
pub struct IntoIterSorted<T, C = MaxCmp>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
inner: BinaryHeap<T, C>,
}

#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
impl<T: Ord> Iterator for IntoIterSorted<T> {
impl<T, C> Iterator for IntoIterSorted<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
type Item = T;

#[inline]
@@ -1168,13 +1245,13 @@ impl<T: Ord> Iterator for IntoIterSorted<T> {
}

#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {}
impl<T, C: Debug> ExactSizeIterator for IntoIterSorted<T, C> where C: Fn(&T, &T) -> Option<Ordering> {}

#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
impl<T: Ord> FusedIterator for IntoIterSorted<T> {}
impl<T, C: Debug> FusedIterator for IntoIterSorted<T, C> where C: Fn(&T, &T) -> Option<Ordering> {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T: Ord> TrustedLen for IntoIterSorted<T> {}
unsafe impl<T, C: Debug> TrustedLen for IntoIterSorted<T, C> where C: Fn(&T, &T) -> Option<Ordering> {}

/// A draining iterator over the elements of a `BinaryHeap`.
///
@@ -1231,20 +1308,29 @@ impl<T> FusedIterator for Drain<'_, T> {}
/// [`BinaryHeap`]: struct.BinaryHeap.html
#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
#[derive(Debug)]
pub struct DrainSorted<'a, T: Ord> {
inner: &'a mut BinaryHeap<T>,
pub struct DrainSorted<'a, T, C = MaxCmp>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
inner: &'a mut BinaryHeap<T, C>,
}

#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
impl<'a, T: Ord> Drop for DrainSorted<'a, T> {
impl<'a, T, C> Drop for DrainSorted<'a, T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
/// Removes heap elements in heap order.
fn drop(&mut self) {
while let Some(_) = self.inner.pop() {}
}
}

#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
impl<T: Ord> Iterator for DrainSorted<'_, T> {
impl<T, C> Iterator for DrainSorted<'_, T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
type Item = T;

#[inline]
@@ -1260,29 +1346,45 @@ impl<T: Ord> Iterator for DrainSorted<'_, T> {
}

#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> {}
impl<T, C> ExactSizeIterator for DrainSorted<'_, T, C> where C: Fn(&T, &T) -> Option<Ordering> {}

#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
impl<T: Ord> FusedIterator for DrainSorted<'_, T> {}
impl<T, C> FusedIterator for DrainSorted<'_, T, C> where C: Fn(&T, &T) -> Option<Ordering> {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, T> {}
unsafe impl<T, C> TrustedLen for DrainSorted<'_, T, C> where C: Fn(&T, &T) -> Option<Ordering> {}

#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
/// Converts a `Vec<T>` into a `BinaryHeap<T>`.
///
/// This conversion happens in-place, and has `O(n)` time complexity.
fn from(vec: Vec<T>) -> BinaryHeap<T> {
let mut heap = BinaryHeap { data: vec };
BinaryHeap::from((vec, MaxCmp::default()))
}
}

#[unstable(feature = "binary_heap_from_vec_cmp", issue = "38886")]
impl<T, C> From<(Vec<T>, C)> for BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
/// Converts a `Vec<T>` and comparator into a `BinaryHeap<T>`.
///
/// This conversion happens in-place, and has `O(n)` time complexity.
fn from(vec_cmp: (Vec<T>, C)) -> BinaryHeap<T, C> {
let mut heap = BinaryHeap { data: vec_cmp.0, cmp: vec_cmp.1 };
heap.rebuild();
heap
}
}

#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T> From<BinaryHeap<T>> for Vec<T> {
fn from(heap: BinaryHeap<T>) -> Vec<T> {
impl<T, C> From<BinaryHeap<T, C>> for Vec<T>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
fn from(heap: BinaryHeap<T, C>) -> Vec<T> {
heap.data
}
}
@@ -1295,7 +1397,10 @@ impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> IntoIterator for BinaryHeap<T> {
impl<T, C> IntoIterator for BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
type Item = T;
type IntoIter = IntoIter<T>;

@@ -1323,7 +1428,10 @@ impl<T> IntoIterator for BinaryHeap<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> IntoIterator for &'a BinaryHeap<T> {
impl<'a, T, C> IntoIterator for &'a BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
type Item = &'a T;
type IntoIter = Iter<'a, T>;

@@ -1333,26 +1441,38 @@ impl<'a, T> IntoIterator for &'a BinaryHeap<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Extend<T> for BinaryHeap<T> {
impl<T, C> Extend<T> for BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
#[inline]
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
<Self as SpecExtend<I>>::spec_extend(self, iter);
}
}

impl<T: Ord, I: IntoIterator<Item = T>> SpecExtend<I> for BinaryHeap<T> {
impl<T, I: IntoIterator<Item = T>, C> SpecExtend<I> for BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
default fn spec_extend(&mut self, iter: I) {
self.extend_desugared(iter.into_iter());
}
}

impl<T: Ord> SpecExtend<BinaryHeap<T>> for BinaryHeap<T> {
fn spec_extend(&mut self, ref mut other: BinaryHeap<T>) {
impl<T, C> SpecExtend<BinaryHeap<T, C>> for BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
fn spec_extend(&mut self, ref mut other: BinaryHeap<T, C>) {
self.append(other);
}
}

impl<T: Ord> BinaryHeap<T> {
impl<T, C> BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
fn extend_desugared<I: IntoIterator<Item = T>>(&mut self, iter: I) {
let iterator = iter.into_iter();
let (lower, _) = iterator.size_hint();
@@ -1364,7 +1484,10 @@ impl<T: Ord> BinaryHeap<T> {
}

#[stable(feature = "extend_ref", since = "1.2.0")]
impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
impl<'a, T: 'a + Copy, C> Extend<&'a T> for BinaryHeap<T, C>
where
C: Fn(&T, &T) -> Option<Ordering>,
{
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
}
30 changes: 30 additions & 0 deletions src/liballoc/tests/binary_heap.rs
Original file line number Diff line number Diff line change
@@ -257,6 +257,36 @@ fn test_from_iter() {
}
}

#[test]
fn test_from_vec_cmp() {
// closure
let heap =
BinaryHeap::from((vec![2, 3, 89, 5, 8, 1, 13, 21, 34, 55, 1], |a: &i32, b: &i32| {
b.partial_cmp(a)
}));
assert_eq!(
heap.into_iter_sorted().collect::<Vec<_>>(),
vec![1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
);
}

#[test]
fn test_from_vec_cmp_boxed_closure() {
// boxed closure
let vec = vec![2, 3, 89, 5, 8, 1, 13, 21, 34, 55, 1];
let cmp1: Box<dyn Fn(&i32, &i32) -> Option<core::cmp::Ordering>> =
Box::new(|a: &i32, b: &i32| a.partial_cmp(b));
let cmp2: Box<dyn Fn(&i32, &i32) -> Option<core::cmp::Ordering>> =
Box::new(|a: &i32, b: &i32| b.partial_cmp(a));

let mut heap = BinaryHeap::from((vec, cmp1));
assert_eq!(heap.pop(), Some(89));

// re-heapify using different comparator
heap = BinaryHeap::from((heap.into(), cmp2));
assert_eq!(heap.pop(), Some(1));
}

#[test]
fn test_drain() {
let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
1 change: 1 addition & 0 deletions src/liballoc/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
#![feature(associated_type_bounds)]
#![feature(binary_heap_into_iter_sorted)]
#![feature(binary_heap_drain_sorted)]
#![feature(binary_heap_from_vec_cmp)]
#![feature(vec_remove_item)]

use std::collections::hash_map::DefaultHasher;