brotli/enc/
ir_interpret.rs
1use super::super::alloc::SliceWrapper;
2use super::constants::{kSigned3BitContextLookup, kUTF8ContextLookup};
3use super::histogram::ContextType;
4use super::input_pair::InputReference;
5use super::interface;
6use super::interface::LiteralPredictionModeNibble;
7pub trait IRInterpreter {
8 fn inc_local_byte_offset(&mut self, inc: usize);
9 fn local_byte_offset(&self) -> usize;
10 fn update_block_type(&mut self, new_type: u8, new_stride: u8);
11 fn block_type(&self) -> u8;
12 fn literal_data_at_offset(&self, index: usize) -> u8;
13 fn literal_context_map(&self) -> &[u8];
14 fn prediction_mode(&self) -> crate::interface::LiteralPredictionModeNibble;
15 fn update_cost(
16 &mut self,
17 stride_prior: [u8; 8],
18 stride_byte_offset: usize,
19 selected_bits: u8,
20 cm_prior: usize,
21 literal: u8,
22 );
23}
24
25pub fn push_base<Interpreter: IRInterpreter>(
26 xself: &mut Interpreter,
27 val: interface::Command<InputReference<'_>>,
28) {
29 match val {
30 interface::Command::BlockSwitchCommand(_)
31 | interface::Command::BlockSwitchDistance(_)
32 | interface::Command::PredictionMode(_) => {}
33 interface::Command::Copy(ref copy) => {
34 xself.inc_local_byte_offset(copy.num_bytes as usize);
35 }
36 interface::Command::Dict(ref dict) => {
37 xself.inc_local_byte_offset(dict.final_size as usize);
38 }
39 interface::Command::BlockSwitchLiteral(block_type) => {
40 xself.update_block_type(block_type.block_type(), block_type.stride())
41 }
42 interface::Command::Literal(ref lit) => {
43 let mut priors = [0u8; 8];
45 for poffset in 0..8 {
46 if xself.local_byte_offset() > poffset {
47 let input_offset = xself.local_byte_offset() - poffset - 1;
48 priors[7 - poffset] = xself.literal_data_at_offset(input_offset);
49 }
50 }
51 let mut cur = 0usize;
52 for literal in lit.data.slice().iter() {
53 let (huffman_table_index, selected_bits) =
54 compute_huffman_table_index_for_context_map(
55 priors[(cur + 7) & 7],
56 priors[(cur + 6) & 7],
57 xself.literal_context_map(),
58 xself.prediction_mode(),
59 xself.block_type(),
60 );
61 xself.update_cost(
62 priors,
63 (cur + 7) & 7,
64 selected_bits,
65 huffman_table_index,
66 *literal,
67 );
68 priors[cur & 7] = *literal;
69 cur += 1;
70 cur &= 7;
71 }
72 xself.inc_local_byte_offset(lit.data.slice().len());
73 }
74 }
75}
76
77fn compute_huffman_table_index_for_context_map(
87 prev_byte: u8,
88 prev_prev_byte: u8,
89 literal_context_map: &[u8], prediction_mode: LiteralPredictionModeNibble,
91 block_type: u8,
92) -> (usize, u8) {
93 let prior = Context(
94 prev_byte,
95 prev_prev_byte,
96 prediction_mode.to_context_enum().unwrap(),
97 );
98 assert!(prior < 64);
99 let context_map_index = ((block_type as usize) << 6) | prior as usize;
100 if context_map_index < literal_context_map.len() {
101 (literal_context_map[context_map_index] as usize, prior)
102 } else {
103 (prior as usize, prior)
104 }
105}
106
107pub fn Context(p1: u8, p2: u8, mode: ContextType) -> u8 {
108 match mode {
109 ContextType::CONTEXT_LSB6 => p1 & 0x3f,
110 ContextType::CONTEXT_MSB6 => (p1 as i32 >> 2) as u8,
111 ContextType::CONTEXT_UTF8 => {
112 (kUTF8ContextLookup[p1 as usize] as i32
113 | kUTF8ContextLookup[(p2 as i32 + 256i32) as usize] as i32) as u8
114 }
115 ContextType::CONTEXT_SIGNED => {
116 (((kSigned3BitContextLookup[p1 as usize] as i32) << 3)
117 + kSigned3BitContextLookup[p2 as usize] as i32) as u8
118 }
119 }
120 }