#![forbid(unsafe_code)]
#![warn(missing_docs)]
mod compress;
mod decompress;
mod huffman;
mod tables;
pub use compress::{compress_to_vec, Compressor, StoredOnlyCompressor};
pub use decompress::{
decompress_to_vec, decompress_to_vec_bounded, BoundedDecompressionError, DecompressionError,
Decompressor,
};
#[doc(hidden)]
pub fn compute_code_lengths(
freqs: &[u64],
min_limit: &[u8],
max_limit: &[u8],
calculated_nbits: &mut [u8],
) {
debug_assert_eq!(freqs.len(), min_limit.len());
debug_assert_eq!(freqs.len(), max_limit.len());
debug_assert_eq!(freqs.len(), calculated_nbits.len());
let len = freqs.len();
for i in 0..len {
debug_assert!(min_limit[i] >= 1);
debug_assert!(min_limit[i] <= max_limit[i]);
}
let precision = *max_limit.iter().max().unwrap();
let num_patterns = 1 << precision;
let mut dynp = vec![u64::MAX; (num_patterns + 1) * (len + 1)];
let index = |sym: usize, off: usize| sym * (num_patterns + 1) + off;
dynp[index(0, 0)] = 0;
for sym in 0..len {
for bits in min_limit[sym]..=max_limit[sym] {
let off_delta = 1 << (precision - bits);
for off in 0..=num_patterns.saturating_sub(off_delta) {
dynp[index(sym + 1, off + off_delta)] = dynp[index(sym, off)]
.saturating_add(freqs[sym] * u64::from(bits))
.min(dynp[index(sym + 1, off + off_delta)]);
}
}
}
let mut sym = len;
let mut off = num_patterns;
while sym > 0 {
sym -= 1;
assert!(off > 0);
for bits in min_limit[sym]..=max_limit[sym] {
let off_delta = 1 << (precision - bits);
if off_delta <= off
&& dynp[index(sym + 1, off)]
== dynp[index(sym, off - off_delta)]
.saturating_add(freqs[sym] * u64::from(bits))
{
off -= off_delta;
calculated_nbits[sym] = bits;
break;
}
}
}
for i in 0..len {
debug_assert!(calculated_nbits[i] >= min_limit[i]);
debug_assert!(calculated_nbits[i] <= max_limit[i]);
}
}
const fn compute_codes<const NSYMS: usize>(lengths: &[u8; NSYMS]) -> Option<[u16; NSYMS]> {
let mut codes = [0u16; NSYMS];
let mut code = 0u32;
let mut len = 1;
while len <= 16 {
let mut i = 0;
while i < lengths.len() {
if lengths[i] == len {
codes[i] = (code as u16).reverse_bits() >> (16 - len);
code += 1;
}
i += 1;
}
code <<= 1;
len += 1;
}
if code == 2 << 16 {
Some(codes)
} else {
None
}
}