use core::cmp::Ordering;
use core::fmt;
use crate::error::LhaError;
use crate::bitstream::BitRead;
#[cfg(not(feature = "std"))]
use alloc::{vec::Vec, string::String};
pub mod entry;
use entry::*;
#[derive(Debug, Clone)]
pub struct HuffTree {
tree: Vec<TreeEntry>
}
impl HuffTree {
pub fn with_capacity(capacity: usize) -> Self {
let tree = Vec::with_capacity(capacity);
HuffTree { tree }
}
pub fn set_single(&mut self, value: u16) {
self.tree.clear();
self.tree.push(TreeEntry::leaf(value));
}
pub fn build_tree(&mut self, value_lengths: &[u8]) -> Result<(), &'static str> {
if value_lengths.len() > TreeEntry::MAX_INDEX / 2 {
return Err("too many code lengths");
}
let tree = &mut self.tree;
tree.clear();
let mut max_allocated: usize = 1; for current_len in 1u8.. {
let max_limit = max_allocated;
for _ in tree.len()..max_limit {
match TreeEntry::branch(max_allocated) {
Ok(branch) => tree.push(branch),
Err(e) => {
tree.clear();
return Err(e);
}
}
max_allocated += 2;
}
let more_leaves = value_lengths.iter().copied().zip(0..)
.fold(false, |mut more, (len, value)| {
match len.cmp(¤t_len) {
Ordering::Equal => {
tree.push(TreeEntry::leaf(value));
}
Ordering::Greater => {
more = true;
}
Ordering::Less => {}
}
more
});
if tree.len() > max_allocated {
return Err("too many leaves");
}
if !more_leaves {
break;
}
}
if tree.len() != max_allocated {
return Err("missing some leaves")
}
Ok(())
}
pub fn read_entry<R: BitRead>(&self, mut path: R) -> Result<u16, LhaError<R::Error>> {
let tree = &self.tree;
let mut node = &tree[0]; loop {
match node.as_type() {
NodeType::Leaf(code) => return Ok(code),
NodeType::Branch(index) => {
let index = index as usize + path.read_bits::<usize>(1)?;
debug_assert!(index < tree.len());
node = unsafe {
tree.get_unchecked(index)
};
}
}
}
}
}
impl fmt::Display for HuffTree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn fmt_step(tree: &Vec<TreeEntry>, index: usize, f: &mut fmt::Formatter<'_>, prefix: &mut String) -> fmt::Result {
match tree[index].as_type() {
NodeType::Leaf(code) => writeln!(f, "{} -> {}", prefix, code)?,
NodeType::Branch(index) => {
prefix.push('0');
fmt_step(tree, index as usize, f, prefix)?;
prefix.pop();
prefix.push('1');
fmt_step(tree, index as usize + 1, f, prefix)?;
prefix.pop();
}
}
Ok(())
}
if !self.tree.is_empty() {
let mut prefix = String::new();
fmt_step(&self.tree, 0, f, &mut prefix)?;
}
Ok(())
}
}
#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use crate::bitstream::BitStream;
use std::collections::{HashSet, HashMap};
use super::*;
fn validate_tree(tree: &HuffTree, num_leaves: usize) {
let mut leaves: HashMap<u16, usize> = HashMap::with_capacity(num_leaves);
let mut children: HashSet<u16> = HashSet::with_capacity(tree.tree.len());
for (index, node) in tree.tree.iter().enumerate() {
match node.as_type() {
NodeType::Leaf(value) => {
assert!(leaves.insert(value, index).is_none());
}
NodeType::Branch(child_index) => {
assert!(child_index != 0);
assert!((child_index as usize) < tree.tree.len() - 1);
assert!(child_index & 1 == 1);
assert!(children.insert(child_index));
}
}
}
assert_eq!(leaves.len(), num_leaves);
fn into_branch(nodes: &[TreeEntry], index: usize, leaves: &mut HashSet<u16>) {
match nodes[index].as_type() {
NodeType::Leaf(code) => {
assert!(leaves.insert(code));
}
NodeType::Branch(index) => {
into_branch(nodes, index as usize, leaves);
into_branch(nodes, index as usize + 1, leaves);
}
}
}
let mut leaves: HashSet<u16> = HashSet::with_capacity(num_leaves);
into_branch(&tree.tree, 0, &mut leaves);
assert_eq!(leaves.len(), num_leaves);
}
#[test]
fn hufftree_works() {
let mut tree = HuffTree::with_capacity(0);
println!("{}", tree);
tree.set_single(42);
validate_tree(&tree, 1);
let path = BitStream::new([].as_ref());
assert_eq!(tree.read_entry(path).unwrap(), 42);
println!("{}", tree);
tree.build_tree(&[0, 1, 0, 1]).unwrap();
validate_tree(&tree, 2);
println!("{}", tree);
tree.build_tree(&[0, 0, 0, 1, 0, 3, 3, 0, 4, 4, 5, 0, 0, 5, 5, 5]).unwrap();
println!("{}", tree);
validate_tree(&tree, 9);
assert_eq!(tree.tree.len(), 9 + 8);
let bits: &[u8] = &[0b01001011, 0b10011011, 0b11001110, 0b11111011, 0b11100000];
let mut path = BitStream::new(bits);
let mut res = Vec::new();
for _ in 0..9 {
res.push(tree.read_entry(&mut path).unwrap());
}
assert_eq!(res, [3, 5, 6, 8, 9, 10, 13, 14, 15]);
assert!(tree.build_tree(&[0, 1, 0, 1, 1]).is_err());
assert!(tree.build_tree(&[0, 1, 0, 1, 10]).is_err());
}
}