#![allow(dead_code)]
use super::encode_primitives::{pack_signed, write_integer_config, write_varlen_u16};
use crate::bit_writer::BitWriter;
use crate::entropy_coding::huffman_tree::{
build_and_store_huffman_tree, convert_bit_depths_to_symbols, create_huffman_tree,
};
use crate::error::Result;
pub(super) fn write_zero_tree_complete(writer: &mut BitWriter) -> Result<()> {
crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: Starting tree histogram (Zero)",
writer.bits_written()
);
writer.write(1, 0)?;
writer.write(1, 1)?; writer.write(2, 0)?;
writer.write(1, 1)?;
const LOG_ALPHABET_SIZE_PREFIX: u32 = 15;
write_integer_config(
writer,
LOG_ALPHABET_SIZE_PREFIX,
LOG_ALPHABET_SIZE_PREFIX,
0,
0,
)?;
write_varlen_u16(writer, 0)?;
crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: After tree histogram (Zero)",
writer.bits_written()
);
Ok(())
}
pub(crate) fn write_tree_histogram_for_gradient(
writer: &mut BitWriter,
) -> Result<(Vec<u8>, Vec<u16>)> {
write_tree_histogram_for_predictor_impl(writer, true, 5)
}
pub(crate) fn write_tree_histogram_for_zero(writer: &mut BitWriter) -> Result<(Vec<u8>, Vec<u16>)> {
write_tree_histogram_for_predictor_impl(writer, true, 0)
}
fn write_tree_histogram_for_predictor_impl(
writer: &mut BitWriter,
write_lz77: bool,
predictor_id: u32,
) -> Result<(Vec<u8>, Vec<u16>)> {
crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: Starting tree histogram (lz77={})",
writer.bits_written(),
write_lz77
);
if write_lz77 {
writer.write(1, 0)?; crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: lz77.enabled = 0",
writer.bits_written()
);
}
writer.write(1, 1)?; writer.write(2, 0)?; crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: context_map (is_simple=1, bits=0)",
writer.bits_written()
);
writer.write(1, 1)?;
crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: use_prefix_code = 1",
writer.bits_written()
);
let max_symbol = if predictor_id == 0 {
0u16
} else {
predictor_id as u16
};
let tree_histogram: &[u32] = if predictor_id == 0 {
&[5u32]
} else {
&[4u32, 0, 0, 0, 0, 1]
};
const LOG_ALPHABET_SIZE_PREFIX: u32 = 15;
write_integer_config(
writer,
LOG_ALPHABET_SIZE_PREFIX,
LOG_ALPHABET_SIZE_PREFIX,
0,
0,
)?;
crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: IntegerConfig (log_alpha={}, split_exp={}, raw symbols)",
writer.bits_written(),
LOG_ALPHABET_SIZE_PREFIX,
LOG_ALPHABET_SIZE_PREFIX
);
let _alphabet_size = (max_symbol + 1) as u32;
write_varlen_u16(writer, max_symbol)?;
crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: alphabet_size-1 = {} (alphabet_size={})",
writer.bits_written(),
max_symbol,
_alphabet_size
);
let al_size = (max_symbol + 1) as usize;
let (depths, codes) = if al_size > 1 {
let table = build_and_store_huffman_tree(tree_histogram, writer)?;
crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: After Huffman table",
writer.bits_written()
);
(table.depths, table.codes)
} else {
crate::trace::debug_eprintln!(
" TREE_HIST [bit {}]: No Huffman table (al_size=1)",
writer.bits_written()
);
(vec![0u8; al_size], vec![0u16; al_size])
};
Ok((depths, codes))
}
pub(crate) fn write_zero_tree_tokens(
writer: &mut BitWriter,
depths: &[u8],
codes: &[u16],
) -> Result<()> {
write_single_leaf_tree_tokens(writer, depths, codes, 0)
}
pub(crate) fn write_gradient_tree_tokens(
writer: &mut BitWriter,
depths: &[u8],
codes: &[u16],
) -> Result<()> {
write_single_leaf_tree_tokens(writer, depths, codes, 5)
}
fn write_single_leaf_tree_tokens(
writer: &mut BitWriter,
depths: &[u8],
codes: &[u16],
predictor_id: u32,
) -> Result<()> {
crate::trace::debug_eprintln!(
" TREE_TOKENS [bit {}]: Starting tree tokens",
writer.bits_written()
);
let tree_predictor = predictor_id;
crate::trace::debug_eprintln!(" TREE_TOKENS: depths = {:?}", depths);
crate::trace::debug_eprintln!(" TREE_TOKENS: codes = {:?}", codes);
let tokens = [0u32, tree_predictor, 0, 0, 0];
let _token_names = ["property", "predictor", "offset", "mul_log", "mul_bits"];
#[allow(clippy::unused_enumerate_index)]
for (_i, &token) in tokens.iter().enumerate() {
let depth = depths.get(token as usize).copied().unwrap_or(0);
let code = codes.get(token as usize).copied().unwrap_or(0);
crate::trace::debug_eprintln!(
" TREE_TOKENS [bit {}]: {} = {} (depth={}, code={:0width$b})",
writer.bits_written(),
_token_names[_i],
token,
depth,
code,
width = depth.max(1) as usize
);
if depth > 0 {
writer.write(depth as usize, code as u64)?;
}
}
crate::trace::debug_eprintln!(" TREE_TOKENS [bit {}]: Done", writer.bits_written());
Ok(())
}
const USE_ZERO_PREDICTOR: bool = false;
pub(super) fn write_tree_histogram_for_weighted(writer: &mut BitWriter) -> Result<()> {
writer.write(1, 0)?;
writer.write(1, 1)?; writer.write(2, 0)?;
writer.write(1, 1)?;
const TREE_PREDICTOR: u32 = 6;
let max_symbol = TREE_PREDICTOR as u16;
let tree_histogram: &[u32] = &[4u32, 0, 0, 0, 0, 0, 1];
const LOG_ALPHABET_SIZE_PREFIX: u32 = 15;
write_integer_config(
writer,
LOG_ALPHABET_SIZE_PREFIX,
LOG_ALPHABET_SIZE_PREFIX,
0,
0,
)?;
write_varlen_u16(writer, max_symbol)?;
let al_size = (max_symbol + 1) as usize;
if al_size > 1 {
build_and_store_huffman_tree(tree_histogram, writer)?;
}
Ok(())
}
pub(super) fn write_weighted_tree_tokens(writer: &mut BitWriter) -> Result<()> {
const TREE_PREDICTOR: u32 = 6;
let tree_histogram = &[4u32, 0, 0, 0, 0, 0, 1]; let depths = create_huffman_tree(tree_histogram, 15);
let codes = convert_bit_depths_to_symbols(&depths);
let tokens = [0u32, TREE_PREDICTOR, 0, 0, 0];
for &token in &tokens {
let depth = depths.get(token as usize).copied().unwrap_or(0);
let code = codes.get(token as usize).copied().unwrap_or(0);
if depth > 0 {
writer.write(depth as usize, code as u64)?;
}
}
Ok(())
}
pub(super) fn write_wp_header(
writer: &mut BitWriter,
params: &super::predictor::WeightedPredictorParams,
) -> Result<()> {
if params.is_default() {
writer.write(1, 1)?;
} else {
writer.write(1, 0)?;
writer.write(5, params.p1c as u64)?;
writer.write(5, params.p2c as u64)?;
writer.write(5, params.p3ca as u64)?;
writer.write(5, params.p3cb as u64)?;
writer.write(5, params.p3cc as u64)?;
writer.write(5, params.p3cd as u64)?;
writer.write(5, params.p3ce as u64)?;
writer.write(4, params.w0 as u64)?;
writer.write(4, params.w1 as u64)?;
writer.write(4, params.w2 as u64)?;
writer.write(4, params.w3 as u64)?;
}
Ok(())
}
pub fn write_tree(writer: &mut BitWriter, tree: &super::tree::Tree) -> Result<()> {
use super::tree::collect_tree_tokens;
use crate::entropy_coding::hybrid_uint::HybridUintConfig;
let tokens = collect_tree_tokens(tree);
let hybrid_config = HybridUintConfig::new(4, 2, 0);
struct EncodedTreeToken {
token: u32,
extra_bits: u32,
num_extra: u32,
}
let mut encoded: Vec<EncodedTreeToken> = Vec::with_capacity(tokens.len());
let mut max_token: u32 = 0;
for t in &tokens {
let val = if t.is_signed {
pack_signed(t.value)
} else {
t.value as u32
};
let (token, extra_bits, num_extra) = hybrid_config.encode(val);
max_token = max_token.max(token);
encoded.push(EncodedTreeToken {
token,
extra_bits,
num_extra,
});
}
let histogram_size = (max_token + 1) as usize;
let mut histogram = vec![0u32; histogram_size];
for e in &encoded {
histogram[e.token as usize] += 1;
}
writer.write(1, 0)?;
writer.write(1, 1)?; writer.write(2, 0)?;
writer.write(1, 1)?;
const LOG_ALPHABET_SIZE: u32 = 15;
write_integer_config(
writer,
LOG_ALPHABET_SIZE,
hybrid_config.split_exponent,
hybrid_config.msb_in_token,
hybrid_config.lsb_in_token,
)?;
write_varlen_u16(writer, max_token as u16)?;
let (depths, codes) = if histogram_size > 1 {
let table = build_and_store_huffman_tree(&histogram[..histogram_size], writer)?;
(table.depths, table.codes)
} else {
(vec![0u8; histogram_size], vec![0u16; histogram_size])
};
for e in &encoded {
let depth = depths.get(e.token as usize).copied().unwrap_or(0);
let code = codes.get(e.token as usize).copied().unwrap_or(0);
if depth > 0 {
writer.write(depth as usize, code as u64)?;
}
if e.num_extra > 0 {
writer.write(e.num_extra as usize, e.extra_bits as u64)?;
}
}
Ok(())
}