use std::cmp;
use crate::ConstDefault;
pub trait Ordering<T> {
fn should_sift_up(&self, elt: &T, parent: &T) -> bool;
fn should_sift_down(&self, elt: &T, child: &T) -> bool;
fn select_upper(&self, a: &T, b: &T) -> bool {
self.should_sift_up(b, a)
}
}
#[derive(Default)]
pub struct MaxHeap<C = Natural>(C);
impl<T, C: Cmp<T>> Ordering<T> for MaxHeap<C> {
fn should_sift_up(&self, elt: &T, parent: &T) -> bool {
self.0.cmp(elt, parent).is_gt()
}
fn should_sift_down(&self, elt: &T, child: &T) -> bool {
self.0.cmp(elt, child).is_lt()
}
}
impl<C: ConstDefault> ConstDefault for MaxHeap<C> {
const DEFAULT: Self = MaxHeap(C::DEFAULT);
}
#[derive(Default)]
pub struct MinHeap<C = Natural>(C);
impl<T, C: Cmp<T>> Ordering<T> for MinHeap<C> {
fn should_sift_up(&self, elt: &T, parent: &T) -> bool {
self.0.cmp(elt, parent).is_lt()
}
fn should_sift_down(&self, elt: &T, child: &T) -> bool {
self.0.cmp(elt, child).is_gt()
}
}
impl<C: ConstDefault> ConstDefault for MinHeap<C> {
const DEFAULT: Self = MinHeap(C::DEFAULT);
}
impl MaxHeap {
pub fn natural() -> MaxHeap {
MaxHeap(Natural)
}
pub fn by<T, F: Fn(&T, &T) -> cmp::Ordering>(cmp: F) -> MaxHeap<ByCmp<F>> {
MaxHeap(ByCmp(cmp))
}
pub fn by_key<T, K: Ord, F: Fn(&T) -> K>(key: F) -> MaxHeap<ByKey<F>> {
MaxHeap(ByKey(key))
}
}
impl MinHeap {
pub fn natural() -> MinHeap {
MinHeap(Natural)
}
pub fn by<T, F: Fn(&T, &T) -> cmp::Ordering>(cmp: F) -> MinHeap<ByCmp<F>> {
MinHeap(ByCmp(cmp))
}
pub fn by_key<T, K: Ord, F: Fn(&T) -> K>(key: F) -> MinHeap<ByKey<F>> {
MinHeap(ByKey(key))
}
}
pub trait Cmp<T> {
fn cmp(&self, a: &T, b: &T) -> cmp::Ordering;
}
#[derive(Default, Clone, Copy)]
pub struct Natural;
impl<T: Ord> Cmp<T> for Natural {
fn cmp(&self, a: &T, b: &T) -> cmp::Ordering {
a.cmp(b)
}
}
impl ConstDefault for Natural {
const DEFAULT: Self = Natural;
}
pub struct ByCmp<F>(F);
impl<T, F: Fn(&T, &T) -> cmp::Ordering> Cmp<T> for ByCmp<F> {
fn cmp(&self, a: &T, b: &T) -> cmp::Ordering {
self.0(a, b)
}
}
pub struct ByKey<F>(F);
impl<T, F: Fn(&T) -> K, K: Ord> Cmp<T> for ByKey<F> {
fn cmp(&self, a: &T, b: &T) -> cmp::Ordering {
self.0(a).cmp(&self.0(b))
}
}