xref: /aosp_15_r20/external/cronet/third_party/brotli/enc/metablock.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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, &params->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