/src/rust-brotli/src/enc/stride_eval.rs
Line | Count | Source |
1 | | use core; |
2 | | |
3 | | use super::super::alloc; |
4 | | use super::super::alloc::{Allocator, SliceWrapper, SliceWrapperMut}; |
5 | | use super::backward_references::BrotliEncoderParams; |
6 | | use super::input_pair::{InputPair, InputReference, InputReferenceMut}; |
7 | | use super::interface; |
8 | | use super::ir_interpret::{push_base, IRInterpreter}; |
9 | | use super::prior_eval::DEFAULT_SPEED; |
10 | | use super::util::{floatX, FastLog2u16}; |
11 | | use crate::enc::combined_alloc::{alloc_default, allocate}; |
12 | | const NIBBLE_PRIOR_SIZE: usize = 16; |
13 | | pub const STRIDE_PRIOR_SIZE: usize = 256 * 256 * NIBBLE_PRIOR_SIZE * 2; |
14 | | |
15 | 0 | pub fn local_init_cdfs(cdfs: &mut [u16]) { |
16 | 0 | for (index, item) in cdfs.iter_mut().enumerate() { |
17 | 0 | *item = 4 + 4 * (index as u16 & 0x0f); |
18 | 0 | } |
19 | 0 | } |
20 | | #[allow(unused_variables)] |
21 | 0 | fn stride_lookup_lin( |
22 | 0 | stride_byte: u8, |
23 | 0 | selected_context: u8, |
24 | 0 | actual_context: usize, |
25 | 0 | high_nibble: Option<u8>, |
26 | 0 | ) -> usize { |
27 | 0 | if let Some(nibble) = high_nibble { |
28 | 0 | 1 + 2 * (actual_context | ((stride_byte as usize & 0xf) << 8) | ((nibble as usize) << 12)) |
29 | | } else { |
30 | 0 | 2 * (actual_context | ((stride_byte as usize) << 8)) |
31 | | } |
32 | 0 | } |
33 | | |
34 | | struct CDF<'a> { |
35 | | cdf: &'a mut [u16], |
36 | | } |
37 | | struct Stride1Prior {} |
38 | | impl Stride1Prior { |
39 | 0 | fn lookup_lin( |
40 | 0 | stride_byte: u8, |
41 | 0 | selected_context: u8, |
42 | 0 | actual_context: usize, |
43 | 0 | high_nibble: Option<u8>, |
44 | 0 | ) -> usize { |
45 | 0 | stride_lookup_lin(stride_byte, selected_context, actual_context, high_nibble) |
46 | 0 | } |
47 | 0 | fn lookup_mut( |
48 | 0 | data: &mut [u16], |
49 | 0 | stride_byte: u8, |
50 | 0 | selected_context: u8, |
51 | 0 | actual_context: usize, |
52 | 0 | high_nibble: Option<u8>, |
53 | 0 | ) -> CDF<'_> { |
54 | 0 | let index = Self::lookup_lin(stride_byte, selected_context, actual_context, high_nibble) |
55 | 0 | * NIBBLE_PRIOR_SIZE; |
56 | 0 | CDF::from(data.split_at_mut(index).1.split_at_mut(16).0) |
57 | 0 | } |
58 | | } |
59 | | |
60 | | impl<'a> CDF<'a> { |
61 | 0 | pub fn cost(&self, nibble_u8: u8) -> floatX { |
62 | 0 | assert_eq!(self.cdf.len(), 16); |
63 | 0 | let nibble = nibble_u8 as usize & 0xf; |
64 | 0 | let mut pdf = self.cdf[nibble]; |
65 | 0 | if nibble_u8 != 0 { |
66 | 0 | pdf -= self.cdf[nibble - 1]; |
67 | 0 | } |
68 | 0 | FastLog2u16(self.cdf[15]) - FastLog2u16(pdf) |
69 | 0 | } |
70 | 0 | pub fn update(&mut self, nibble_u8: u8, speed: (u16, u16)) { |
71 | 0 | assert_eq!(self.cdf.len(), 16); |
72 | 0 | for nib_range in (nibble_u8 as usize & 0xf)..16 { |
73 | 0 | self.cdf[nib_range] += speed.0; |
74 | 0 | } |
75 | 0 | if self.cdf[15] >= speed.1 { |
76 | | const CDF_BIAS: [u16; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; |
77 | 0 | for nibble_index in 0..16 { |
78 | 0 | let tmp = &mut self.cdf[nibble_index]; |
79 | 0 | *tmp = (tmp.wrapping_add(CDF_BIAS[nibble_index])) |
80 | 0 | .wrapping_sub(tmp.wrapping_add(CDF_BIAS[nibble_index]) >> 2); |
81 | 0 | } |
82 | 0 | } |
83 | 0 | } |
84 | | } |
85 | | |
86 | | impl<'a> From<&'a mut [u16]> for CDF<'a> { |
87 | 0 | fn from(cdf: &'a mut [u16]) -> CDF<'a> { |
88 | 0 | assert_eq!(cdf.len(), 16); |
89 | 0 | CDF { cdf } |
90 | 0 | } |
91 | | } |
92 | | |
93 | | pub struct StrideEval< |
94 | | 'a, |
95 | | Alloc: alloc::Allocator<u16> + alloc::Allocator<u32> + alloc::Allocator<floatX> + 'a, |
96 | | > { |
97 | | input: InputPair<'a>, |
98 | | alloc: &'a mut Alloc, |
99 | | context_map: &'a interface::PredictionModeContextMap<InputReferenceMut<'a>>, |
100 | | block_type: u8, |
101 | | local_byte_offset: usize, |
102 | | stride_priors: [<Alloc as Allocator<u16>>::AllocatedMemory; 8], |
103 | | score: <Alloc as Allocator<floatX>>::AllocatedMemory, |
104 | | cur_score_epoch: usize, |
105 | | stride_speed: [(u16, u16); 2], |
106 | | cur_stride: u8, |
107 | | } |
108 | | |
109 | | impl<'a, Alloc: alloc::Allocator<u16> + alloc::Allocator<u32> + alloc::Allocator<floatX> + 'a> |
110 | | StrideEval<'a, Alloc> |
111 | | { |
112 | 0 | pub fn new( |
113 | 0 | alloc: &'a mut Alloc, |
114 | 0 | input: InputPair<'a>, |
115 | 0 | prediction_mode: &'a interface::PredictionModeContextMap<InputReferenceMut<'a>>, |
116 | 0 | params: &BrotliEncoderParams, |
117 | 0 | ) -> Self { |
118 | 0 | let do_alloc = true; |
119 | 0 | let mut stride_speed = prediction_mode.stride_context_speed(); |
120 | 0 | if stride_speed[0] == (0, 0) { |
121 | 0 | stride_speed[0] = params.literal_adaptation[0] |
122 | 0 | } |
123 | 0 | if stride_speed[0] == (0, 0) { |
124 | 0 | stride_speed[0] = DEFAULT_SPEED; |
125 | 0 | } |
126 | 0 | if stride_speed[1] == (0, 0) { |
127 | 0 | stride_speed[1] = params.literal_adaptation[1] |
128 | 0 | } |
129 | 0 | if stride_speed[1] == (0, 0) { |
130 | 0 | stride_speed[1] = stride_speed[0]; |
131 | 0 | } |
132 | 0 | let score = if do_alloc { |
133 | 0 | allocate::<floatX, _>(alloc, 8 * 4) // FIXME make this bigger than just 4 |
134 | | } else { |
135 | 0 | alloc_default::<floatX, Alloc>() |
136 | | }; |
137 | 0 | let stride_priors = if do_alloc { |
138 | 0 | [ |
139 | 0 | allocate::<u16, _>(alloc, STRIDE_PRIOR_SIZE), |
140 | 0 | allocate::<u16, _>(alloc, STRIDE_PRIOR_SIZE), |
141 | 0 | allocate::<u16, _>(alloc, STRIDE_PRIOR_SIZE), |
142 | 0 | allocate::<u16, _>(alloc, STRIDE_PRIOR_SIZE), |
143 | 0 | allocate::<u16, _>(alloc, STRIDE_PRIOR_SIZE), |
144 | 0 | allocate::<u16, _>(alloc, STRIDE_PRIOR_SIZE), |
145 | 0 | allocate::<u16, _>(alloc, STRIDE_PRIOR_SIZE), |
146 | 0 | allocate::<u16, _>(alloc, STRIDE_PRIOR_SIZE), |
147 | 0 | ] |
148 | | } else { |
149 | 0 | [ |
150 | 0 | alloc_default::<u16, Alloc>(), |
151 | 0 | alloc_default::<u16, Alloc>(), |
152 | 0 | alloc_default::<u16, Alloc>(), |
153 | 0 | alloc_default::<u16, Alloc>(), |
154 | 0 | alloc_default::<u16, Alloc>(), |
155 | 0 | alloc_default::<u16, Alloc>(), |
156 | 0 | alloc_default::<u16, Alloc>(), |
157 | 0 | alloc_default::<u16, Alloc>(), |
158 | 0 | ] |
159 | | }; |
160 | 0 | let mut ret = StrideEval::<Alloc> { |
161 | 0 | input, |
162 | 0 | context_map: prediction_mode, |
163 | 0 | block_type: 0, |
164 | 0 | alloc, |
165 | 0 | cur_stride: 1, |
166 | 0 | cur_score_epoch: 0, |
167 | 0 | local_byte_offset: 0, |
168 | 0 | stride_priors, |
169 | 0 | score, |
170 | 0 | stride_speed, |
171 | 0 | }; |
172 | 0 | for stride_prior in ret.stride_priors.iter_mut() { |
173 | 0 | local_init_cdfs(stride_prior.slice_mut()); |
174 | 0 | } |
175 | 0 | ret |
176 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc>>::new Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_>>::new |
177 | 0 | pub fn alloc(&mut self) -> &mut Alloc { |
178 | 0 | self.alloc |
179 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc>>::alloc Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_>>::alloc |
180 | 0 | pub fn choose_stride(&self, stride_data: &mut [u8]) { |
181 | 0 | assert_eq!(stride_data.len(), self.cur_score_epoch); |
182 | 0 | assert!(self.score.slice().len() > stride_data.len()); |
183 | 0 | assert!(self.score.slice().len() > (stride_data.len() << 3) + 7 + 8); |
184 | 0 | for (index, choice) in stride_data.iter_mut().enumerate() { |
185 | 0 | let choices = self |
186 | 0 | .score |
187 | 0 | .slice() |
188 | 0 | .split_at((1 + index) << 3) |
189 | 0 | .1 |
190 | 0 | .split_at(8) |
191 | 0 | .0; |
192 | 0 | let mut best_choice: u8 = 0; |
193 | 0 | let mut best_score = choices[0]; |
194 | 0 | for (cur_index, cur_score) in choices.iter().enumerate() { |
195 | 0 | if *cur_score + 2.0 < best_score { |
196 | 0 | // needs to be 2 bits better to be worth the type switch |
197 | 0 | best_score = *cur_score; |
198 | 0 | best_choice = cur_index as u8; |
199 | 0 | } |
200 | | } |
201 | 0 | *choice = best_choice; |
202 | | } |
203 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc>>::choose_stride Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_>>::choose_stride |
204 | 0 | pub fn num_types(&self) -> usize { |
205 | 0 | self.cur_score_epoch |
206 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc>>::num_types Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_>>::num_types |
207 | 0 | fn update_cost_base( |
208 | 0 | &mut self, |
209 | 0 | stride_prior: [u8; 8], |
210 | 0 | selected_bits: u8, |
211 | 0 | cm_prior: usize, |
212 | 0 | literal: u8, |
213 | 0 | ) { |
214 | | type CurPrior = Stride1Prior; |
215 | | { |
216 | 0 | for i in 0..8 { |
217 | 0 | let mut cdf = CurPrior::lookup_mut( |
218 | 0 | self.stride_priors[i].slice_mut(), |
219 | 0 | stride_prior[i], |
220 | 0 | selected_bits, |
221 | 0 | cm_prior, |
222 | 0 | None, |
223 | 0 | ); |
224 | 0 | self.score.slice_mut()[self.cur_score_epoch * 8 + i] += cdf.cost(literal >> 4); |
225 | 0 | cdf.update(literal >> 4, self.stride_speed[1]); |
226 | 0 | } |
227 | | } |
228 | | { |
229 | 0 | for i in 0..8 { |
230 | 0 | let mut cdf = CurPrior::lookup_mut( |
231 | 0 | self.stride_priors[i].slice_mut(), |
232 | 0 | stride_prior[i], |
233 | 0 | selected_bits, |
234 | 0 | cm_prior, |
235 | 0 | Some(literal >> 4), |
236 | 0 | ); |
237 | 0 | self.score.slice_mut()[self.cur_score_epoch * 8 + i] += cdf.cost(literal & 0xf); |
238 | 0 | cdf.update(literal & 0xf, self.stride_speed[0]); |
239 | 0 | } |
240 | | } |
241 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc>>::update_cost_base Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_>>::update_cost_base |
242 | | } |
243 | | impl<'a, Alloc: alloc::Allocator<u16> + alloc::Allocator<u32> + alloc::Allocator<floatX>> Drop |
244 | | for StrideEval<'a, Alloc> |
245 | | { |
246 | 0 | fn drop(&mut self) { |
247 | 0 | <Alloc as Allocator<floatX>>::free_cell(self.alloc, core::mem::take(&mut self.score)); |
248 | 0 | for i in 0..8 { |
249 | 0 | <Alloc as Allocator<u16>>::free_cell( |
250 | 0 | self.alloc, |
251 | 0 | core::mem::take(&mut self.stride_priors[i]), |
252 | 0 | ); |
253 | 0 | } |
254 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as core::ops::drop::Drop>::drop Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as core::ops::drop::Drop>::drop |
255 | | } |
256 | | |
257 | | impl<'a, Alloc: alloc::Allocator<u16> + alloc::Allocator<u32> + alloc::Allocator<floatX>> |
258 | | IRInterpreter for StrideEval<'a, Alloc> |
259 | | { |
260 | 0 | fn inc_local_byte_offset(&mut self, inc: usize) { |
261 | 0 | self.local_byte_offset += inc; |
262 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::ir_interpret::IRInterpreter>::inc_local_byte_offset Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::ir_interpret::IRInterpreter>::inc_local_byte_offset |
263 | 0 | fn local_byte_offset(&self) -> usize { |
264 | 0 | self.local_byte_offset |
265 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::ir_interpret::IRInterpreter>::local_byte_offset Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::ir_interpret::IRInterpreter>::local_byte_offset |
266 | 0 | fn update_block_type(&mut self, new_type: u8, stride: u8) { |
267 | 0 | self.block_type = new_type; |
268 | 0 | self.cur_stride = stride; |
269 | 0 | self.cur_score_epoch += 1; |
270 | 0 | if self.cur_score_epoch * 8 + 7 >= self.score.slice().len() { |
271 | 0 | let new_len = self.score.slice().len() * 2; |
272 | 0 | let mut new_score = allocate::<floatX, _>(self.alloc, new_len); |
273 | 0 | for (src, dst) in self.score.slice().iter().zip( |
274 | 0 | new_score |
275 | 0 | .slice_mut() |
276 | 0 | .split_at_mut(self.score.slice().len()) |
277 | 0 | .0 |
278 | 0 | .iter_mut(), |
279 | 0 | ) { |
280 | 0 | *dst = *src; |
281 | 0 | } |
282 | 0 | <Alloc as Allocator<floatX>>::free_cell( |
283 | 0 | self.alloc, |
284 | 0 | core::mem::replace(&mut self.score, new_score), |
285 | | ); |
286 | 0 | } |
287 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::ir_interpret::IRInterpreter>::update_block_type Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::ir_interpret::IRInterpreter>::update_block_type |
288 | 0 | fn block_type(&self) -> u8 { |
289 | 0 | self.block_type |
290 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::ir_interpret::IRInterpreter>::block_type Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::ir_interpret::IRInterpreter>::block_type |
291 | 0 | fn literal_data_at_offset(&self, index: usize) -> u8 { |
292 | 0 | self.input[index] |
293 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::ir_interpret::IRInterpreter>::literal_data_at_offset Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::ir_interpret::IRInterpreter>::literal_data_at_offset |
294 | 0 | fn literal_context_map(&self) -> &[u8] { |
295 | 0 | self.context_map.literal_context_map.slice() |
296 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::ir_interpret::IRInterpreter>::literal_context_map Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::ir_interpret::IRInterpreter>::literal_context_map |
297 | 0 | fn prediction_mode(&self) -> crate::interface::LiteralPredictionModeNibble { |
298 | 0 | self.context_map.literal_prediction_mode() |
299 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::ir_interpret::IRInterpreter>::prediction_mode Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::ir_interpret::IRInterpreter>::prediction_mode |
300 | 0 | fn update_cost( |
301 | 0 | &mut self, |
302 | 0 | stride_prior: [u8; 8], |
303 | 0 | stride_prior_offset: usize, |
304 | 0 | selected_bits: u8, |
305 | 0 | cm_prior: usize, |
306 | 0 | literal: u8, |
307 | 0 | ) { |
308 | 0 | let reversed_stride_priors = [ |
309 | 0 | stride_prior[stride_prior_offset & 7], |
310 | 0 | stride_prior[stride_prior_offset.wrapping_sub(1) & 7], |
311 | 0 | stride_prior[stride_prior_offset.wrapping_sub(2) & 7], |
312 | 0 | stride_prior[stride_prior_offset.wrapping_sub(3) & 7], |
313 | 0 | stride_prior[stride_prior_offset.wrapping_sub(4) & 7], |
314 | 0 | stride_prior[stride_prior_offset.wrapping_sub(5) & 7], |
315 | 0 | stride_prior[stride_prior_offset.wrapping_sub(6) & 7], |
316 | 0 | stride_prior[stride_prior_offset.wrapping_sub(7) & 7], |
317 | 0 | ]; |
318 | 0 | self.update_cost_base(reversed_stride_priors, selected_bits, cm_prior, literal) |
319 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::ir_interpret::IRInterpreter>::update_cost Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::ir_interpret::IRInterpreter>::update_cost |
320 | | } |
321 | | |
322 | | impl<'a, 'b, Alloc: alloc::Allocator<u16> + alloc::Allocator<u32> + alloc::Allocator<floatX>> |
323 | | interface::CommandProcessor<'b> for StrideEval<'a, Alloc> |
324 | | { |
325 | 0 | fn push(&mut self, val: interface::Command<InputReference<'b>>) { |
326 | 0 | push_base(self, val) |
327 | 0 | } Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<alloc_stdlib::std_alloc::StandardAlloc> as brotli::enc::interface::CommandProcessor>::push Unexecuted instantiation: <brotli::enc::stride_eval::StrideEval<_> as brotli::enc::interface::CommandProcessor>::push |
328 | | } |