1 /* Copyright 2015 Google Inc. All Rights Reserved.
2
3 Distributed under MIT license.
4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5 */
6
7 /* Algorithms for distributing the literals and commands of a metablock between
8 block types and contexts. */
9
10 #include "./metablock.h"
11
12 #include "../common/constants.h"
13 #include "../common/context.h"
14 #include "../common/platform.h"
15 #include <brotli/types.h>
16 #include "./bit_cost.h"
17 #include "./block_splitter.h"
18 #include "./cluster.h"
19 #include "./entropy_encode.h"
20 #include "./histogram.h"
21 #include "./memory.h"
22 #include "./quality.h"
23
24 #if defined(__cplusplus) || defined(c_plusplus)
25 extern "C" {
26 #endif
27
BrotliInitDistanceParams(BrotliEncoderParams * params,uint32_t npostfix,uint32_t ndirect)28 void BrotliInitDistanceParams(BrotliEncoderParams* params,
29 uint32_t npostfix, uint32_t ndirect) {
30 BrotliDistanceParams* dist_params = ¶ms->dist;
31 uint32_t alphabet_size, 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(
37 npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
38 max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
39 (1U << (npostfix + 2));
40
41 if (params->large_window) {
42 static const uint32_t bound[BROTLI_MAX_NPOSTFIX + 1] = {0, 4, 12, 28};
43 uint32_t postfix = 1U << npostfix;
44 alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(
45 npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
46 /* The maximum distance is set so that no distance symbol used can encode
47 a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all
48 its extra bits set. */
49 if (ndirect < bound[npostfix]) {
50 max_distance = BROTLI_MAX_ALLOWED_DISTANCE - (bound[npostfix] - ndirect);
51 } else if (ndirect >= bound[npostfix] + postfix) {
52 max_distance = (3U << 29) - 4 + (ndirect - bound[npostfix]);
53 } else {
54 max_distance = BROTLI_MAX_ALLOWED_DISTANCE;
55 }
56 }
57
58 dist_params->alphabet_size = alphabet_size;
59 dist_params->max_distance = max_distance;
60 }
61
RecomputeDistancePrefixes(Command * cmds,size_t num_commands,const BrotliDistanceParams * orig_params,const BrotliDistanceParams * new_params)62 static void RecomputeDistancePrefixes(Command* cmds,
63 size_t num_commands,
64 const BrotliDistanceParams* orig_params,
65 const BrotliDistanceParams* new_params) {
66 size_t i;
67
68 if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
69 orig_params->num_direct_distance_codes ==
70 new_params->num_direct_distance_codes) {
71 return;
72 }
73
74 for (i = 0; i < num_commands; ++i) {
75 Command* cmd = &cmds[i];
76 if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
77 PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params),
78 new_params->num_direct_distance_codes,
79 new_params->distance_postfix_bits,
80 &cmd->dist_prefix_,
81 &cmd->dist_extra_);
82 }
83 }
84 }
85
ComputeDistanceCost(const Command * cmds,size_t num_commands,const BrotliDistanceParams * orig_params,const BrotliDistanceParams * new_params,double * cost)86 static BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
87 size_t num_commands,
88 const BrotliDistanceParams* orig_params,
89 const BrotliDistanceParams* new_params,
90 double* cost) {
91 size_t i;
92 BROTLI_BOOL equal_params = BROTLI_FALSE;
93 uint16_t dist_prefix;
94 uint32_t dist_extra;
95 double extra_bits = 0.0;
96 HistogramDistance histo;
97 HistogramClearDistance(&histo);
98
99 if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
100 orig_params->num_direct_distance_codes ==
101 new_params->num_direct_distance_codes) {
102 equal_params = BROTLI_TRUE;
103 }
104
105 for (i = 0; i < num_commands; i++) {
106 const Command* cmd = &cmds[i];
107 if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
108 if (equal_params) {
109 dist_prefix = cmd->dist_prefix_;
110 } else {
111 uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params);
112 if (distance > new_params->max_distance) {
113 return BROTLI_FALSE;
114 }
115 PrefixEncodeCopyDistance(distance,
116 new_params->num_direct_distance_codes,
117 new_params->distance_postfix_bits,
118 &dist_prefix,
119 &dist_extra);
120 }
121 HistogramAddDistance(&histo, dist_prefix & 0x3FF);
122 extra_bits += dist_prefix >> 10;
123 }
124 }
125
126 *cost = BrotliPopulationCostDistance(&histo) + extra_bits;
127 return BROTLI_TRUE;
128 }
129
BrotliBuildMetaBlock(MemoryManager * m,const uint8_t * ringbuffer,const size_t pos,const size_t mask,BrotliEncoderParams * params,uint8_t prev_byte,uint8_t prev_byte2,Command * cmds,size_t num_commands,ContextType literal_context_mode,MetaBlockSplit * mb)130 void BrotliBuildMetaBlock(MemoryManager* m,
131 const uint8_t* ringbuffer,
132 const size_t pos,
133 const size_t mask,
134 BrotliEncoderParams* params,
135 uint8_t prev_byte,
136 uint8_t prev_byte2,
137 Command* cmds,
138 size_t num_commands,
139 ContextType literal_context_mode,
140 MetaBlockSplit* mb) {
141 /* Histogram ids need to fit in one byte. */
142 static const size_t kMaxNumberOfHistograms = 256;
143 HistogramDistance* distance_histograms;
144 HistogramLiteral* literal_histograms;
145 ContextType* literal_context_modes = NULL;
146 size_t literal_histograms_size;
147 size_t distance_histograms_size;
148 size_t i;
149 size_t literal_context_multiplier = 1;
150 uint32_t npostfix;
151 uint32_t ndirect_msb = 0;
152 BROTLI_BOOL check_orig = BROTLI_TRUE;
153 double best_dist_cost = 1e99;
154 BrotliEncoderParams orig_params = *params;
155 BrotliEncoderParams new_params = *params;
156
157 for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) {
158 for (; ndirect_msb < 16; ndirect_msb++) {
159 uint32_t ndirect = ndirect_msb << npostfix;
160 BROTLI_BOOL skip;
161 double dist_cost;
162 BrotliInitDistanceParams(&new_params, npostfix, ndirect);
163 if (npostfix == orig_params.dist.distance_postfix_bits &&
164 ndirect == orig_params.dist.num_direct_distance_codes) {
165 check_orig = BROTLI_FALSE;
166 }
167 skip = !ComputeDistanceCost(
168 cmds, num_commands,
169 &orig_params.dist, &new_params.dist, &dist_cost);
170 if (skip || (dist_cost > best_dist_cost)) {
171 break;
172 }
173 best_dist_cost = dist_cost;
174 params->dist = new_params.dist;
175 }
176 if (ndirect_msb > 0) ndirect_msb--;
177 ndirect_msb /= 2;
178 }
179 if (check_orig) {
180 double dist_cost;
181 ComputeDistanceCost(cmds, num_commands,
182 &orig_params.dist, &orig_params.dist, &dist_cost);
183 if (dist_cost < best_dist_cost) {
184 /* NB: currently unused; uncomment when more param tuning is added. */
185 /* best_dist_cost = dist_cost; */
186 params->dist = orig_params.dist;
187 }
188 }
189 RecomputeDistancePrefixes(cmds, num_commands,
190 &orig_params.dist, ¶ms->dist);
191
192 BrotliSplitBlock(m, cmds, num_commands,
193 ringbuffer, pos, mask, params,
194 &mb->literal_split,
195 &mb->command_split,
196 &mb->distance_split);
197 if (BROTLI_IS_OOM(m)) return;
198
199 if (!params->disable_literal_context_modeling) {
200 literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
201 literal_context_modes =
202 BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
203 if (BROTLI_IS_OOM(m)) return;
204 for (i = 0; i < mb->literal_split.num_types; ++i) {
205 literal_context_modes[i] = literal_context_mode;
206 }
207 }
208
209 literal_histograms_size =
210 mb->literal_split.num_types * literal_context_multiplier;
211 literal_histograms =
212 BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
213 if (BROTLI_IS_OOM(m)) return;
214 ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
215
216 distance_histograms_size =
217 mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
218 distance_histograms =
219 BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
220 if (BROTLI_IS_OOM(m)) return;
221 ClearHistogramsDistance(distance_histograms, distance_histograms_size);
222
223 BROTLI_DCHECK(mb->command_histograms == 0);
224 mb->command_histograms_size = mb->command_split.num_types;
225 mb->command_histograms =
226 BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
227 if (BROTLI_IS_OOM(m)) return;
228 ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
229
230 BrotliBuildHistogramsWithContext(cmds, num_commands,
231 &mb->literal_split, &mb->command_split, &mb->distance_split,
232 ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes,
233 literal_histograms, mb->command_histograms, distance_histograms);
234 BROTLI_FREE(m, literal_context_modes);
235
236 BROTLI_DCHECK(mb->literal_context_map == 0);
237 mb->literal_context_map_size =
238 mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
239 mb->literal_context_map =
240 BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
241 if (BROTLI_IS_OOM(m)) return;
242
243 BROTLI_DCHECK(mb->literal_histograms == 0);
244 mb->literal_histograms_size = mb->literal_context_map_size;
245 mb->literal_histograms =
246 BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
247 if (BROTLI_IS_OOM(m)) return;
248
249 BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
250 kMaxNumberOfHistograms, mb->literal_histograms,
251 &mb->literal_histograms_size, mb->literal_context_map);
252 if (BROTLI_IS_OOM(m)) return;
253 BROTLI_FREE(m, literal_histograms);
254
255 if (params->disable_literal_context_modeling) {
256 /* Distribute assignment to all contexts. */
257 for (i = mb->literal_split.num_types; i != 0;) {
258 size_t j = 0;
259 i--;
260 for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) {
261 mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
262 mb->literal_context_map[i];
263 }
264 }
265 }
266
267 BROTLI_DCHECK(mb->distance_context_map == 0);
268 mb->distance_context_map_size =
269 mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
270 mb->distance_context_map =
271 BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
272 if (BROTLI_IS_OOM(m)) return;
273
274 BROTLI_DCHECK(mb->distance_histograms == 0);
275 mb->distance_histograms_size = mb->distance_context_map_size;
276 mb->distance_histograms =
277 BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
278 if (BROTLI_IS_OOM(m)) return;
279
280 BrotliClusterHistogramsDistance(m, distance_histograms,
281 mb->distance_context_map_size,
282 kMaxNumberOfHistograms,
283 mb->distance_histograms,
284 &mb->distance_histograms_size,
285 mb->distance_context_map);
286 if (BROTLI_IS_OOM(m)) return;
287 BROTLI_FREE(m, distance_histograms);
288 }
289
290 #define FN(X) X ## Literal
291 #include "./metablock_inc.h" /* NOLINT(build/include) */
292 #undef FN
293
294 #define FN(X) X ## Command
295 #include "./metablock_inc.h" /* NOLINT(build/include) */
296 #undef FN
297
298 #define FN(X) X ## Distance
299 #include "./metablock_inc.h" /* NOLINT(build/include) */
300 #undef FN
301
302 #define BROTLI_MAX_STATIC_CONTEXTS 13
303
304 /* Greedy block splitter for one block category (literal, command or distance).
305 Gathers histograms for all context buckets. */
306 typedef struct ContextBlockSplitter {
307 /* Alphabet size of particular block category. */
308 size_t alphabet_size_;
309 size_t num_contexts_;
310 size_t max_block_types_;
311 /* We collect at least this many symbols for each block. */
312 size_t min_block_size_;
313 /* We merge histograms A and B if
314 entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
315 where A is the current histogram and B is the histogram of the last or the
316 second last block type. */
317 double split_threshold_;
318
319 size_t num_blocks_;
320 BlockSplit* split_; /* not owned */
321 HistogramLiteral* histograms_; /* not owned */
322 size_t* histograms_size_; /* not owned */
323
324 /* The number of symbols that we want to collect before deciding on whether
325 or not to merge the block with a previous one or emit a new block. */
326 size_t target_block_size_;
327 /* The number of symbols in the current histogram. */
328 size_t block_size_;
329 /* Offset of the current histogram. */
330 size_t curr_histogram_ix_;
331 /* Offset of the histograms of the previous two block types. */
332 size_t last_histogram_ix_[2];
333 /* Entropy of the previous two block types. */
334 double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
335 /* The number of times we merged the current block with the last one. */
336 size_t merge_last_count_;
337 } ContextBlockSplitter;
338
InitContextBlockSplitter(MemoryManager * m,ContextBlockSplitter * self,size_t alphabet_size,size_t num_contexts,size_t min_block_size,double split_threshold,size_t num_symbols,BlockSplit * split,HistogramLiteral ** histograms,size_t * histograms_size)339 static void InitContextBlockSplitter(
340 MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size,
341 size_t num_contexts, size_t min_block_size, double split_threshold,
342 size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms,
343 size_t* histograms_size) {
344 size_t max_num_blocks = num_symbols / min_block_size + 1;
345 size_t max_num_types;
346 BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
347
348 self->alphabet_size_ = alphabet_size;
349 self->num_contexts_ = num_contexts;
350 self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts;
351 self->min_block_size_ = min_block_size;
352 self->split_threshold_ = split_threshold;
353 self->num_blocks_ = 0;
354 self->split_ = split;
355 self->histograms_size_ = histograms_size;
356 self->target_block_size_ = min_block_size;
357 self->block_size_ = 0;
358 self->curr_histogram_ix_ = 0;
359 self->merge_last_count_ = 0;
360
361 /* We have to allocate one more histogram than the maximum number of block
362 types for the current histogram when the meta-block is too big. */
363 max_num_types =
364 BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1);
365 BROTLI_ENSURE_CAPACITY(m, uint8_t,
366 split->types, split->types_alloc_size, max_num_blocks);
367 BROTLI_ENSURE_CAPACITY(m, uint32_t,
368 split->lengths, split->lengths_alloc_size, max_num_blocks);
369 if (BROTLI_IS_OOM(m)) return;
370 split->num_blocks = max_num_blocks;
371 if (BROTLI_IS_OOM(m)) return;
372 BROTLI_DCHECK(*histograms == 0);
373 *histograms_size = max_num_types * num_contexts;
374 *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
375 self->histograms_ = *histograms;
376 if (BROTLI_IS_OOM(m)) return;
377 /* Clear only current histogram. */
378 ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
379 self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
380 }
381
382 /* Does either of three things:
383 (1) emits the current block with a new block type;
384 (2) emits the current block with the type of the second last block;
385 (3) merges the current block with the last block. */
ContextBlockSplitterFinishBlock(ContextBlockSplitter * self,MemoryManager * m,BROTLI_BOOL is_final)386 static void ContextBlockSplitterFinishBlock(
387 ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
388 BlockSplit* split = self->split_;
389 const size_t num_contexts = self->num_contexts_;
390 double* last_entropy = self->last_entropy_;
391 HistogramLiteral* histograms = self->histograms_;
392
393 if (self->block_size_ < self->min_block_size_) {
394 self->block_size_ = self->min_block_size_;
395 }
396 if (self->num_blocks_ == 0) {
397 size_t i;
398 /* Create first block. */
399 split->lengths[0] = (uint32_t)self->block_size_;
400 split->types[0] = 0;
401
402 for (i = 0; i < num_contexts; ++i) {
403 last_entropy[i] =
404 BitsEntropy(histograms[i].data_, self->alphabet_size_);
405 last_entropy[num_contexts + i] = last_entropy[i];
406 }
407 ++self->num_blocks_;
408 ++split->num_types;
409 self->curr_histogram_ix_ += num_contexts;
410 if (self->curr_histogram_ix_ < *self->histograms_size_) {
411 ClearHistogramsLiteral(
412 &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
413 }
414 self->block_size_ = 0;
415 } else if (self->block_size_ > 0) {
416 /* Try merging the set of histograms for the current block type with the
417 respective set of histograms for the last and second last block types.
418 Decide over the split based on the total reduction of entropy across
419 all contexts. */
420 double entropy[BROTLI_MAX_STATIC_CONTEXTS];
421 HistogramLiteral* combined_histo =
422 BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
423 double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
424 double diff[2] = { 0.0 };
425 size_t i;
426 if (BROTLI_IS_OOM(m)) return;
427 for (i = 0; i < num_contexts; ++i) {
428 size_t curr_histo_ix = self->curr_histogram_ix_ + i;
429 size_t j;
430 entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_,
431 self->alphabet_size_);
432 for (j = 0; j < 2; ++j) {
433 size_t jx = j * num_contexts + i;
434 size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
435 combined_histo[jx] = histograms[curr_histo_ix];
436 HistogramAddHistogramLiteral(&combined_histo[jx],
437 &histograms[last_histogram_ix]);
438 combined_entropy[jx] = BitsEntropy(
439 &combined_histo[jx].data_[0], self->alphabet_size_);
440 diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
441 }
442 }
443
444 if (split->num_types < self->max_block_types_ &&
445 diff[0] > self->split_threshold_ &&
446 diff[1] > self->split_threshold_) {
447 /* Create new block. */
448 split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
449 split->types[self->num_blocks_] = (uint8_t)split->num_types;
450 self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
451 self->last_histogram_ix_[0] = split->num_types * num_contexts;
452 for (i = 0; i < num_contexts; ++i) {
453 last_entropy[num_contexts + i] = last_entropy[i];
454 last_entropy[i] = entropy[i];
455 }
456 ++self->num_blocks_;
457 ++split->num_types;
458 self->curr_histogram_ix_ += num_contexts;
459 if (self->curr_histogram_ix_ < *self->histograms_size_) {
460 ClearHistogramsLiteral(
461 &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
462 }
463 self->block_size_ = 0;
464 self->merge_last_count_ = 0;
465 self->target_block_size_ = self->min_block_size_;
466 } else if (diff[1] < diff[0] - 20.0) {
467 /* Combine this block with second last block. */
468 split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
469 split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
470 BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
471 for (i = 0; i < num_contexts; ++i) {
472 histograms[self->last_histogram_ix_[0] + i] =
473 combined_histo[num_contexts + i];
474 last_entropy[num_contexts + i] = last_entropy[i];
475 last_entropy[i] = combined_entropy[num_contexts + i];
476 HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
477 }
478 ++self->num_blocks_;
479 self->block_size_ = 0;
480 self->merge_last_count_ = 0;
481 self->target_block_size_ = self->min_block_size_;
482 } else {
483 /* Combine this block with last block. */
484 split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
485 for (i = 0; i < num_contexts; ++i) {
486 histograms[self->last_histogram_ix_[0] + i] = combined_histo[i];
487 last_entropy[i] = combined_entropy[i];
488 if (split->num_types == 1) {
489 last_entropy[num_contexts + i] = last_entropy[i];
490 }
491 HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
492 }
493 self->block_size_ = 0;
494 if (++self->merge_last_count_ > 1) {
495 self->target_block_size_ += self->min_block_size_;
496 }
497 }
498 BROTLI_FREE(m, combined_histo);
499 }
500 if (is_final) {
501 *self->histograms_size_ = split->num_types * num_contexts;
502 split->num_blocks = self->num_blocks_;
503 }
504 }
505
506 /* Adds the next symbol to the current block type and context. When the
507 current block reaches the target size, decides on merging the block. */
ContextBlockSplitterAddSymbol(ContextBlockSplitter * self,MemoryManager * m,size_t symbol,size_t context)508 static void ContextBlockSplitterAddSymbol(
509 ContextBlockSplitter* self, MemoryManager* m,
510 size_t symbol, size_t context) {
511 HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
512 symbol);
513 ++self->block_size_;
514 if (self->block_size_ == self->target_block_size_) {
515 ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
516 if (BROTLI_IS_OOM(m)) return;
517 }
518 }
519
MapStaticContexts(MemoryManager * m,size_t num_contexts,const uint32_t * static_context_map,MetaBlockSplit * mb)520 static void MapStaticContexts(MemoryManager* m,
521 size_t num_contexts,
522 const uint32_t* static_context_map,
523 MetaBlockSplit* mb) {
524 size_t i;
525 BROTLI_DCHECK(mb->literal_context_map == 0);
526 mb->literal_context_map_size =
527 mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
528 mb->literal_context_map =
529 BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
530 if (BROTLI_IS_OOM(m)) return;
531
532 for (i = 0; i < mb->literal_split.num_types; ++i) {
533 uint32_t offset = (uint32_t)(i * num_contexts);
534 size_t j;
535 for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
536 mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
537 offset + static_context_map[j];
538 }
539 }
540 }
541
BrotliBuildMetaBlockGreedyInternal(MemoryManager * m,const uint8_t * ringbuffer,size_t pos,size_t mask,uint8_t prev_byte,uint8_t prev_byte2,ContextLut literal_context_lut,const size_t num_contexts,const uint32_t * static_context_map,const Command * commands,size_t n_commands,MetaBlockSplit * mb)542 static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
543 MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
544 uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
545 const size_t num_contexts, const uint32_t* static_context_map,
546 const Command* commands, size_t n_commands, MetaBlockSplit* mb) {
547 union {
548 BlockSplitterLiteral plain;
549 ContextBlockSplitter ctx;
550 } lit_blocks;
551 BlockSplitterCommand cmd_blocks;
552 BlockSplitterDistance dist_blocks;
553 size_t num_literals = 0;
554 size_t i;
555 for (i = 0; i < n_commands; ++i) {
556 num_literals += commands[i].insert_len_;
557 }
558
559 if (num_contexts == 1) {
560 InitBlockSplitterLiteral(m, &lit_blocks.plain, 256, 512, 400.0,
561 num_literals, &mb->literal_split, &mb->literal_histograms,
562 &mb->literal_histograms_size);
563 } else {
564 InitContextBlockSplitter(m, &lit_blocks.ctx, 256, num_contexts, 512, 400.0,
565 num_literals, &mb->literal_split, &mb->literal_histograms,
566 &mb->literal_histograms_size);
567 }
568 if (BROTLI_IS_OOM(m)) return;
569 InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, 1024,
570 500.0, n_commands, &mb->command_split, &mb->command_histograms,
571 &mb->command_histograms_size);
572 if (BROTLI_IS_OOM(m)) return;
573 InitBlockSplitterDistance(m, &dist_blocks, 64, 512, 100.0, n_commands,
574 &mb->distance_split, &mb->distance_histograms,
575 &mb->distance_histograms_size);
576 if (BROTLI_IS_OOM(m)) return;
577
578 for (i = 0; i < n_commands; ++i) {
579 const Command cmd = commands[i];
580 size_t j;
581 BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_);
582 for (j = cmd.insert_len_; j != 0; --j) {
583 uint8_t literal = ringbuffer[pos & mask];
584 if (num_contexts == 1) {
585 BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal);
586 } else {
587 size_t context =
588 BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
589 ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal,
590 static_context_map[context]);
591 if (BROTLI_IS_OOM(m)) return;
592 }
593 prev_byte2 = prev_byte;
594 prev_byte = literal;
595 ++pos;
596 }
597 pos += CommandCopyLen(&cmd);
598 if (CommandCopyLen(&cmd)) {
599 prev_byte2 = ringbuffer[(pos - 2) & mask];
600 prev_byte = ringbuffer[(pos - 1) & mask];
601 if (cmd.cmd_prefix_ >= 128) {
602 BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_ & 0x3FF);
603 }
604 }
605 }
606
607 if (num_contexts == 1) {
608 BlockSplitterFinishBlockLiteral(
609 &lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
610 } else {
611 ContextBlockSplitterFinishBlock(
612 &lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
613 if (BROTLI_IS_OOM(m)) return;
614 }
615 BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE);
616 BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE);
617
618 if (num_contexts > 1) {
619 MapStaticContexts(m, num_contexts, static_context_map, mb);
620 }
621 }
622
BrotliBuildMetaBlockGreedy(MemoryManager * m,const uint8_t * ringbuffer,size_t pos,size_t mask,uint8_t prev_byte,uint8_t prev_byte2,ContextLut literal_context_lut,size_t num_contexts,const uint32_t * static_context_map,const Command * commands,size_t n_commands,MetaBlockSplit * mb)623 void BrotliBuildMetaBlockGreedy(MemoryManager* m,
624 const uint8_t* ringbuffer,
625 size_t pos,
626 size_t mask,
627 uint8_t prev_byte,
628 uint8_t prev_byte2,
629 ContextLut literal_context_lut,
630 size_t num_contexts,
631 const uint32_t* static_context_map,
632 const Command* commands,
633 size_t n_commands,
634 MetaBlockSplit* mb) {
635 if (num_contexts == 1) {
636 BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
637 prev_byte2, literal_context_lut, 1, NULL, commands, n_commands, mb);
638 } else {
639 BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
640 prev_byte2, literal_context_lut, num_contexts, static_context_map,
641 commands, n_commands, mb);
642 }
643 }
644
BrotliOptimizeHistograms(uint32_t num_distance_codes,MetaBlockSplit * mb)645 void BrotliOptimizeHistograms(uint32_t num_distance_codes,
646 MetaBlockSplit* mb) {
647 uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
648 size_t i;
649 for (i = 0; i < mb->literal_histograms_size; ++i) {
650 BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
651 good_for_rle);
652 }
653 for (i = 0; i < mb->command_histograms_size; ++i) {
654 BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS,
655 mb->command_histograms[i].data_,
656 good_for_rle);
657 }
658 for (i = 0; i < mb->distance_histograms_size; ++i) {
659 BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
660 mb->distance_histograms[i].data_,
661 good_for_rle);
662 }
663 }
664
665 #if defined(__cplusplus) || defined(c_plusplus)
666 } /* extern "C" */
667 #endif
668