use crate::{ElemPool, Index, IndexError, PieList};
use crate::IndexMap;
use crate::slot::Slot;
use core::{error, fmt, mem};
use alloc::{format, string::ToString, vec::Vec};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[derive(Debug, PartialEq, Eq)]
pub enum DecreaseKeyError {
InvalidHandle {
slot: u32,
generation: u32,
},
NewKeyGreaterThanCurrent,
}
impl error::Error for DecreaseKeyError {}
impl fmt::Display for DecreaseKeyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidHandle { slot, generation } => write!(
f, "Invalid handle provided to decrease_key (slot={}, generation={})",
slot, generation
),
Self::NewKeyGreaterThanCurrent => write!(f, "Key greater than current provided"),
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Node<K, V> {
key: K,
value: V,
parent: FibHandle<K, V>,
children: PieList<Node<K, V>>,
degree: usize,
marked: bool,
}
pub type FibHandle<K, V> = Index<Node<K, V>>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[must_use]
pub struct FibHeap<K, V> {
pool: ElemPool<Node<K, V>>,
roots: PieList<Node<K, V>>,
min: FibHandle<K, V>,
len: usize,
#[cfg_attr(feature = "serde", serde(skip))]
consolidate_buf: Vec<FibHandle<K, V>>,
}
impl<K, V> FibHeap<K, V> {
pub fn new() -> Self {
let mut pool = ElemPool::new();
let roots = PieList::new(&mut pool).without_leak_check();
Self { pool, roots, min: FibHandle::NONE, len: 0, consolidate_buf: Vec::new() }
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn pool_capacity(&self) -> usize {
self.pool.capacity()
}
pub fn clear(&mut self) {
self.pool.reset();
self.roots = PieList::new(&mut self.pool).without_leak_check();
self.min = FibHandle::NONE;
self.len = 0;
self.consolidate_buf.clear();
}
}
impl<K: Ord, V> FibHeap<K, V> {
pub fn push(&mut self, key: K, value: V) -> FibHandle<K, V> {
self.try_push(key, value)
.expect("Failed to allocate node in FibHeap::push")
}
pub fn try_push(&mut self, key: K, value: V) -> Result<FibHandle<K, V>, IndexError> {
let children = PieList::new(&mut self.pool).without_leak_check();
let node = Node {
key,
value,
parent: FibHandle::NONE,
children,
degree: 0,
marked: false,
};
self.roots.push_front(node, &mut self.pool)?;
let handle = self.pool.next(self.roots.sentinel);
self.update_min(handle);
self.len += 1;
Ok(handle)
}
fn update_min(&mut self, handle: FibHandle<K, V>) {
if self.min.is_none() {
self.min = handle;
} else {
let min_key = &self.pool.data(self.min).expect("valid node data").key;
let new_key = &self.pool.data(handle).expect("valid node data").key;
if new_key < min_key {
self.min = handle;
}
}
}
pub fn peek(&self) -> Option<(&K, &V)> {
self.pool.data(self.min).map(|node| (&node.key, &node.value))
}
pub fn pop(&mut self) -> Option<(K, V)> {
if self.min.is_none() {
return None;
}
let min_handle = self.min;
self.pool.index_linkout(min_handle).expect("linked element");
self.roots.len -= 1;
let min_node_data = self.pool.data_swap(min_handle, None).expect("valid node for data_swap");
self.len -= 1;
let num_children = min_node_data.children.len;
if num_children > 0 {
let first_child = self.pool.next(min_node_data.children.sentinel);
let last_child = self.pool.prev(min_node_data.children.sentinel);
let root_last = self.pool.prev(self.roots.sentinel);
self.pool.get_elem_mut(root_last).expect("valid element").set_next(Slot::new(first_child.slot));
self.pool.get_elem_mut(first_child).expect("valid element").set_prev(Slot::new(root_last.slot));
self.pool.get_elem_mut(last_child).expect("valid element").set_next(Slot::new(self.roots.sentinel.slot));
self.pool.get_elem_mut(self.roots.sentinel).expect("valid element").set_prev(Slot::new(last_child.slot));
self.roots.len += num_children;
let mut current = first_child;
for _ in 0..num_children {
self.pool.data_mut(current).expect("valid node data").parent = FibHandle::NONE;
current = self.pool.next(current);
}
}
self.pool
.index_del(min_node_data.children.sentinel)
.expect("deletable children sentinel");
self.pool.index_del(min_handle).expect("deletable element");
if self.roots.is_empty() {
self.min = FibHandle::NONE;
} else {
self.consolidate();
}
Some((min_node_data.key, min_node_data.value))
}
fn consolidate(&mut self) {
let mut a: [Option<FibHandle<K, V>>; 64] = [None; 64];
self.min = FibHandle::NONE;
self.consolidate_buf.clear();
self.consolidate_buf.reserve(self.roots.len());
let mut current = self.pool.next(self.roots.sentinel);
while current != self.roots.sentinel {
self.consolidate_buf.push(current);
current = self.pool.next(current);
}
let roots_slot = Slot::new(self.roots.sentinel.slot);
self.pool.get_elem_mut(self.roots.sentinel).expect("valid element")
.set_links(roots_slot, roots_slot);
self.roots.len = 0;
for i in 0..self.consolidate_buf.len() {
let handle = self.consolidate_buf[i];
let mut x = handle;
let mut d = self.pool.data(x).expect("valid node data").degree;
while let Some(mut y) = a[d] {
if self.pool.data(x).expect("valid node data").key > self.pool.data(y).expect("valid node data").key {
mem::swap(&mut x, &mut y);
}
self.heap_link(y, x);
a[d] = None;
d += 1;
}
a[d] = Some(x);
}
for handle in a.iter().flatten() {
self.pool.index_link_after(*handle, self.roots.sentinel).expect("valid list insertion");
self.roots.len += 1;
self.update_min(*handle);
}
}
fn heap_link(&mut self, y: FibHandle<K, V>, x: FibHandle<K, V>) {
let mut x_children = self.pool.data_mut(x).expect("valid node data").children.shallow_copy();
self.pool.index_link_after(y, x_children.sentinel).expect("valid list insertion");
x_children.len += 1;
self.pool.data_mut(x).expect("valid node data").children = x_children;
self.pool.data_mut(x).expect("valid node data").degree += 1;
self.pool.data_mut(y).expect("valid node data").parent = x;
self.pool.data_mut(y).expect("valid node data").marked = false;
}
pub fn decrease_key(&mut self, handle: FibHandle<K, V>, new_key: K
) -> Result<(), DecreaseKeyError> {
let parent = {
let node = self.pool.data(handle).ok_or(DecreaseKeyError::InvalidHandle {
slot: handle.slot,
generation: handle.vers,
})?;
if new_key > node.key {
return Err(DecreaseKeyError::NewKeyGreaterThanCurrent);
}
node.parent
};
{
let node_mut = self.pool.data_mut(handle).expect("valid node data");
node_mut.key = new_key;
}
if parent.is_some() && self.pool.data(handle).expect("valid node data").key < self.pool.data(parent).expect("valid node data").key {
self.cut(handle, parent);
self.cascading_cut(parent);
}
self.update_min(handle);
Ok(())
}
fn cut(&mut self, x: FibHandle<K, V>, y: FibHandle<K, V>) {
self.pool.index_linkout(x).expect("linked element");
let mut y_children = self.pool.data_mut(y).expect("valid node data").children.shallow_copy();
y_children.len -= 1;
self.pool.data_mut(y).expect("valid node data").children = y_children;
self.pool.data_mut(y).expect("valid node data").degree -= 1;
self.pool.index_link_after(x, self.roots.sentinel).expect("valid list insertion");
self.roots.len += 1;
self.pool.data_mut(x).expect("valid node data").parent = FibHandle::NONE;
self.pool.data_mut(x).expect("valid node data").marked = false;
}
fn cascading_cut(&mut self, mut y: FibHandle<K, V>) {
loop {
let y_parent = self.pool.data(y).expect("valid node data").parent;
if y_parent.is_none() {
break;
}
if !self.pool.data(y).expect("valid node data").marked {
self.pool.data_mut(y).expect("valid node data").marked = true;
break;
}
self.cut(y, y_parent);
y = y_parent;
}
}
#[must_use = "the remapping table must be used to update external FibHandles"]
pub fn shrink_to_fit(&mut self) -> IndexMap<FibHandle<K, V>, FibHandle<K, V>> {
let map = self.pool.shrink_to_fit();
self.roots.remap(&map);
if let Some(new_min) = map.get(&self.min) {
self.min = *new_min;
}
let used_indices: Vec<Index<Node<K, V>>> = self.pool.iter_elems()
.enumerate()
.filter_map(|(slot, elem)| {
if elem.is_used() {
Some(Index::new(slot as u32, elem.vers_raw()))
} else {
None
}
})
.collect();
for index in used_indices {
let node = self.pool.data_mut(index).expect("valid node data");
if let Some(new_parent) = map.get(&node.parent) {
node.parent = *new_parent;
}
node.children.remap(&map);
}
map
}
pub fn drain(&mut self) -> Drain<'_, K, V> {
Drain { heap: self }
}
}
impl<K: Ord, V> Default for FibHeap<K, V> {
fn default() -> Self {
Self::new()
}
}
impl<K, V> Drop for FibHeap<K, V> {
fn drop(&mut self) {
self.clear();
}
}
impl<K: Ord + fmt::Display, V: fmt::Display> fmt::Display for FibHeap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_empty() {
return writeln!(f, "FibHeap (empty)");
}
writeln!(f, "FibHeap (len: {}, min: {})",
self.len,
self.pool.data(self.min)
.map_or_else(|| "N/A".to_string(), |n| n.key.to_string()))?;
let mut current = self.pool.next(self.roots.sentinel);
if current == self.roots.sentinel {
return writeln!(f, " <no roots>");
}
loop {
let next = self.pool.next(current);
let is_last = next == self.roots.sentinel;
self.fmt_node(current, f, " ", is_last)?;
if is_last {
break;
}
current = next;
}
Ok(())
}
}
impl<K: Ord + fmt::Display, V: fmt::Display> FibHeap<K, V> {
fn fmt_node(
&self,
handle: FibHandle<K, V>,
f: &mut fmt::Formatter<'_>,
prefix: &str,
is_last: bool,
) -> fmt::Result {
let node = self.pool.data(handle).expect("valid node data");
let connector = if is_last { "└─" } else { "├─" };
let marked_str = if node.marked { " (M)" } else { "" };
writeln!(f, "{}{} Node(k: {}, v: {}){}",
prefix, connector, node.key, node.value, marked_str)?;
let child_prefix = format!("{}{}", prefix, if is_last { " " } else { "│ " });
let children_list = node.children.shallow_copy();
if !children_list.is_empty() {
let mut current_child = self.pool.next(children_list.sentinel);
while current_child != children_list.sentinel {
let next_child = self.pool.next(current_child);
let is_last_child = next_child == children_list.sentinel;
self.fmt_node(current_child, f, &child_prefix, is_last_child)?;
current_child = next_child;
}
}
Ok(())
}
}
pub struct Drain<'a, K: Ord, V> {
heap: &'a mut FibHeap<K, V>,
}
impl<'a, K: Ord, V> Iterator for Drain<'a, K, V> {
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
self.heap.pop()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.heap.len(), Some(self.heap.len()))
}
}
impl<'a, K: Ord, V> ExactSizeIterator for Drain<'a, K, V> {
fn len(&self) -> usize {
self.heap.len()
}
}
impl<'a, K: Ord, V> core::iter::FusedIterator for Drain<'a, K, V> {}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
#[test]
fn test_new_empty_len() {
let heap = FibHeap::<i32, ()>::new();
assert!(heap.is_empty());
assert_eq!(heap.len(), 0);
assert_eq!(heap.peek(), None);
}
#[test]
fn test_push_and_peek() {
let mut heap = FibHeap::new();
heap.push(10, 'a');
assert!(!heap.is_empty());
assert_eq!(heap.len(), 1);
assert_eq!(heap.peek(), Some((&10, &'a')));
heap.push(5, 'b');
assert_eq!(heap.len(), 2);
assert_eq!(heap.peek(), Some((&5, &'b')));
heap.push(20, 'c');
assert_eq!(heap.len(), 3);
assert_eq!(heap.peek(), Some((&5, &'b')));
}
#[test]
fn test_pop() {
let mut heap = FibHeap::new();
heap.push(10, "ten");
heap.push(20, "twenty");
heap.push(5, "five");
heap.push(15, "fifteen");
assert_eq!(heap.len(), 4);
assert_eq!(heap.pop(), Some((5, "five")));
assert_eq!(heap.len(), 3);
assert_eq!(heap.pop(), Some((10, "ten")));
assert_eq!(heap.len(), 2);
assert_eq!(heap.pop(), Some((15, "fifteen")));
assert_eq!(heap.len(), 1);
assert_eq!(heap.pop(), Some((20, "twenty")));
assert_eq!(heap.len(), 0);
assert!(heap.is_empty());
assert_eq!(heap.pop(), None);
}
#[test]
fn test_pop_empty() {
let mut heap = FibHeap::<i32, i32>::new();
assert_eq!(heap.pop(), None);
}
#[test]
fn test_clear() {
let mut heap = FibHeap::new();
heap.push(10, ());
heap.push(5, ());
assert!(!heap.is_empty());
assert_eq!(heap.len(), 2);
heap.clear();
assert!(heap.is_empty());
assert_eq!(heap.len(), 0);
assert_eq!(heap.peek(), None);
assert_eq!(heap.pop(), None);
}
#[test]
fn test_drop() {
let mut heap = FibHeap::new();
heap.push(10, 'a');
heap.push(5, 'b');
}
#[test]
fn test_consolidation() {
let mut heap = FibHeap::new();
for i in (0..8).rev() {
heap.push(i, ());
}
assert_eq!(heap.roots.len, 8);
assert_eq!(heap.peek().unwrap().0, &0);
assert_eq!(heap.pop(), Some((0, ())));
assert_eq!(heap.len(), 7);
assert!(heap.roots.len < 7);
assert_eq!(heap.peek().unwrap().0, &1);
heap.clear();
}
#[test]
fn test_decrease_key_simple() {
let mut heap = FibHeap::new();
heap.push(10, 'a');
let handle = heap.push(20, 'b');
assert_eq!(heap.peek(), Some((&10, &'a')));
let _ = heap.decrease_key(handle, 5);
assert_eq!(heap.peek(), Some((&5, &'b')));
assert_eq!(heap.len(), 2);
}
#[test]
fn test_decrease_key_with_cut() {
let mut heap = FibHeap::new();
heap.push(10, 'a');
heap.push(20, 'b');
heap.push(5, 'c');
assert_eq!(heap.pop(), Some((5, 'c')));
assert_eq!(heap.roots.len, 1); assert_eq!(heap.peek(), Some((&10, &'a')));
let handle_20 = heap
.pool
.next(heap.pool.data(heap.min).unwrap().children.sentinel);
assert_eq!(heap.pool.data(handle_20).unwrap().key, 20);
let _ = heap.decrease_key(handle_20, 8);
assert_eq!(heap.peek(), Some((&8, &'b')));
assert_eq!(heap.len(), 2);
assert_eq!(heap.roots.len, 2); heap.clear();
}
#[test]
fn test_decrease_key_cascading_cut() {
let mut heap = FibHeap::new();
let h30 = heap.push(30, "P"); let h40 = heap.push(40, "C"); heap.push(29, "min");
heap.pop(); println!("#1: {heap}");
let h20 = heap.push(20, "P-Sibling");
heap.push(19, "min");
heap.pop(); println!("#2: {heap}");
let h10 = heap.push(10, "GP"); heap.push(9, "min");
heap.pop(); println!("#3: {heap}");
assert_eq!(
heap.pool.data(h30).unwrap().parent,
h10,
"P(h30) should be child of GP(h10)"
);
assert_eq!(
heap.pool.data(h40).unwrap().parent,
h30,
"C(h40) should be child of P(h30)"
);
let _ = heap.decrease_key(h40, 5); println!("#4: {heap}");
assert!(
heap.pool.data(h40).unwrap().parent.is_none(),
"h40 should be a root after cut"
);
assert!(
heap.pool.data(h30).unwrap().marked,
"h30 should be marked after losing one child"
);
assert!(
!heap.pool.data(h10).unwrap().marked,
"h10 should not be marked"
);
let _ = heap.decrease_key(h30, 6); println!("#5: {heap}");
assert!(
heap.pool.data(h30).unwrap().parent.is_none(),
"h30 should be a root after cascading cut"
);
assert!(
!heap.pool.data(h30).unwrap().marked,
"h30's mark should be reset"
);
assert!(
heap.pool.data(h10).unwrap().parent.is_none(),
"h10 should still be a root"
);
assert_eq!(
heap.pool.data(h20).unwrap().parent,
h10,
"h20 should still be a child of h10"
);
heap.clear();
}
#[test]
fn test_decrease_key_panic() {
let mut heap = FibHeap::new();
let handle = heap.push(10, ());
let err = heap.decrease_key(handle, 20);
assert_eq!(err, Err(DecreaseKeyError::NewKeyGreaterThanCurrent));
}
#[test]
fn test_drain() {
let mut heap = FibHeap::new();
heap.push(20, 'd');
heap.push(5, 'a');
heap.push(15, 'c');
heap.push(10, 'b');
assert_eq!(heap.len(), 4);
let mut drain = heap.drain();
assert_eq!(drain.next(), Some((5, 'a')));
assert_eq!(drain.next(), Some((10, 'b')));
let rest: Vec<_> = drain.collect();
assert_eq!(rest, vec![(15, 'c'), (20, 'd')]);
assert!(heap.is_empty());
assert_eq!(heap.len(), 0);
assert_eq!(heap.pop(), None);
heap.clear();
}
fn validate_heap_integrity<K: Ord + fmt::Debug, V>(heap: &FibHeap<K, V>) {
let mut visited = HashSet::new();
let mut nodes_to_visit = Vec::new();
if !heap.roots.is_empty() {
let mut current = heap.pool.next(heap.roots.sentinel);
while current != heap.roots.sentinel {
nodes_to_visit.push((current, FibHandle::NONE)); current = heap.pool.next(current);
}
}
while let Some((handle, expected_parent)) = nodes_to_visit.pop() {
assert!(visited.insert(handle), "Cycle detected or node visited twice!");
let node = heap.pool.data(handle).expect("Handle points to free/invalid memory");
assert_eq!(node.parent, expected_parent, "Node {:?} has wrong parent pointer", handle);
if !node.children.is_empty() {
let mut child = heap.pool.next(node.children.sentinel);
let mut count = 0;
while child != node.children.sentinel {
nodes_to_visit.push((child, handle)); child = heap.pool.next(child);
count += 1;
}
assert_eq!(node.children.len(), count, "Child list len mismatch");
}
}
assert_eq!(visited.len(), heap.len(), "Pool contains orphaned nodes not reachable from roots!");
}
#[test]
fn test_shrink_handle_usability() {
let mut heap = FibHeap::new();
let _h1 = heap.push(10, "A");
let _h2 = heap.push(20, "B");
let h3 = heap.push(30, "C");
let h4 = heap.push(40, "D");
assert_eq!(heap.pop(), Some((10, "A")));
assert_eq!(heap.pop(), Some((20, "B")));
println!("Before shrink: {}", heap);
validate_heap_integrity(&heap);
let map = heap.shrink_to_fit();
println!("After shrink: {}", heap);
validate_heap_integrity(&heap);
let _new_h3 = map.get(&h3).copied().unwrap_or(h3);
let new_h4 = map.get(&h4).copied().unwrap_or(h4);
heap.decrease_key(new_h4, 5).expect("Decrease key failed on remapped handle");
assert_eq!(heap.peek().unwrap().0, &5);
assert_eq!(heap.pop(), Some((5, "D")));
assert_eq!(heap.pop(), Some((30, "C")));
}
#[test]
fn test_shrink_structural_stress() {
let mut heap = FibHeap::new();
let mut handles = Vec::new();
for i in 0..100 {
handles.push(heap.push(i, i));
}
for _ in 0..40 {
heap.pop();
}
handles.drain(0..40);
let initial_len = heap.len();
let initial_cap = heap.pool_capacity();
validate_heap_integrity(&heap);
let map = heap.shrink_to_fit();
assert_eq!(heap.len(), initial_len);
assert!(heap.pool_capacity() <= initial_cap);
validate_heap_integrity(&heap);
for old_handle in handles {
let new_handle = map.get(&old_handle).copied().unwrap_or(old_handle);
let node = heap.pool.data(new_handle).expect("Remapped handle points to nothing!");
assert!(node.key >= 40 && node.key < 100);
}
while heap.pop().is_some() {}
}
#[test]
fn test_shrink_empty_and_single() {
let mut heap = FibHeap::<i32, i32>::new();
let map = heap.shrink_to_fit();
assert!(map.is_empty());
validate_heap_integrity(&heap);
let _h = heap.push(1, 1);
let h2 = heap.push(2, 2);
heap.pop();
let map = heap.shrink_to_fit();
assert!(map.contains_key(&h2));
let new_h2 = map[&h2];
assert_eq!(heap.peek(), Some((&2, &2)));
assert_eq!(heap.min, new_h2);
}
#[test]
fn test_drain_partial_consumption() {
let mut heap = FibHeap::new();
heap.push(10, "ten");
heap.push(5, "five");
heap.push(20, "twenty");
heap.push(1, "one");
{
let mut drain = heap.drain();
assert_eq!(drain.next(), Some((1, "one")));
assert_eq!(drain.next(), Some((5, "five")));
}
assert_eq!(heap.len(), 2);
assert_eq!(heap.pop(), Some((10, "ten")));
assert_eq!(heap.pop(), Some((20, "twenty")));
assert!(heap.is_empty());
}
#[test]
fn test_consolidation_large() {
let mut heap = FibHeap::new();
let n = 500;
for i in (0..n).rev() {
heap.push(i, i);
}
assert_eq!(heap.len(), n);
let mut prev = None;
for _ in 0..n {
let (key, _) = heap.pop().expect("unexpected empty heap");
if let Some(p) = prev {
assert!(key >= p, "heap order violated: {} after {}", key, p);
}
prev = Some(key);
}
assert!(heap.is_empty());
}
#[test]
fn test_deep_cascading_cuts() {
let mut heap = FibHeap::new();
let mut handles = Vec::new();
for i in 0..16 {
handles.push(heap.push(i * 10, i));
}
assert_eq!(heap.pop().unwrap().0, 0);
validate_heap_integrity(&heap);
let remaining: Vec<_> = (1..16)
.filter_map(|i| {
let h = handles[i];
if heap.pool.data(h).is_some() { Some((i, h)) } else { None }
})
.collect();
for (count, &(i, h)) in remaining.iter().rev().take(6).enumerate() {
let new_key = -(count as i32) - 1; let current_key = heap.pool.data(h).unwrap().key;
if new_key < current_key {
heap.decrease_key(h, new_key).unwrap();
validate_heap_integrity(&heap);
assert!(
heap.pool.data(h).unwrap().parent.is_none(),
"node {} (val={}) should have been cut to root", i, new_key,
);
}
}
let mut prev = i32::MIN;
while let Some((key, _)) = heap.pop() {
assert!(key >= prev, "heap order violated after cascading cuts");
prev = key;
}
}
#[test]
fn test_push_pop_interleaved_large() {
let mut heap = FibHeap::new();
let mut expected = std::collections::BinaryHeap::new();
for i in 0..200 {
heap.push(i, ());
expected.push(std::cmp::Reverse(i));
}
for i in 200..300 {
let got = heap.pop().unwrap().0;
let want = expected.pop().unwrap().0;
assert_eq!(got, want);
heap.push(i, ());
expected.push(std::cmp::Reverse(i));
}
while let Some(std::cmp::Reverse(want)) = expected.pop() {
let got = heap.pop().unwrap().0;
assert_eq!(got, want);
}
assert!(heap.is_empty());
}
#[test]
fn test_decrease_key_to_new_min() {
let mut heap = FibHeap::new();
heap.push(10, 'a');
let h = heap.push(50, 'b');
heap.push(30, 'c');
let _ = heap.pop(); assert_eq!(heap.peek().unwrap().0, &30);
heap.decrease_key(h, 5).unwrap();
assert_eq!(heap.peek().unwrap().0, &5);
assert_eq!(heap.peek().unwrap().1, &'b');
let (k1, v1) = heap.pop().unwrap();
assert_eq!((k1, v1), (5, 'b'));
let (k2, v2) = heap.pop().unwrap();
assert_eq!((k2, v2), (30, 'c'));
assert!(heap.is_empty());
}
#[test]
fn test_decrease_key_many() {
let mut heap = FibHeap::new();
let mut handles = Vec::new();
for i in 0..200i32 {
handles.push(heap.push(i * 2, i));
}
let (k, _) = heap.pop().unwrap();
assert_eq!(k, 0);
for (j, h) in handles.iter().enumerate().skip(1) {
if j % 2 == 0 {
heap.decrease_key(*h, -((j as i32) * 3)).unwrap();
}
}
let mut prev = i32::MIN;
while let Some((k, _)) = heap.pop() {
assert!(k >= prev, "pop order violated: {} after {}", k, prev);
prev = k;
}
}
#[test]
fn test_try_push() {
let mut heap = FibHeap::new();
let handle = heap.try_push(10, "ten").unwrap();
assert_eq!(heap.len(), 1);
assert_eq!(heap.peek(), Some((&10, &"ten")));
heap.try_push(5, "five").unwrap();
heap.try_push(20, "twenty").unwrap();
assert_eq!(heap.peek(), Some((&5, &"five")));
assert_eq!(heap.len(), 3);
heap.decrease_key(handle, 1).unwrap();
assert_eq!(heap.peek(), Some((&1, &"ten")));
heap.clear();
}
#[test]
fn test_decrease_key_invalid_handle_diagnostic() {
let mut heap = FibHeap::new();
heap.push(10, ());
let (_, _) = heap.pop().unwrap();
let stale = FibHandle::<i32, ()>::new(42, 99);
let err = heap.decrease_key(stale, 0);
match err {
Err(DecreaseKeyError::InvalidHandle { slot, generation }) => {
assert_eq!(slot, 42);
assert_eq!(generation, 99);
}
other => panic!("expected InvalidHandle, got {:?}", other),
}
}
#[test]
fn test_default() {
let heap = FibHeap::<i32, &str>::default();
assert!(heap.is_empty());
assert_eq!(heap.len(), 0);
assert_eq!(heap.peek(), None);
}
#[test]
fn test_default_then_use() {
let mut heap = FibHeap::<i32, &str>::default();
heap.push(5, "five");
heap.push(3, "three");
heap.push(7, "seven");
assert_eq!(heap.peek(), Some((&3, &"three")));
assert_eq!(heap.pop(), Some((3, "three")));
assert_eq!(heap.pop(), Some((5, "five")));
assert_eq!(heap.pop(), Some((7, "seven")));
assert!(heap.is_empty());
}
#[test]
fn test_clear_then_reuse() {
let mut heap = FibHeap::new();
for i in 0..50 {
heap.push(i, ());
}
heap.clear();
assert!(heap.is_empty());
assert_eq!(heap.len(), 0);
assert_eq!(heap.peek(), None);
for i in (0..30).rev() {
heap.push(i, ());
}
assert_eq!(heap.len(), 30);
assert_eq!(heap.peek(), Some((&0, &())));
let mut prev = None;
while let Some((k, _)) = heap.pop() {
if let Some(p) = prev {
assert!(k >= p);
}
prev = Some(k);
}
assert!(heap.is_empty());
}
#[test]
fn test_drain_size_hint() {
let mut heap = FibHeap::new();
for i in 0..5 {
heap.push(i, ());
}
let mut drain = heap.drain();
assert_eq!(drain.size_hint(), (5, Some(5)));
assert_eq!(drain.len(), 5);
drain.next();
assert_eq!(drain.size_hint(), (4, Some(4)));
assert_eq!(drain.len(), 4);
for _ in drain {}
assert!(heap.is_empty());
}
#[test]
fn test_drain_is_fused() {
let mut heap = FibHeap::new();
heap.push(1, ());
let mut drain = heap.drain();
assert!(drain.next().is_some());
assert!(drain.next().is_none());
assert!(drain.next().is_none()); }
}