1use core;
2use core::cmp::{max, min};
3
4use super::super::alloc;
5use super::super::alloc::{Allocator, SliceWrapper, SliceWrapperMut};
6use super::backward_references::BrotliEncoderParams;
7use super::bit_cost::{BitsEntropy, BrotliPopulationCost};
8use super::block_split::BlockSplit;
9use super::block_splitter::BrotliSplitBlock;
10use super::brotli_bit_stream::MetaBlockSplit;
11use super::cluster::BrotliClusterHistograms;
12use super::combined_alloc::BrotliAlloc;
13use super::command::{BrotliDistanceParams, Command, PrefixEncodeCopyDistance};
14use super::constants::BROTLI_MAX_NPOSTFIX;
15use super::encode::{
16 BROTLI_DISTANCE_ALPHABET_SIZE, BROTLI_LARGE_MAX_DISTANCE_BITS, BROTLI_MAX_ALLOWED_DISTANCE,
17 BROTLI_MAX_DISTANCE_BITS,
18};
19use super::entropy_encode::BrotliOptimizeHuffmanCountsForRle;
20use super::histogram::{
21 BrotliBuildHistogramsWithContext, ClearHistograms, Context, ContextType, CostAccessors,
22 HistogramAddHistogram, HistogramAddItem, HistogramClear, HistogramCommand, HistogramDistance,
23 HistogramLiteral,
24};
25use crate::enc::combined_alloc::{alloc_default, allocate};
26use crate::enc::floatX;
27
28pub fn BrotliInitDistanceParams(params: &mut BrotliEncoderParams, npostfix: u32, ndirect: u32) {
29 let dist_params = &mut params.dist;
30 let mut alphabet_size;
31 let mut max_distance;
32
33 dist_params.distance_postfix_bits = npostfix;
34 dist_params.num_direct_distance_codes = ndirect;
35
36 alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
37 max_distance =
38 ndirect + (1u32 << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) - (1u32 << (npostfix + 2));
39
40 if (params.large_window) {
41 let bound: [u32; BROTLI_MAX_NPOSTFIX + 1] = [0, 4, 12, 28];
42 let postfix = 1u32 << npostfix;
43 alphabet_size =
44 BROTLI_DISTANCE_ALPHABET_SIZE(npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
45 if (ndirect < bound[npostfix as usize]) {
49 max_distance =
50 BROTLI_MAX_ALLOWED_DISTANCE as u32 - (bound[npostfix as usize] - ndirect);
51 } else if (ndirect >= bound[npostfix as usize] + postfix) {
52 max_distance = (3u32 << 29) - 4 + (ndirect - bound[npostfix as usize]);
53 } else {
54 max_distance = BROTLI_MAX_ALLOWED_DISTANCE as u32;
55 }
56 }
57
58 dist_params.alphabet_size = alphabet_size;
59 dist_params.max_distance = max_distance as usize;
60}
61
62fn RecomputeDistancePrefixes(
63 cmds: &mut [Command],
64 num_commands: usize,
65 orig_params: &BrotliDistanceParams,
66 new_params: &BrotliDistanceParams,
67) {
68 if orig_params.distance_postfix_bits == new_params.distance_postfix_bits
69 && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes
70 {
71 return;
72 }
73
74 for cmd in cmds.split_at_mut(num_commands).0.iter_mut() {
75 if (cmd.copy_len() != 0 && cmd.cmd_prefix_ >= 128) {
76 let ret = cmd.restore_distance_code(orig_params);
77 PrefixEncodeCopyDistance(
78 ret as usize,
79 new_params.num_direct_distance_codes as usize,
80 new_params.distance_postfix_bits as u64,
81 &mut cmd.dist_prefix_,
82 &mut cmd.dist_extra_,
83 );
84 }
85 }
86}
87
88fn ComputeDistanceCost(
89 cmds: &[Command],
90 num_commands: usize,
91 orig_params: &BrotliDistanceParams,
92 new_params: &BrotliDistanceParams,
93 scratch: &mut <HistogramDistance as CostAccessors>::i32vec,
94 cost: &mut f64,
95) -> bool {
96 let mut equal_params = false;
97 let mut dist_prefix: u16 = 0;
98 let mut dist_extra: u32 = 0;
99 let mut extra_bits: f64 = 0.0;
100 let mut histo = HistogramDistance::default();
101
102 if (orig_params.distance_postfix_bits == new_params.distance_postfix_bits
103 && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes)
104 {
105 equal_params = true;
106 }
107 for cmd in cmds.split_at(num_commands).0 {
108 if cmd.copy_len() != 0 && cmd.cmd_prefix_ >= 128 {
109 if equal_params {
110 dist_prefix = cmd.dist_prefix_;
111 } else {
112 let distance = cmd.restore_distance_code(orig_params);
113 if distance > new_params.max_distance as u32 {
114 return false;
115 }
116 PrefixEncodeCopyDistance(
117 distance as usize,
118 new_params.num_direct_distance_codes as usize,
119 new_params.distance_postfix_bits as u64,
120 &mut dist_prefix,
121 &mut dist_extra,
122 );
123 }
124 HistogramAddItem(&mut histo, (dist_prefix & 0x03ff) as usize);
125 extra_bits += (dist_prefix >> 10) as f64;
126 }
127 }
128
129 *cost = BrotliPopulationCost(&histo, scratch) as f64 + extra_bits;
130 true
131}
132
133#[cfg_attr(feature = "hotpath", hotpath::measure)]
134pub fn BrotliBuildMetaBlock<Alloc: BrotliAlloc>(
135 alloc: &mut Alloc,
136 ringbuffer: &[u8],
137 pos: usize,
138 mask: usize,
139 params: &mut BrotliEncoderParams,
140 prev_byte: u8,
141 prev_byte2: u8,
142 cmds: &mut [Command],
143 num_commands: usize,
144 literal_context_mode: ContextType,
145 lit_scratch_space: &mut <HistogramLiteral as CostAccessors>::i32vec,
146 cmd_scratch_space: &mut <HistogramCommand as CostAccessors>::i32vec,
147 dst_scratch_space: &mut <HistogramDistance as CostAccessors>::i32vec,
148 mb: &mut MetaBlockSplit<Alloc>,
149) {
150 static kMaxNumberOfHistograms: usize = 256usize;
151 let mut distance_histograms: <Alloc as Allocator<HistogramDistance>>::AllocatedMemory;
152 let mut literal_histograms: <Alloc as Allocator<HistogramLiteral>>::AllocatedMemory;
153 let mut literal_context_modes = alloc_default::<ContextType, Alloc>();
154
155 let mut i: usize;
156 let mut literal_context_multiplier: usize = 1;
157 let mut ndirect_msb: u32 = 0;
158 let mut check_orig = true;
159 if !params.avoid_distance_prefix_search {
160 let mut best_dist_cost: f64 = 1e99;
161 let orig_params = params.clone();
162 let mut new_params = params.clone();
163
164 for npostfix in 0..(BROTLI_MAX_NPOSTFIX + 1) {
165 while ndirect_msb < 16 {
166 let ndirect = ndirect_msb << npostfix;
167
168 let mut dist_cost: f64 = 0.0;
169 BrotliInitDistanceParams(&mut new_params, npostfix as u32, ndirect);
170 if npostfix as u32 == orig_params.dist.distance_postfix_bits
171 && ndirect == orig_params.dist.num_direct_distance_codes
172 {
173 check_orig = false;
174 }
175 let skip: bool = !ComputeDistanceCost(
176 cmds,
177 num_commands,
178 &orig_params.dist,
179 &new_params.dist,
180 dst_scratch_space,
181 &mut dist_cost,
182 );
183 if skip || (dist_cost > best_dist_cost) {
184 break;
185 }
186 best_dist_cost = dist_cost;
187 params.dist = new_params.dist;
188 ndirect_msb += 1;
189 }
190 ndirect_msb = ndirect_msb.saturating_sub(1);
191 ndirect_msb /= 2;
192 }
193 if check_orig {
194 let mut dist_cost: f64 = 0.0;
195 ComputeDistanceCost(
196 cmds,
197 num_commands,
198 &orig_params.dist,
199 &orig_params.dist,
200 dst_scratch_space,
201 &mut dist_cost,
202 );
203 if dist_cost < best_dist_cost {
204 params.dist = orig_params.dist;
206 }
207 }
208 RecomputeDistancePrefixes(cmds, num_commands, &orig_params.dist, ¶ms.dist);
209 }
210 BrotliSplitBlock(
211 alloc,
212 cmds,
213 num_commands,
214 ringbuffer,
215 pos,
216 mask,
217 params,
218 lit_scratch_space,
219 cmd_scratch_space,
220 dst_scratch_space,
221 &mut mb.literal_split,
222 &mut mb.command_split,
223 &mut mb.distance_split,
224 );
225 if params.disable_literal_context_modeling == 0 {
226 literal_context_multiplier = (1i32 << 6) as usize;
227 literal_context_modes = allocate::<ContextType, _>(alloc, mb.literal_split.num_types);
228 for item in literal_context_modes.slice_mut().iter_mut() {
229 *item = literal_context_mode;
230 }
231 }
232 let literal_histograms_size: usize = mb
233 .literal_split
234 .num_types
235 .wrapping_mul(literal_context_multiplier);
236 literal_histograms = allocate::<HistogramLiteral, _>(alloc, literal_histograms_size);
237 let distance_histograms_size: usize = mb.distance_split.num_types << 2;
238 distance_histograms = allocate::<HistogramDistance, _>(alloc, distance_histograms_size);
239 mb.command_histograms_size = mb.command_split.num_types;
240 mb.command_histograms = allocate::<HistogramCommand, _>(alloc, mb.command_histograms_size);
241 BrotliBuildHistogramsWithContext(
242 cmds,
243 num_commands,
244 &mut mb.literal_split,
245 &mut mb.command_split,
246 &mut mb.distance_split,
247 ringbuffer,
248 pos,
249 mask,
250 prev_byte,
251 prev_byte2,
252 literal_context_modes.slice(),
253 literal_histograms.slice_mut(),
254 mb.command_histograms.slice_mut(),
255 distance_histograms.slice_mut(),
256 );
257 <Alloc as Allocator<ContextType>>::free_cell(alloc, literal_context_modes);
258 mb.literal_context_map_size = mb.literal_split.num_types << 6;
259 mb.literal_context_map = allocate::<u32, _>(alloc, mb.literal_context_map_size);
260 mb.literal_histograms_size = mb.literal_context_map_size;
261 mb.literal_histograms = allocate::<HistogramLiteral, _>(alloc, mb.literal_histograms_size);
262 BrotliClusterHistograms(
263 alloc,
264 literal_histograms.slice(),
265 literal_histograms_size,
266 kMaxNumberOfHistograms,
267 lit_scratch_space,
268 mb.literal_histograms.slice_mut(),
269 &mut mb.literal_histograms_size,
270 mb.literal_context_map.slice_mut(),
271 );
272 <Alloc as Allocator<HistogramLiteral>>::free_cell(alloc, literal_histograms);
273 if params.disable_literal_context_modeling != 0 {
274 i = mb.literal_split.num_types;
275 while i != 0usize {
276 let mut j: usize = 0usize;
277 i = i.wrapping_sub(1);
278 while j < (1i32 << 6) as usize {
279 {
280 let val = mb.literal_context_map.slice()[i];
281 mb.literal_context_map.slice_mut()[(i << 6).wrapping_add(j)] = val;
282 }
283 j = j.wrapping_add(1);
284 }
285 }
286 }
287 mb.distance_context_map_size = mb.distance_split.num_types << 2;
288 mb.distance_context_map = allocate::<u32, _>(alloc, mb.distance_context_map_size);
289 mb.distance_histograms_size = mb.distance_context_map_size;
290 mb.distance_histograms = allocate::<HistogramDistance, _>(alloc, mb.distance_histograms_size);
291 BrotliClusterHistograms(
292 alloc,
293 distance_histograms.slice(),
294 mb.distance_context_map_size,
295 kMaxNumberOfHistograms,
296 dst_scratch_space,
297 mb.distance_histograms.slice_mut(),
298 &mut mb.distance_histograms_size,
299 mb.distance_context_map.slice_mut(),
300 );
301 <Alloc as Allocator<HistogramDistance>>::free_cell(alloc, distance_histograms);
302}
303
304pub struct BlockSplitter {
311 pub alphabet_size_: usize,
312 pub min_block_size_: usize,
313 pub split_threshold_: floatX,
314 pub num_blocks_: usize,
315 pub target_block_size_: usize,
319 pub block_size_: usize,
320 pub curr_histogram_ix_: usize,
321 pub last_histogram_ix_: [usize; 2],
322 pub last_entropy_: [floatX; 2],
323 pub merge_last_count_: usize,
324}
325
326pub struct ContextBlockSplitter {
327 pub alphabet_size_: usize,
328 pub num_contexts_: usize,
329 pub max_block_types_: usize,
330 pub min_block_size_: usize,
331 pub split_threshold_: floatX,
332 pub num_blocks_: usize,
333 pub target_block_size_: usize,
337 pub block_size_: usize,
338 pub curr_histogram_ix_: usize,
339 pub last_histogram_ix_: [usize; 2],
340 pub last_entropy_: [floatX; 2 * BROTLI_MAX_STATIC_CONTEXTS],
341 pub merge_last_count_: usize,
342}
343
344enum LitBlocks {
345 plain(BlockSplitter), ctx(ContextBlockSplitter), }
348
349fn InitBlockSplitter<
387 HistogramType: SliceWrapper<u32> + SliceWrapperMut<u32> + CostAccessors,
388 Alloc: alloc::Allocator<u8> + alloc::Allocator<u32> + alloc::Allocator<HistogramType>,
389>(
390 alloc: &mut Alloc,
391 alphabet_size: usize,
392 min_block_size: usize,
393 split_threshold: floatX,
394 num_symbols: usize,
395 split: &mut BlockSplit<Alloc>,
396 histograms: &mut <Alloc as Allocator<HistogramType>>::AllocatedMemory,
397 histograms_size: &mut usize,
398) -> BlockSplitter {
399 let max_num_blocks: usize = num_symbols.wrapping_div(min_block_size).wrapping_add(1);
400 let max_num_types: usize = min(max_num_blocks, (256i32 + 1i32) as usize);
401 let mut xself = BlockSplitter {
402 last_entropy_: [0.0; 2],
403 alphabet_size_: alphabet_size,
404 min_block_size_: min_block_size,
405 split_threshold_: split_threshold,
406 num_blocks_: 0usize,
407 target_block_size_: min_block_size,
410 block_size_: 0usize,
411 curr_histogram_ix_: 0usize,
412 merge_last_count_: 0usize,
413 last_histogram_ix_: [0; 2],
414 };
415 {
416 if split.types.slice().len() < max_num_blocks {
417 let mut _new_size: usize = if split.types.slice().is_empty() {
418 max_num_blocks
419 } else {
420 split.types.slice().len()
421 };
422 let mut new_array: <Alloc as Allocator<u8>>::AllocatedMemory;
423 while _new_size < max_num_blocks {
424 _new_size = _new_size.wrapping_mul(2);
425 }
426 new_array = allocate::<u8, _>(alloc, _new_size);
427 if (!split.types.slice().is_empty()) {
428 new_array.slice_mut()[..split.types.slice().len()]
429 .copy_from_slice(split.types.slice());
430 }
431 <Alloc as Allocator<u8>>::free_cell(
432 alloc,
433 core::mem::replace(&mut split.types, new_array),
434 );
435 }
436 }
437 {
438 if split.lengths.slice().len() < max_num_blocks {
439 let mut _new_size: usize = if split.lengths.slice().is_empty() {
440 max_num_blocks
441 } else {
442 split.lengths.slice().len()
443 };
444 while _new_size < max_num_blocks {
445 _new_size = _new_size.wrapping_mul(2);
446 }
447 let mut new_array = allocate::<u32, _>(alloc, _new_size);
448 new_array.slice_mut()[..split.lengths.slice().len()]
449 .copy_from_slice(split.lengths.slice());
450 <Alloc as Allocator<u32>>::free_cell(
451 alloc,
452 core::mem::replace(&mut split.lengths, new_array),
453 );
454 }
455 }
456 split.num_blocks = max_num_blocks;
457 *histograms_size = max_num_types;
458 let hlocal = allocate::<HistogramType, _>(alloc, *histograms_size);
459 <Alloc as Allocator<HistogramType>>::free_cell(
460 alloc,
461 core::mem::replace(&mut *histograms, hlocal),
462 );
463 HistogramClear(&mut histograms.slice_mut()[0]);
464 xself.last_histogram_ix_[0] = 0;
465 xself.last_histogram_ix_[1] = 0;
466 xself
467}
468fn InitContextBlockSplitter<
469 Alloc: alloc::Allocator<u8> + alloc::Allocator<u32> + alloc::Allocator<HistogramLiteral>,
470>(
471 alloc: &mut Alloc,
472 alphabet_size: usize,
473 num_contexts: usize,
474 min_block_size: usize,
475 split_threshold: floatX,
476 num_symbols: usize,
477 split: &mut BlockSplit<Alloc>,
478 histograms: &mut <Alloc as Allocator<HistogramLiteral>>::AllocatedMemory,
479 histograms_size: &mut usize,
480) -> ContextBlockSplitter {
481 let max_num_blocks: usize = num_symbols.wrapping_div(min_block_size).wrapping_add(1);
482
483 assert!(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
484 let mut xself = ContextBlockSplitter {
485 alphabet_size_: alphabet_size,
486 num_contexts_: num_contexts,
487 max_block_types_: (256usize).wrapping_div(num_contexts),
488 min_block_size_: min_block_size,
489 split_threshold_: split_threshold,
490 num_blocks_: 0usize,
491 target_block_size_: min_block_size,
493 block_size_: 0usize,
494 curr_histogram_ix_: 0usize,
495 merge_last_count_: 0usize,
496 last_histogram_ix_: [0; 2],
497 last_entropy_: [0.0; 2 * BROTLI_MAX_STATIC_CONTEXTS],
498 };
499 let max_num_types: usize = min(max_num_blocks, xself.max_block_types_.wrapping_add(1));
500 {
501 if split.types.slice().len() < max_num_blocks {
502 let mut _new_size: usize = if split.types.slice().is_empty() {
503 max_num_blocks
504 } else {
505 split.types.slice().len()
506 };
507 while _new_size < max_num_blocks {
508 _new_size = _new_size.wrapping_mul(2);
509 }
510 let mut new_array = allocate::<u8, _>(alloc, _new_size);
511 if (!split.types.slice().is_empty()) {
512 new_array.slice_mut()[..split.types.slice().len()]
513 .copy_from_slice(split.types.slice());
514 }
515 <Alloc as Allocator<u8>>::free_cell(
516 alloc,
517 core::mem::replace(&mut split.types, new_array),
518 );
519 }
520 }
521 {
522 if split.lengths.slice().len() < max_num_blocks {
523 let mut _new_size: usize = if split.lengths.slice().is_empty() {
524 max_num_blocks
525 } else {
526 split.lengths.slice().len()
527 };
528 while _new_size < max_num_blocks {
529 _new_size = _new_size.wrapping_mul(2);
530 }
531 let mut new_array = allocate::<u32, _>(alloc, _new_size);
532 if (!split.lengths.slice().is_empty()) {
533 new_array.slice_mut()[..split.lengths.slice().len()]
534 .copy_from_slice(split.lengths.slice());
535 }
536 <Alloc as Allocator<u32>>::free_cell(
537 alloc,
538 core::mem::replace(&mut split.lengths, new_array),
539 );
540 }
541 }
542 split.num_blocks = max_num_blocks;
543 *histograms_size = max_num_types.wrapping_mul(num_contexts);
544 *histograms = allocate::<HistogramLiteral, _>(alloc, *histograms_size);
545 ClearHistograms(&mut histograms.slice_mut()[0..], num_contexts);
547 xself.last_histogram_ix_[0] = 0;
548 xself.last_histogram_ix_[1] = 0;
549 xself
550}
551
552fn BlockSplitterFinishBlock<
553 HistogramType: SliceWrapper<u32> + SliceWrapperMut<u32> + CostAccessors + Clone,
554 Alloc: alloc::Allocator<u8> + alloc::Allocator<u32>,
555>(
556 xself: &mut BlockSplitter,
557 split: &mut BlockSplit<Alloc>,
558 histograms: &mut [HistogramType],
559 histograms_size: &mut usize,
560 is_final: bool,
561) {
562 xself.block_size_ = max(xself.block_size_, xself.min_block_size_);
563 if xself.num_blocks_ == 0usize {
564 split.lengths.slice_mut()[0] = xself.block_size_ as u32;
565 split.types.slice_mut()[0] = 0u8;
566 xself.last_entropy_[0] = BitsEntropy((histograms[0]).slice(), xself.alphabet_size_);
567 xself.last_entropy_[1] = xself.last_entropy_[0];
568 xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
569 split.num_types = split.num_types.wrapping_add(1);
570 xself.curr_histogram_ix_ = xself.curr_histogram_ix_.wrapping_add(1);
571 if xself.curr_histogram_ix_ < *histograms_size {
572 HistogramClear(&mut histograms[xself.curr_histogram_ix_]);
573 }
574 xself.block_size_ = 0usize;
575 } else if xself.block_size_ > 0usize {
576 let entropy = BitsEntropy(
577 (histograms[xself.curr_histogram_ix_]).slice(),
578 xself.alphabet_size_,
579 );
580 let mut combined_histo: [HistogramType; 2] = [
581 histograms[xself.curr_histogram_ix_].clone(),
582 histograms[xself.curr_histogram_ix_].clone(),
583 ];
584
585 let mut combined_entropy: [floatX; 2] = [0.0, 0.0];
586 let mut diff: [floatX; 2] = [0.0, 0.0];
587 for j in 0..2 {
588 let last_histogram_ix: usize = xself.last_histogram_ix_[j];
589 HistogramAddHistogram(&mut combined_histo[j], &histograms[last_histogram_ix]);
590 combined_entropy[j] = BitsEntropy(
591 &mut combined_histo[j].slice_mut()[0..],
592 xself.alphabet_size_,
593 );
594 diff[j] = combined_entropy[j] - entropy - xself.last_entropy_[j];
595 }
596 if split.num_types < 256usize
597 && (diff[0] > xself.split_threshold_)
598 && (diff[1] > xself.split_threshold_)
599 {
600 split.lengths.slice_mut()[xself.num_blocks_] = xself.block_size_ as u32;
601 split.types.slice_mut()[xself.num_blocks_] = split.num_types as u8;
602 xself.last_histogram_ix_[1] = xself.last_histogram_ix_[0];
603 xself.last_histogram_ix_[0] = split.num_types as u8 as usize;
604 xself.last_entropy_[1] = xself.last_entropy_[0];
605 xself.last_entropy_[0] = entropy;
606 xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
607 split.num_types = split.num_types.wrapping_add(1);
608 xself.curr_histogram_ix_ = xself.curr_histogram_ix_.wrapping_add(1);
609 if xself.curr_histogram_ix_ < *histograms_size {
610 HistogramClear(&mut histograms[xself.curr_histogram_ix_]);
611 }
612 xself.block_size_ = 0usize;
613 xself.merge_last_count_ = 0usize;
614 xself.target_block_size_ = xself.min_block_size_;
615 } else if diff[1] < diff[0] - 20.0 {
616 split.lengths.slice_mut()[xself.num_blocks_] = xself.block_size_ as u32;
617 split.types.slice_mut()[xself.num_blocks_] =
618 split.types.slice()[xself.num_blocks_.wrapping_sub(2)]; {
620 xself.last_histogram_ix_.swap(0, 1);
621 }
622 histograms[xself.last_histogram_ix_[0]] = combined_histo[1].clone();
623 xself.last_entropy_[1] = xself.last_entropy_[0];
624 xself.last_entropy_[0] = combined_entropy[1];
625 xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
626 xself.block_size_ = 0usize;
627 HistogramClear(&mut histograms[xself.curr_histogram_ix_]);
628 xself.merge_last_count_ = 0usize;
629 xself.target_block_size_ = xself.min_block_size_;
630 } else {
631 {
632 let _rhs = xself.block_size_ as u32;
633 let _lhs = &mut split.lengths.slice_mut()[xself.num_blocks_.wrapping_sub(1)];
634 *_lhs = (*_lhs).wrapping_add(_rhs);
635 }
636 histograms[xself.last_histogram_ix_[0]] = combined_histo[0].clone();
637 xself.last_entropy_[0] = combined_entropy[0];
638 if split.num_types == 1 {
639 xself.last_entropy_[1] = xself.last_entropy_[0];
640 }
641 xself.block_size_ = 0usize;
642 HistogramClear(&mut histograms[xself.curr_histogram_ix_]);
643 if {
644 xself.merge_last_count_ = xself.merge_last_count_.wrapping_add(1);
645 xself.merge_last_count_
646 } > 1
647 {
648 xself.target_block_size_ =
649 xself.target_block_size_.wrapping_add(xself.min_block_size_);
650 }
651 }
652 }
653 if is_final {
654 *histograms_size = split.num_types;
655 split.num_blocks = xself.num_blocks_;
656 }
657}
658const BROTLI_MAX_STATIC_CONTEXTS: usize = 13;
659
660fn ContextBlockSplitterFinishBlock<
661 Alloc: alloc::Allocator<u8> + alloc::Allocator<u32> + alloc::Allocator<HistogramLiteral>,
662 AllocHL: alloc::Allocator<HistogramLiteral>,
663>(
664 xself: &mut ContextBlockSplitter,
665 m: &mut AllocHL,
666 split: &mut BlockSplit<Alloc>,
667 histograms: &mut [HistogramLiteral],
668 histograms_size: &mut usize,
669 is_final: bool,
670) {
671 let num_contexts: usize = xself.num_contexts_;
672 if xself.block_size_ < xself.min_block_size_ {
673 xself.block_size_ = xself.min_block_size_;
674 }
675 if xself.num_blocks_ == 0usize {
676 split.lengths.slice_mut()[0] = xself.block_size_ as u32;
677 split.types.slice_mut()[0] = 0u8;
678 for i in 0usize..num_contexts {
679 xself.last_entropy_[i] = BitsEntropy((histograms[i]).slice(), xself.alphabet_size_);
680 xself.last_entropy_[num_contexts.wrapping_add(i)] = xself.last_entropy_[i];
681 }
682 xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
683 split.num_types = split.num_types.wrapping_add(1);
684 xself.curr_histogram_ix_ = xself.curr_histogram_ix_.wrapping_add(num_contexts);
685 if xself.curr_histogram_ix_ < *histograms_size {
686 ClearHistograms(
687 &mut histograms[xself.curr_histogram_ix_..],
688 xself.num_contexts_,
689 );
690 }
691 xself.block_size_ = 0usize;
692 } else if xself.block_size_ > 0usize {
693 let mut entropy = [0.0; BROTLI_MAX_STATIC_CONTEXTS];
694 let mut combined_histo = m.alloc_cell(2 * num_contexts);
695 let mut combined_entropy = [0.0; 2 * BROTLI_MAX_STATIC_CONTEXTS];
696 let mut diff = [0.0; 2];
697 for i in 0usize..num_contexts {
698 let curr_histo_ix: usize = xself.curr_histogram_ix_.wrapping_add(i);
699 let mut j: usize;
700 entropy[i] = BitsEntropy((histograms[curr_histo_ix]).slice(), xself.alphabet_size_);
701 j = 0usize;
702 while j < 2usize {
703 {
704 let jx: usize = j.wrapping_mul(num_contexts).wrapping_add(i);
705 let last_histogram_ix: usize = xself.last_histogram_ix_[j].wrapping_add(i);
706 combined_histo.slice_mut()[jx] = histograms[curr_histo_ix].clone();
707 HistogramAddHistogram(
708 &mut combined_histo.slice_mut()[jx],
709 &mut histograms[last_histogram_ix],
710 );
711 combined_entropy[jx] =
712 BitsEntropy(combined_histo.slice()[jx].slice(), xself.alphabet_size_);
713 diff[j] += combined_entropy[jx] - entropy[i] - xself.last_entropy_[jx];
714 }
715 j = j.wrapping_add(1);
716 }
717 }
718 if split.num_types < xself.max_block_types_
719 && (diff[0] > xself.split_threshold_)
720 && (diff[1] > xself.split_threshold_)
721 {
722 split.lengths.slice_mut()[xself.num_blocks_] = xself.block_size_ as u32;
723 split.types.slice_mut()[xself.num_blocks_] = split.num_types as u8;
724 xself.last_histogram_ix_[1] = xself.last_histogram_ix_[0];
725 xself.last_histogram_ix_[0] = split.num_types.wrapping_mul(num_contexts);
726 for i in 0usize..num_contexts {
727 xself.last_entropy_[num_contexts.wrapping_add(i)] = xself.last_entropy_[i];
728 xself.last_entropy_[i] = entropy[i];
729 }
730 xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
731 split.num_types = split.num_types.wrapping_add(1);
732 xself.curr_histogram_ix_ = xself.curr_histogram_ix_.wrapping_add(num_contexts);
733 if xself.curr_histogram_ix_ < *histograms_size {
734 ClearHistograms(
735 &mut histograms[xself.curr_histogram_ix_..],
736 xself.num_contexts_,
737 );
738 }
739 xself.block_size_ = 0usize;
740 xself.merge_last_count_ = 0usize;
741 xself.target_block_size_ = xself.min_block_size_;
742 } else if diff[1] < diff[0] - 20.0 {
743 split.lengths.slice_mut()[xself.num_blocks_] = xself.block_size_ as u32;
744 let nbm2 = split.types.slice()[xself.num_blocks_.wrapping_sub(2)];
745 split.types.slice_mut()[xself.num_blocks_] = nbm2;
746
747 {
748 xself.last_histogram_ix_.swap(0, 1);
749 }
750 for i in 0usize..num_contexts {
751 histograms[xself.last_histogram_ix_[0].wrapping_add(i)] =
752 combined_histo.slice()[num_contexts.wrapping_add(i)].clone();
753 xself.last_entropy_[num_contexts.wrapping_add(i)] = xself.last_entropy_[i];
754 xself.last_entropy_[i] = combined_entropy[num_contexts.wrapping_add(i)];
755 HistogramClear(&mut histograms[xself.curr_histogram_ix_.wrapping_add(i)]);
756 }
757 xself.num_blocks_ = xself.num_blocks_.wrapping_add(1);
758 xself.block_size_ = 0usize;
759 xself.merge_last_count_ = 0usize;
760 xself.target_block_size_ = xself.min_block_size_;
761 } else {
762 {
763 let _rhs = xself.block_size_ as u32;
764 let _lhs = &mut split.lengths.slice_mut()[xself.num_blocks_.wrapping_sub(1)];
765 let old_split_length = *_lhs;
766 *_lhs = old_split_length.wrapping_add(_rhs);
767 }
768 for i in 0usize..num_contexts {
769 histograms[xself.last_histogram_ix_[0].wrapping_add(i)] =
770 combined_histo.slice()[i].clone();
771 xself.last_entropy_[i] = combined_entropy[i];
772 if split.num_types == 1 {
773 xself.last_entropy_[num_contexts.wrapping_add(i)] = xself.last_entropy_[i];
774 }
775 HistogramClear(&mut histograms[xself.curr_histogram_ix_.wrapping_add(i)]);
776 }
777 xself.block_size_ = 0usize;
778 if {
779 xself.merge_last_count_ = xself.merge_last_count_.wrapping_add(1);
780 xself.merge_last_count_
781 } > 1
782 {
783 xself.target_block_size_ =
784 xself.target_block_size_.wrapping_add(xself.min_block_size_);
785 }
786 }
787 m.free_cell(combined_histo);
788 }
789 if is_final {
790 *histograms_size = split.num_types.wrapping_mul(num_contexts);
791 split.num_blocks = xself.num_blocks_;
792 }
793}
794
795fn BlockSplitterAddSymbol<
796 HistogramType: SliceWrapper<u32> + SliceWrapperMut<u32> + CostAccessors + Clone,
797 Alloc: alloc::Allocator<u8> + alloc::Allocator<u32>,
798>(
799 xself: &mut BlockSplitter,
800 split: &mut BlockSplit<Alloc>,
801 histograms: &mut [HistogramType],
802 histograms_size: &mut usize,
803 symbol: usize,
804) {
805 HistogramAddItem(&mut histograms[xself.curr_histogram_ix_], symbol);
806 xself.block_size_ = xself.block_size_.wrapping_add(1);
807 if xself.block_size_ == xself.target_block_size_ {
808 BlockSplitterFinishBlock(xself, split, histograms, histograms_size, false);
809 }
810}
811
812fn ContextBlockSplitterAddSymbol<
813 Alloc: alloc::Allocator<u8> + alloc::Allocator<u32> + alloc::Allocator<HistogramLiteral>,
814>(
815 xself: &mut ContextBlockSplitter,
816 m: &mut Alloc,
817 split: &mut BlockSplit<Alloc>,
818 histograms: &mut [HistogramLiteral],
819 histograms_size: &mut usize,
820 symbol: usize,
821 context: usize,
822) {
823 HistogramAddItem(
824 &mut histograms[xself.curr_histogram_ix_.wrapping_add(context)],
825 symbol,
826 );
827 xself.block_size_ = xself.block_size_.wrapping_add(1);
828 if xself.block_size_ == xself.target_block_size_ {
829 ContextBlockSplitterFinishBlock(xself, m, split, histograms, histograms_size, false);
830 }
831}
832
833fn MapStaticContexts<
834 Alloc: alloc::Allocator<u8>
835 + alloc::Allocator<u32>
836 + alloc::Allocator<HistogramLiteral>
837 + alloc::Allocator<HistogramCommand>
838 + alloc::Allocator<HistogramDistance>,
839>(
840 m32: &mut Alloc,
841 num_contexts: usize,
842 static_context_map: &[u32],
843 mb: &mut MetaBlockSplit<Alloc>,
844) {
845 mb.literal_context_map_size = mb.literal_split.num_types << 6;
846 let new_literal_context_map = allocate::<u32, _>(m32, mb.literal_context_map_size);
847 <Alloc as Allocator<u32>>::free_cell(
848 m32,
849 core::mem::replace(&mut mb.literal_context_map, new_literal_context_map),
850 );
851 for i in 0usize..mb.literal_split.num_types {
852 let offset: u32 = i.wrapping_mul(num_contexts) as u32;
853 for j in 0usize..(1u32 << 6) as usize {
854 mb.literal_context_map.slice_mut()[(i << 6).wrapping_add(j)] =
855 offset.wrapping_add(static_context_map[j]);
856 }
857 }
858}
859pub fn BrotliBuildMetaBlockGreedyInternal<
860 Alloc: alloc::Allocator<u8>
861 + alloc::Allocator<u32>
862 + alloc::Allocator<HistogramLiteral>
863 + alloc::Allocator<HistogramCommand>
864 + alloc::Allocator<HistogramDistance>,
865>(
866 alloc: &mut Alloc,
867 ringbuffer: &[u8],
868 mut pos: usize,
869 mask: usize,
870 mut prev_byte: u8,
871 mut prev_byte2: u8,
872 literal_context_mode: ContextType,
873 num_contexts: usize,
874 static_context_map: &[u32],
875 commands: &[Command],
876 n_commands: usize,
877 mb: &mut MetaBlockSplit<Alloc>,
878) {
879 let mut lit_blocks: LitBlocks;
880 let mut cmd_blocks: BlockSplitter;
881 let mut dist_blocks: BlockSplitter;
882 let mut num_literals: usize = 0usize;
883 for i in 0usize..n_commands {
884 num_literals = num_literals.wrapping_add((commands[i]).insert_len_ as usize);
885 }
886 lit_blocks = if num_contexts == 1 {
887 LitBlocks::plain(InitBlockSplitter::<HistogramLiteral, Alloc>(
888 alloc,
889 256usize,
890 512usize,
891 400.0,
892 num_literals,
893 &mut mb.literal_split,
894 &mut mb.literal_histograms,
895 &mut mb.literal_histograms_size,
896 ))
897 } else {
898 LitBlocks::ctx(InitContextBlockSplitter::<Alloc>(
899 alloc,
900 256usize,
901 num_contexts,
902 512usize,
903 400.0,
904 num_literals,
905 &mut mb.literal_split,
906 &mut mb.literal_histograms,
907 &mut mb.literal_histograms_size,
908 ))
909 };
910 cmd_blocks = InitBlockSplitter::<HistogramCommand, Alloc>(
911 alloc,
912 704usize,
913 1024usize,
914 500.0,
915 n_commands,
916 &mut mb.command_split,
917 &mut mb.command_histograms,
918 &mut mb.command_histograms_size,
919 );
920 dist_blocks = InitBlockSplitter::<HistogramDistance, Alloc>(
921 alloc,
922 64usize,
923 512usize,
924 100.0,
925 n_commands,
926 &mut mb.distance_split,
927 &mut mb.distance_histograms,
928 &mut mb.distance_histograms_size,
929 );
930
931 for i in 0usize..n_commands {
932 let cmd: Command = commands[i];
933 let mut j: usize;
934 BlockSplitterAddSymbol(
935 &mut cmd_blocks,
936 &mut mb.command_split,
937 mb.command_histograms.slice_mut(),
938 &mut mb.command_histograms_size,
939 cmd.cmd_prefix_ as usize,
940 );
941 j = cmd.insert_len_ as usize;
942 while j != 0usize {
943 {
944 let literal: u8 = ringbuffer[(pos & mask)];
945 match (&mut lit_blocks) {
946 &mut LitBlocks::plain(ref mut lit_blocks_plain) => BlockSplitterAddSymbol(
947 lit_blocks_plain,
948 &mut mb.literal_split,
949 mb.literal_histograms.slice_mut(),
950 &mut mb.literal_histograms_size,
951 literal as usize,
952 ),
953 &mut LitBlocks::ctx(ref mut lit_blocks_ctx) => {
954 let context: usize =
955 Context(prev_byte, prev_byte2, literal_context_mode) as usize;
956 ContextBlockSplitterAddSymbol(
957 lit_blocks_ctx,
958 alloc,
959 &mut mb.literal_split,
960 mb.literal_histograms.slice_mut(),
961 &mut mb.literal_histograms_size,
962 literal as usize,
963 static_context_map[(context as usize)] as usize,
964 );
965 }
966 }
967 prev_byte2 = prev_byte;
968 prev_byte = literal;
969 pos = pos.wrapping_add(1);
970 }
971 j = j.wrapping_sub(1);
972 }
973 pos = pos.wrapping_add(cmd.copy_len() as usize);
974 if cmd.copy_len() != 0 {
975 prev_byte2 = ringbuffer[(pos.wrapping_sub(2) & mask)];
976 prev_byte = ringbuffer[(pos.wrapping_sub(1) & mask)];
977 if cmd.cmd_prefix_ as i32 >= 128i32 {
978 BlockSplitterAddSymbol(
979 &mut dist_blocks,
980 &mut mb.distance_split,
981 mb.distance_histograms.slice_mut(),
982 &mut mb.distance_histograms_size,
983 cmd.dist_prefix_ as usize & 0x3ff,
984 );
985 }
986 }
987 }
988 match (&mut lit_blocks) {
989 &mut LitBlocks::plain(ref mut lit_blocks_plain) => BlockSplitterFinishBlock(
990 lit_blocks_plain,
991 &mut mb.literal_split,
992 mb.literal_histograms.slice_mut(),
993 &mut mb.literal_histograms_size,
994 true,
995 ),
996 &mut LitBlocks::ctx(ref mut lit_blocks_ctx) => ContextBlockSplitterFinishBlock(
997 lit_blocks_ctx,
998 alloc,
999 &mut mb.literal_split,
1000 mb.literal_histograms.slice_mut(),
1001 &mut mb.literal_histograms_size,
1002 true,
1003 ),
1004 }
1005 BlockSplitterFinishBlock(
1006 &mut cmd_blocks,
1007 &mut mb.command_split,
1008 mb.command_histograms.slice_mut(),
1009 &mut mb.command_histograms_size,
1010 true,
1011 );
1012 BlockSplitterFinishBlock(
1013 &mut dist_blocks,
1014 &mut mb.distance_split,
1015 mb.distance_histograms.slice_mut(),
1016 &mut mb.distance_histograms_size,
1017 true,
1018 );
1019 if num_contexts > 1 {
1020 MapStaticContexts(alloc, num_contexts, static_context_map, mb);
1021 }
1022}
1023#[cfg_attr(feature = "hotpath", hotpath::measure)]
1024pub fn BrotliBuildMetaBlockGreedy<
1025 Alloc: alloc::Allocator<u8>
1026 + alloc::Allocator<u32>
1027 + alloc::Allocator<HistogramLiteral>
1028 + alloc::Allocator<HistogramCommand>
1029 + alloc::Allocator<HistogramDistance>,
1030>(
1031 alloc: &mut Alloc,
1032 ringbuffer: &[u8],
1033 pos: usize,
1034 mask: usize,
1035 prev_byte: u8,
1036 prev_byte2: u8,
1037 literal_context_mode: ContextType,
1038 _literal_context_lut: &[u8],
1039 num_contexts: usize,
1040 static_context_map: &[u32],
1041 commands: &[Command],
1042 n_commands: usize,
1043 mb: &mut MetaBlockSplit<Alloc>,
1044) {
1045 if num_contexts == 1 {
1046 BrotliBuildMetaBlockGreedyInternal(
1047 alloc,
1048 ringbuffer,
1049 pos,
1050 mask,
1051 prev_byte,
1052 prev_byte2,
1053 literal_context_mode,
1054 1,
1055 &[],
1056 commands,
1057 n_commands,
1058 mb,
1059 );
1060 } else {
1061 BrotliBuildMetaBlockGreedyInternal(
1062 alloc,
1063 ringbuffer,
1064 pos,
1065 mask,
1066 prev_byte,
1067 prev_byte2,
1068 literal_context_mode,
1069 num_contexts,
1070 static_context_map,
1071 commands,
1072 n_commands,
1073 mb,
1074 );
1075 }
1076}
1077
1078#[cfg_attr(feature = "hotpath", hotpath::measure)]
1079pub fn BrotliOptimizeHistograms<
1080 Alloc: alloc::Allocator<u8>
1081 + alloc::Allocator<u32>
1082 + alloc::Allocator<HistogramLiteral>
1083 + alloc::Allocator<HistogramCommand>
1084 + alloc::Allocator<HistogramDistance>,
1085>(
1086 num_distance_codes: usize,
1087 mb: &mut MetaBlockSplit<Alloc>,
1088) {
1089 let mut good_for_rle: [u8; 704] = [0; 704];
1090 for i in 0usize..mb.literal_histograms_size {
1091 BrotliOptimizeHuffmanCountsForRle(
1092 256usize,
1093 mb.literal_histograms.slice_mut()[i].slice_mut(),
1094 &mut good_for_rle[..],
1095 );
1096 }
1097 for i in 0usize..mb.command_histograms_size {
1098 BrotliOptimizeHuffmanCountsForRle(
1099 704usize,
1100 mb.command_histograms.slice_mut()[i].slice_mut(),
1101 &mut good_for_rle[..],
1102 );
1103 }
1104 for i in 0usize..mb.distance_histograms_size {
1105 BrotliOptimizeHuffmanCountsForRle(
1106 num_distance_codes,
1107 mb.distance_histograms.slice_mut()[i].slice_mut(),
1108 &mut good_for_rle[..],
1109 );
1110 }
1111}