use super::constants::{NUM_COMMAND_SYMBOLS, NUM_LITERAL_SYMBOLS};
use super::huffman::{HuffmanNode, tree_capacity};
use super::tables::{
DEFAULT_COMMAND_BITS, DEFAULT_COMMAND_CODE, DEFAULT_COMMAND_CODE_NUM_BITS,
DEFAULT_COMMAND_DEPTHS,
};
const COMMAND_CODE_CAPACITY: usize = 512;
pub(crate) struct OnePassArena {
pub(crate) lit_depth: [u8; NUM_LITERAL_SYMBOLS],
pub(crate) lit_bits: [u16; NUM_LITERAL_SYMBOLS],
pub(crate) cmd_depth: [u8; 128],
pub(crate) cmd_bits: [u16; 128],
pub(crate) cmd_histo: [u32; 128],
pub(crate) cmd_code: [u8; COMMAND_CODE_CAPACITY],
pub(crate) cmd_code_numbits: usize,
pub(crate) tree: Vec<HuffmanNode>,
pub(crate) histogram: [u32; NUM_LITERAL_SYMBOLS],
pub(crate) tmp_depth: [u8; NUM_COMMAND_SYMBOLS],
pub(crate) tmp_bits: [u16; 64],
}
impl OnePassArena {
pub(crate) fn reset(&mut self) {
self.lit_depth.fill(0);
self.lit_bits.fill(0);
self.cmd_depth = DEFAULT_COMMAND_DEPTHS;
self.cmd_bits = DEFAULT_COMMAND_BITS;
self.cmd_histo.fill(0);
self.cmd_code.fill(0);
self.cmd_code[..DEFAULT_COMMAND_CODE.len()].copy_from_slice(&DEFAULT_COMMAND_CODE);
self.cmd_code_numbits = DEFAULT_COMMAND_CODE_NUM_BITS;
self.tree.fill(HuffmanNode::default());
self.histogram.fill(0);
self.tmp_depth.fill(0);
self.tmp_bits.fill(0);
}
}
impl Default for OnePassArena {
fn default() -> Self {
let mut cmd_code = [0u8; COMMAND_CODE_CAPACITY];
cmd_code[..DEFAULT_COMMAND_CODE.len()].copy_from_slice(&DEFAULT_COMMAND_CODE);
Self {
lit_depth: [0; NUM_LITERAL_SYMBOLS],
lit_bits: [0; NUM_LITERAL_SYMBOLS],
cmd_depth: DEFAULT_COMMAND_DEPTHS,
cmd_bits: DEFAULT_COMMAND_BITS,
cmd_histo: [0; 128],
cmd_code,
cmd_code_numbits: DEFAULT_COMMAND_CODE_NUM_BITS,
tree: vec![HuffmanNode::default(); tree_capacity(NUM_LITERAL_SYMBOLS)],
histogram: [0; NUM_LITERAL_SYMBOLS],
tmp_depth: [0; NUM_COMMAND_SYMBOLS],
tmp_bits: [0; 64],
}
}
}
pub(crate) struct TwoPassArena {
pub(crate) lit_histo: [u32; NUM_LITERAL_SYMBOLS],
pub(crate) lit_depth: [u8; NUM_LITERAL_SYMBOLS],
pub(crate) lit_bits: [u16; NUM_LITERAL_SYMBOLS],
pub(crate) cmd_histo: [u32; 128],
pub(crate) cmd_depth: [u8; 128],
pub(crate) cmd_bits: [u16; 128],
pub(crate) tmp_tree: Vec<HuffmanNode>,
pub(crate) tmp_depth: [u8; NUM_COMMAND_SYMBOLS],
pub(crate) tmp_bits: [u16; 64],
}
impl TwoPassArena {
pub(crate) fn reset(&mut self) {
self.lit_histo.fill(0);
self.lit_depth.fill(0);
self.lit_bits.fill(0);
self.cmd_histo.fill(0);
self.cmd_depth.fill(0);
self.cmd_bits.fill(0);
self.tmp_tree.fill(HuffmanNode::default());
self.tmp_depth.fill(0);
self.tmp_bits.fill(0);
}
}
impl Default for TwoPassArena {
fn default() -> Self {
Self {
lit_histo: [0; NUM_LITERAL_SYMBOLS],
lit_depth: [0; NUM_LITERAL_SYMBOLS],
lit_bits: [0; NUM_LITERAL_SYMBOLS],
cmd_histo: [0; 128],
cmd_depth: [0; 128],
cmd_bits: [0; 128],
tmp_tree: vec![HuffmanNode::default(); tree_capacity(NUM_LITERAL_SYMBOLS)],
tmp_depth: [0; NUM_COMMAND_SYMBOLS],
tmp_bits: [0; 64],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn one_pass_arena_starts_from_the_reference_command_code() {
let arena = OnePassArena::default();
assert_eq!(arena.cmd_code_numbits, 448);
assert_eq!(&arena.cmd_code[..57], &DEFAULT_COMMAND_CODE);
assert!(arena.cmd_code[57..].iter().all(|&b| b == 0));
assert_eq!(arena.cmd_depth, DEFAULT_COMMAND_DEPTHS);
assert_eq!(arena.cmd_bits, DEFAULT_COMMAND_BITS);
assert_eq!(arena.tree.len(), 513);
}
#[test]
fn two_pass_arena_starts_cleared() {
let arena = TwoPassArena::default();
assert!(arena.lit_histo.iter().all(|&c| c == 0));
assert!(arena.cmd_histo.iter().all(|&c| c == 0));
assert_eq!(arena.tmp_tree.len(), 513);
}
}