Coverage Report

Created: 2026-05-30 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}