use core::{
marker::PhantomPinned,
mem,
ops::{Deref, DerefMut, Drop},
ptr::NonNull,
};
fn safe_lesser<T: Ord>(a: &T, b: &T) -> bool {
struct DropBomb;
impl Drop for DropBomb {
fn drop(&mut self) {
panic!("Panicked while comparing");
}
}
let bomb = DropBomb;
let ordering = a < b;
mem::forget(bomb);
ordering
}
#[derive(Debug)]
pub struct HeapNode<T> {
parent: Option<NonNull<HeapNode<T>>>,
prev: Option<NonNull<HeapNode<T>>>,
next: Option<NonNull<HeapNode<T>>>,
first_child: Option<NonNull<HeapNode<T>>>,
data: T,
_pin: PhantomPinned,
}
impl<T> HeapNode<T> {
pub fn new(data: T) -> HeapNode<T> {
HeapNode::<T> {
parent: None,
prev: None,
next: None,
first_child: None,
data,
_pin: PhantomPinned,
}
}
fn is_root(&self) -> bool {
if self.parent.is_none() {
debug_assert_eq!(self.prev, None);
debug_assert_eq!(self.next, None);
true
} else {
false
}
}
}
impl<T> Deref for HeapNode<T> {
type Target = T;
fn deref(&self) -> &T {
&self.data
}
}
impl<T> DerefMut for HeapNode<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.data
}
}
unsafe fn add_child<T: Ord>(
mut parent: NonNull<HeapNode<T>>,
mut child: NonNull<HeapNode<T>>,
) {
debug_assert!(!safe_lesser(&child.as_ref().data, &parent.as_ref().data));
if let Some(mut old_first_child) = parent.as_mut().first_child.take() {
child.as_mut().next = Some(old_first_child);
debug_assert_eq!(old_first_child.as_ref().prev, None);
old_first_child.as_mut().prev = Some(child);
}
parent.as_mut().first_child = Some(child);
child.as_mut().parent = Some(parent);
}
unsafe fn meld<T: Ord>(
left: NonNull<HeapNode<T>>,
right: NonNull<HeapNode<T>>,
) -> NonNull<HeapNode<T>> {
debug_assert!(left.as_ref().is_root());
debug_assert!(right.as_ref().is_root());
if safe_lesser(&left.as_ref().data, &right.as_ref().data) {
add_child(left, right);
left
} else {
add_child(right, left);
right
}
}
unsafe fn maybe_meld<T: Ord>(
left: Option<NonNull<HeapNode<T>>>,
right: NonNull<HeapNode<T>>,
) -> NonNull<HeapNode<T>> {
if let Some(left) = left {
meld(left, right)
} else {
right
}
}
unsafe fn last_child<T>(
first_child: NonNull<HeapNode<T>>,
) -> NonNull<HeapNode<T>> {
let mut cur = first_child;
while let Some(next) = cur.as_ref().next {
cur = next;
}
cur
}
unsafe fn unlink_prev<T>(
mut node: NonNull<HeapNode<T>>,
) -> Option<NonNull<HeapNode<T>>> {
debug_assert_eq!(node.as_ref().next, None);
let mut prev = node.as_mut().prev.take()?;
debug_assert_eq!(prev.as_ref().next, Some(node));
prev.as_mut().next = None;
Some(prev)
}
unsafe fn merge_children<T: Ord>(
first_child: NonNull<HeapNode<T>>,
) -> NonNull<HeapNode<T>> {
let common_parent = first_child.as_ref().parent;
debug_assert!(common_parent.is_some());
let mut node = last_child(first_child);
let mut current = None;
loop {
let node_parent = node.as_mut().parent.take();
debug_assert_eq!(node_parent, common_parent);
let mut prev = if let Some(prev) = unlink_prev(node) {
prev
} else {
return maybe_meld(current, node);
};
let prev_parent = prev.as_mut().parent.take();
debug_assert_eq!(prev_parent, common_parent);
let prev_prev = unlink_prev(prev);
let cur = maybe_meld(current, meld(prev, node));
if let Some(prev_prev) = prev_prev {
node = prev_prev;
current = Some(cur);
continue;
} else {
return cur;
}
}
}
#[derive(Debug)]
pub struct PairingHeap<T> {
root: Option<NonNull<HeapNode<T>>>,
}
impl<T: Ord> PairingHeap<T> {
pub fn new() -> Self {
PairingHeap::<T> { root: None }
}
pub unsafe fn insert(&mut self, node: &mut HeapNode<T>) {
debug_assert!(node.is_root());
debug_assert_eq!(node.first_child, None);
if let Some(root) = self.root {
self.root = Some(meld(root, node.into()));
} else {
self.root = Some(node.into());
}
}
pub fn peek_min(&self) -> Option<NonNull<HeapNode<T>>> {
self.root
}
pub unsafe fn remove(&mut self, node: &mut HeapNode<T>) {
let parent = node.parent.take();
if let Some(mut parent) = parent {
if let Some(mut prev) = node.prev {
prev.as_mut().next = node.next;
} else {
parent.as_mut().first_child = node.next;
}
if let Some(mut next) = node.next {
next.as_mut().prev = node.prev;
}
node.next = None;
node.prev = None;
} else {
debug_assert_eq!(node.next, None);
debug_assert_eq!(node.prev, None);
debug_assert_eq!(self.root, Some(node.into()));
self.root = None;
}
if let Some(first_child) = node.first_child.take() {
let children = merge_children(first_child);
if let Some(parent) = parent {
add_child(parent, children);
} else {
self.root = Some(children);
}
}
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::{HeapNode, PairingHeap};
use core::ptr::NonNull;
unsafe fn validate_heap_node<T: Ord>(
node: &HeapNode<T>,
parent: Option<&HeapNode<T>>,
) {
assert_eq!(node.parent, parent.map(NonNull::from));
if let Some(p) = parent {
assert!(p.data <= node.data);
}
if let Some(prev) = node.prev {
assert_eq!(prev.as_ref().next, Some(node.into()));
}
if let Some(next) = node.next {
assert_eq!(next.as_ref().prev, Some(node.into()));
}
let mut child = node.first_child;
while let Some(c) = child {
validate_heap_node(c.as_ref(), Some(node));
child = c.as_ref().next;
}
}
fn validate_heap<T: Ord>(heap: &PairingHeap<T>) {
if let Some(root) = heap.root {
unsafe {
validate_heap_node(root.as_ref(), None);
}
}
}
#[test]
fn insert_and_remove() {
#[derive(Copy, Clone, Debug)]
enum Action {
Insert(u8),
Remove(u8),
}
fn generate_schedules(
current: &mut Vec<Action>,
available: &mut Vec<Action>,
f: fn(&[Action]),
) {
for i in 0..available.len() {
let action = available.swap_remove(i);
current.push(action);
f(current);
if let Action::Insert(j) = action {
available.push(Action::Remove(j));
}
generate_schedules(current, available, f);
if let Action::Insert(_) = action {
available.pop();
}
current.pop();
available.push(action);
let len = available.len();
available.swap(i, len - 1);
}
}
let max = if cfg!(miri) {
3
} else {
5
};
generate_schedules(
&mut vec![],
&mut (0..max).map(Action::Insert).collect(),
|schedule| unsafe {
let mut nodes = [
HeapNode::new(0u8),
HeapNode::new(1),
HeapNode::new(2),
HeapNode::new(3),
HeapNode::new(4),
];
let mut heap = PairingHeap::new();
for action in schedule {
match *action {
Action::Insert(n) => {
heap.insert(&mut nodes[n as usize]);
validate_heap(&heap);
}
Action::Remove(n) => {
heap.remove(&mut nodes[n as usize]);
assert!(nodes[n as usize].is_root());
assert_eq!(nodes[n as usize].first_child, None);
validate_heap(&heap);
}
}
}
},
);
}
#[test]
fn equal_values() {
unsafe {
let mut nodes = [
HeapNode::new(0u8),
HeapNode::new(0),
HeapNode::new(0),
HeapNode::new(0),
HeapNode::new(0),
];
let mut heap = PairingHeap::new();
for node in &mut nodes {
heap.insert(node);
validate_heap(&heap);
}
for _ in 0..5 {
heap.remove(heap.peek_min().unwrap().as_mut());
validate_heap(&heap);
}
assert_eq!(heap.peek_min(), None);
}
}
}