use core::marker::Destruct;
mod helpers;
#[cfg(test)]
mod tests;
mod veclike;
pub use self::veclike::*;
#[const_trait]
pub trait BinaryHeapCtx<Element> {
fn lt(&mut self, x: &Element, y: &Element) -> bool;
fn on_move(&mut self, e: &mut Element, new_index: usize) {
let _ = (e, new_index);
}
}
impl<T: ~const Ord + ~const PartialOrd> const BinaryHeapCtx<T> for () {
fn lt(&mut self, x: &T, y: &T) -> bool {
*x < *y
}
}
#[const_trait]
pub trait BinaryHeap: VecLike {
fn heap_pop<Ctx>(&mut self, ctx: Ctx) -> Option<Self::Element>
where
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct;
fn heap_remove<Ctx>(&mut self, i: usize, ctx: Ctx) -> Option<Self::Element>
where
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct;
fn heap_push<Ctx>(&mut self, item: Self::Element, ctx: Ctx) -> usize
where
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct;
}
impl<T> const BinaryHeap for T
where
T: ~const VecLike,
T::Element: ~const Destruct,
{
fn heap_pop<Ctx>(&mut self, ctx: Ctx) -> Option<Self::Element>
where
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct,
{
self.heap_remove(0, ctx)
}
fn heap_remove<Ctx>(&mut self, i: usize, mut ctx: Ctx) -> Option<Self::Element>
where
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct,
{
if i >= self.len() {
return None;
}
if let Some(mut item) = self.pop() {
let slice = &mut **self;
if i < slice.len() {
core::mem::swap(&mut slice[i], &mut item);
ctx.on_move(&mut slice[i], i);
let should_sift_up = i > 0 && ctx.lt(&slice[i], &slice[(i - 1) / 2]);
unsafe {
if should_sift_up {
sift_up(slice, 0, i, ctx);
} else {
sift_down(slice, i, ctx);
}
}
}
Some(item)
} else {
debug_assert!(false);
None
}
}
fn heap_push<Ctx>(&mut self, item: Self::Element, ctx: Ctx) -> usize
where
Ctx: ~const BinaryHeapCtx<Self::Element> + ~const Destruct,
{
let i = self.len();
self.push(item);
let slice = &mut **self;
assert!(i < slice.len());
unsafe { sift_up(slice, 0, i, ctx) }
}
}
const unsafe fn sift_up<Element, Ctx>(
this: &mut [Element],
start: usize,
pos: usize,
mut ctx: Ctx,
) -> usize
where
Ctx: ~const BinaryHeapCtx<Element> + ~const Destruct,
Element: ~const Destruct,
{
unsafe {
let mut hole = helpers::Hole::new(this, pos);
while hole.pos() > start {
let parent = (hole.pos() - 1) / 2;
if !ctx.lt(hole.element(), hole.get(parent)) {
break;
}
let prev_pos = hole.pos();
hole.move_to(parent);
ctx.on_move(hole.get_mut(prev_pos), prev_pos);
}
let pos = hole.pos();
ctx.on_move(hole.element_mut(), pos);
pos
}
}
const unsafe fn sift_down<Element, Ctx>(this: &mut [Element], pos: usize, mut ctx: Ctx)
where
Ctx: ~const BinaryHeapCtx<Element> + ~const Destruct,
Element: ~const Destruct,
{
let end = this.len();
unsafe {
let mut hole = helpers::Hole::new(this, pos);
let mut child = 2 * pos + 1;
while child < end {
let right = child + 1;
if right < end && !ctx.lt(hole.get(child), hole.get(right)) {
child = right;
}
if !ctx.lt(hole.get(child), hole.element()) {
break;
}
let prev_pos = hole.pos();
hole.move_to(child);
ctx.on_move(hole.get_mut(prev_pos), prev_pos);
child = 2 * hole.pos() + 1;
}
let pos = hole.pos();
ctx.on_move(hole.element_mut(), pos);
}
}