use rustc_hash::FxHashMap as HashMap;
use std::{cmp::Ordering, collections::VecDeque, fmt::Debug, hash::Hash};
use crate::code::{Bit, HfmnCode};
pub struct Node<T> {
#[allow(clippy::type_complexity)]
children: Option<(Box<Node<T>>, Box<Node<T>>)>,
probability: f64,
symbol: Option<T>,
}
impl<T: Hash + Eq> Node<T> {
pub fn new(children: Option<(Self, Self)>, probability: f64, symbol: Option<T>) -> Self {
Self {
children: children.map(|(l, r)| (Box::new(l), Box::new(r))),
probability,
symbol,
}
}
pub const fn probability(&self) -> f64 {
self.probability
}
pub fn traverse(self, symbols: &mut HashMap<T, HfmnCode>, preceeding_bits: HfmnCode) {
match self.children {
Some((l, r)) => {
let mut left_preceeding_bits = preceeding_bits;
left_preceeding_bits.push(Bit::Zero);
l.traverse(symbols, left_preceeding_bits);
let mut right_preceeding_bits = preceeding_bits;
right_preceeding_bits.push(Bit::One);
r.traverse(symbols, right_preceeding_bits);
}
None => {
if symbols
.insert(
self.symbol
.expect("No symbol found, presumably a parent node?"),
preceeding_bits,
)
.is_some()
{
panic!("Symbol was already in use.");
};
}
}
}
}
impl<T: Debug> Debug for Node<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Node ({},{:?})", self.probability, self.symbol)
}
}
impl<T> PartialEq for Node<T> {
fn eq(&self, other: &Self) -> bool {
self.probability == other.probability
}
}
impl<T> PartialOrd for Node<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
other.probability.partial_cmp(&self.probability)
}
}
pub fn get_smallest_node<T>(
leaf_nodes: &mut VecDeque<Node<T>>,
internal_nodes: &mut VecDeque<Node<T>>,
) -> Node<T> {
match leaf_nodes.front().partial_cmp(&internal_nodes.front()) {
Some(Ordering::Less) => {
internal_nodes
.pop_front()
.expect("Internal nodes queue was empty")
}
Some(Ordering::Greater) => {
leaf_nodes.pop_front().expect("Leaf nodes queue was empty")
}
Some(Ordering::Equal) => {
if leaf_nodes.front().is_some() && internal_nodes.front().is_some() {
leaf_nodes.pop_front().expect("Leaf nodes queue was empty")
} else {
panic!("Something went wrong!")
}
}
None => {
panic!("Probabilities were NaN.")
}
}
}