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