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 stride = xself.get_stride(xself.local_byte_offset()) as usize;
44            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
77// not sure why this fails
78//impl<'a> interface::CommandProcessor<'a> for IRInterpreter {
79//    fn push<Cb: FnMut(&[interface::Command<InputReference>])>(&mut self,
80//                                                              val: interface::Command<InputReference<'a>>,
81//                                                              callback: &mut Cb) {
82//        push_base(self, val, callback)
83//    }
84//}
85
86fn compute_huffman_table_index_for_context_map(
87    prev_byte: u8,
88    prev_prev_byte: u8,
89    literal_context_map: &[u8], //interface::PredictionModeContextMap<SliceType>,
90    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    //  0u8
121}