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