use std::{hint::black_box, mem::size_of};
use butils::UnitPrefix;
use constriction::{
backends::Cursor, symbol::{
huffman::{DecoderHuffmanTree, EncoderHuffmanTree},
DefaultQueueEncoder, DefaultStackCoder, EncoderCodebook, QueueDecoder, ReadBitStream, WriteBitStream
}, UnwrapInfallible};
use crate::{compare_texts, minimum_redundancy::frequencies_u8};
#[inline(always)] fn encode_prefix(text: &Box<[u8]>, encoder_codebook: &EncoderHuffmanTree) -> Vec<u32> {
let mut encoder = DefaultQueueEncoder::new();
encoder.encode_iid_symbols(text.iter().map(|v| *v as usize), encoder_codebook).unwrap();
encoder.into_compressed().unwrap_infallible()
}
#[inline(always)] fn encode_suffix(text: &Box<[u8]>, encoder_codebook: &EncoderHuffmanTree) -> DefaultStackCoder {
let mut encoder = DefaultStackCoder::new();
encoder.encode_iid_symbols_reverse(text.iter().map(|v| *v as usize), encoder_codebook).unwrap();
encoder
}
pub fn benchmark(conf: &super::Conf) {
println!("### constriction ###");
let text = conf.text();
let frequencies= frequencies_u8(conf, &text);
let dec_constr_ns = conf.measure(|| DecoderHuffmanTree::from_probabilities::<usize, _>(&frequencies)).as_nanos();
let enc_constr_ns = conf.measure(|| EncoderHuffmanTree::from_probabilities::<usize, _>(&frequencies)).as_nanos();
println!(" Decoder + encoder construction time [ns]: {:.0} + {:.0} = {:.0}", dec_constr_ns, enc_constr_ns, dec_constr_ns+enc_constr_ns);
let encoder_codebook = EncoderHuffmanTree::from_probabilities::<usize, _>(&frequencies);
let decoder_codebook = DecoderHuffmanTree::from_probabilities::<usize, _>(&frequencies);
println!(" Decoder size (lower estimate): {} bytes",
(decoder_codebook.num_symbols()-1) * size_of::<[usize; 2]>() + size_of::<DecoderHuffmanTree>()
);
println!(" Encoding without adding to bit vector:");
conf.print_speed(" prefix order", conf.measure(|| { for k in text.iter() {
let _ = encoder_codebook.encode_symbol_prefix(*k as usize, |bit| {
black_box(bit); Result::<(), ()>::Ok(())
});
}
}));
conf.print_speed(" suffix order", conf.measure(|| {
for k in text.iter() {
let _ = encoder_codebook.encode_symbol_suffix(*k as usize, |bit| {
black_box(bit); Result::<(), ()>::Ok(())
});
}
}));
println!(" Encoding + adding to bit vector:");
conf.print_speed(" prefix order", conf.measure(|| encode_prefix(&text, &encoder_codebook)));
conf.print_speed(" suffix order", conf.measure(|| encode_suffix(&text, &encoder_codebook)));
println!(" Decoding (without storing):");
let cursor = Cursor::new_at_write_beginning(encode_prefix(&text, &encoder_codebook));
conf.print_speed(" from a queue (prefix order)", conf.measure(|| {
let mut decoder = QueueDecoder::from_compressed(cursor.as_view());
for sym in decoder.decode_iid_symbols(text.len(), &decoder_codebook) {
let _ = black_box(sym);
}
}));
if conf.verify {
print!(" verifying decoding from a queue... ");
let mut decoder = QueueDecoder::from_compressed(cursor.as_view());
let reconstructed: Vec<u8> = decoder
.decode_iid_symbols(text.len(), &decoder_codebook)
.map(|sym| sym.unwrap() as u8)
.collect();
compare_texts(&text, &reconstructed);
assert!(decoder.maybe_exhausted());
}
drop(cursor);
let mut encoder = encode_suffix(&text, &encoder_codebook);
conf.print_speed(" from a stack (suffix order)", conf.measure(|| {
let mut decoder = encoder.as_decoder();
for sym in decoder.decode_iid_symbols(text.len(), &decoder_codebook) {
let _ = black_box(sym);
}
}));
conf.print_compressed_size(encoder.len());
if conf.verify {
print!(" verifying decoding from a stack... ");
let reconstructed: Vec<u8> = encoder
.decode_iid_symbols(text.len(), &decoder_codebook)
.map(|sym| sym.unwrap() as u8)
.collect();
compare_texts(&text, &reconstructed);
}
}