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