Coverage Report

Created: 2023-06-07 06:21

/src/h2o/deps/brotli/c/enc/metablock.c
Line
Count
Source (jump to first uncovered line)
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 <brotli/types.h>
14
#include "./bit_cost.h"
15
#include "./block_splitter.h"
16
#include "./cluster.h"
17
#include "./context.h"
18
#include "./entropy_encode.h"
19
#include "./histogram.h"
20
#include "./memory.h"
21
#include "./port.h"
22
#include "./quality.h"
23
24
#if defined(__cplusplus) || defined(c_plusplus)
25
extern "C" {
26
#endif
27
28
void BrotliBuildMetaBlock(MemoryManager* m,
29
                          const uint8_t* ringbuffer,
30
                          const size_t pos,
31
                          const size_t mask,
32
                          const BrotliEncoderParams* params,
33
                          uint8_t prev_byte,
34
                          uint8_t prev_byte2,
35
                          const Command* cmds,
36
                          size_t num_commands,
37
                          ContextType literal_context_mode,
38
0
                          MetaBlockSplit* mb) {
39
  /* Histogram ids need to fit in one byte. */
40
0
  static const size_t kMaxNumberOfHistograms = 256;
41
0
  HistogramDistance* distance_histograms;
42
0
  HistogramLiteral* literal_histograms;
43
0
  ContextType* literal_context_modes = NULL;
44
0
  size_t literal_histograms_size;
45
0
  size_t distance_histograms_size;
46
0
  size_t i;
47
0
  size_t literal_context_multiplier = 1;
48
49
0
  BrotliSplitBlock(m, cmds, num_commands,
50
0
                   ringbuffer, pos, mask, params,
51
0
                   &mb->literal_split,
52
0
                   &mb->command_split,
53
0
                   &mb->distance_split);
54
0
  if (BROTLI_IS_OOM(m)) return;
55
56
0
  if (!params->disable_literal_context_modeling) {
57
0
    literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
58
0
    literal_context_modes =
59
0
        BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
60
0
    if (BROTLI_IS_OOM(m)) return;
61
0
    for (i = 0; i < mb->literal_split.num_types; ++i) {
62
0
      literal_context_modes[i] = literal_context_mode;
63
0
    }
64
0
  }
65
66
0
  literal_histograms_size =
67
0
      mb->literal_split.num_types * literal_context_multiplier;
68
0
  literal_histograms =
69
0
      BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
70
0
  if (BROTLI_IS_OOM(m)) return;
71
0
  ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
72
73
0
  distance_histograms_size =
74
0
      mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
75
0
  distance_histograms =
76
0
      BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
77
0
  if (BROTLI_IS_OOM(m)) return;
78
0
  ClearHistogramsDistance(distance_histograms, distance_histograms_size);
79
80
0
  assert(mb->command_histograms == 0);
81
0
  mb->command_histograms_size = mb->command_split.num_types;
82
0
  mb->command_histograms =
83
0
      BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
84
0
  if (BROTLI_IS_OOM(m)) return;
85
0
  ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
86
87
0
  BrotliBuildHistogramsWithContext(cmds, num_commands,
88
0
      &mb->literal_split, &mb->command_split, &mb->distance_split,
89
0
      ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes,
90
0
      literal_histograms, mb->command_histograms, distance_histograms);
91
0
  BROTLI_FREE(m, literal_context_modes);
92
93
0
  assert(mb->literal_context_map == 0);
94
0
  mb->literal_context_map_size =
95
0
      mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
96
0
  mb->literal_context_map =
97
0
      BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
98
0
  if (BROTLI_IS_OOM(m)) return;
99
100
0
  assert(mb->literal_histograms == 0);
101
0
  mb->literal_histograms_size = mb->literal_context_map_size;
102
0
  mb->literal_histograms =
103
0
      BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
104
0
  if (BROTLI_IS_OOM(m)) return;
105
106
0
  BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
107
0
      kMaxNumberOfHistograms, mb->literal_histograms,
108
0
      &mb->literal_histograms_size, mb->literal_context_map);
109
0
  if (BROTLI_IS_OOM(m)) return;
110
0
  BROTLI_FREE(m, literal_histograms);
111
112
0
  if (params->disable_literal_context_modeling) {
113
    /* Distribute assignment to all contexts. */
114
0
    for (i = mb->literal_split.num_types; i != 0;) {
115
0
      size_t j = 0;
116
0
      i--;
117
0
      for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) {
118
0
        mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
119
0
            mb->literal_context_map[i];
120
0
      }
121
0
    }
122
0
  }
123
124
0
  assert(mb->distance_context_map == 0);
125
0
  mb->distance_context_map_size =
126
0
      mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
127
0
  mb->distance_context_map =
128
0
      BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
129
0
  if (BROTLI_IS_OOM(m)) return;
130
131
0
  assert(mb->distance_histograms == 0);
132
0
  mb->distance_histograms_size = mb->distance_context_map_size;
133
0
  mb->distance_histograms =
134
0
      BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
135
0
  if (BROTLI_IS_OOM(m)) return;
136
137
0
  BrotliClusterHistogramsDistance(m, distance_histograms,
138
0
                                  mb->distance_context_map_size,
139
0
                                  kMaxNumberOfHistograms,
140
0
                                  mb->distance_histograms,
141
0
                                  &mb->distance_histograms_size,
142
0
                                  mb->distance_context_map);
143
0
  if (BROTLI_IS_OOM(m)) return;
144
0
  BROTLI_FREE(m, distance_histograms);
145
0
}
146
147
0
#define FN(X) X ## Literal
148
#include "./metablock_inc.h"  /* NOLINT(build/include) */
149
#undef FN
150
151
0
#define FN(X) X ## Command
152
#include "./metablock_inc.h"  /* NOLINT(build/include) */
153
#undef FN
154
155
0
#define FN(X) X ## Distance
156
#include "./metablock_inc.h"  /* NOLINT(build/include) */
157
#undef FN
158
159
#define BROTLI_MAX_STATIC_CONTEXTS 13
160
161
/* Greedy block splitter for one block category (literal, command or distance).
162
   Gathers histograms for all context buckets. */
163
typedef struct ContextBlockSplitter {
164
  /* Alphabet size of particular block category. */
165
  size_t alphabet_size_;
166
  size_t num_contexts_;
167
  size_t max_block_types_;
168
  /* We collect at least this many symbols for each block. */
169
  size_t min_block_size_;
170
  /* We merge histograms A and B if
171
       entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
172
     where A is the current histogram and B is the histogram of the last or the
173
     second last block type. */
174
  double split_threshold_;
175
176
  size_t num_blocks_;
177
  BlockSplit* split_;  /* not owned */
178
  HistogramLiteral* histograms_;  /* not owned */
179
  size_t* histograms_size_;  /* not owned */
180
181
  /* The number of symbols that we want to collect before deciding on whether
182
     or not to merge the block with a previous one or emit a new block. */
183
  size_t target_block_size_;
184
  /* The number of symbols in the current histogram. */
185
  size_t block_size_;
186
  /* Offset of the current histogram. */
187
  size_t curr_histogram_ix_;
188
  /* Offset of the histograms of the previous two block types. */
189
  size_t last_histogram_ix_[2];
190
  /* Entropy of the previous two block types. */
191
  double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
192
  /* The number of times we merged the current block with the last one. */
193
  size_t merge_last_count_;
194
} ContextBlockSplitter;
195
196
static void InitContextBlockSplitter(
197
    MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size,
198
    size_t num_contexts, size_t min_block_size, double split_threshold,
199
    size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms,
200
0
    size_t* histograms_size) {
201
0
  size_t max_num_blocks = num_symbols / min_block_size + 1;
202
0
  size_t max_num_types;
203
0
  assert(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
204
205
0
  self->alphabet_size_ = alphabet_size;
206
0
  self->num_contexts_ = num_contexts;
207
0
  self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts;
208
0
  self->min_block_size_ = min_block_size;
209
0
  self->split_threshold_ = split_threshold;
210
0
  self->num_blocks_ = 0;
211
0
  self->split_ = split;
212
0
  self->histograms_size_ = histograms_size;
213
0
  self->target_block_size_ = min_block_size;
214
0
  self->block_size_ = 0;
215
0
  self->curr_histogram_ix_ = 0;
216
0
  self->merge_last_count_ = 0;
217
218
  /* We have to allocate one more histogram than the maximum number of block
219
     types for the current histogram when the meta-block is too big. */
220
0
  max_num_types =
221
0
      BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1);
222
0
  BROTLI_ENSURE_CAPACITY(m, uint8_t,
223
0
      split->types, split->types_alloc_size, max_num_blocks);
224
0
  BROTLI_ENSURE_CAPACITY(m, uint32_t,
225
0
      split->lengths, split->lengths_alloc_size, max_num_blocks);
226
0
  if (BROTLI_IS_OOM(m)) return;
227
0
  split->num_blocks = max_num_blocks;
228
0
  if (BROTLI_IS_OOM(m)) return;
229
0
  assert(*histograms == 0);
230
0
  *histograms_size = max_num_types * num_contexts;
231
0
  *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
232
0
  self->histograms_ = *histograms;
233
0
  if (BROTLI_IS_OOM(m)) return;
234
  /* Clear only current histogram. */
235
0
  ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
236
0
  self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
237
0
}
238
239
/* Does either of three things:
240
     (1) emits the current block with a new block type;
241
     (2) emits the current block with the type of the second last block;
242
     (3) merges the current block with the last block. */
243
static void ContextBlockSplitterFinishBlock(
244
0
    ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
245
0
  BlockSplit* split = self->split_;
246
0
  const size_t num_contexts = self->num_contexts_;
247
0
  double* last_entropy = self->last_entropy_;
248
0
  HistogramLiteral* histograms = self->histograms_;
249
250
0
  if (self->block_size_ < self->min_block_size_) {
251
0
    self->block_size_ = self->min_block_size_;
252
0
  }
253
0
  if (self->num_blocks_ == 0) {
254
0
    size_t i;
255
    /* Create first block. */
256
0
    split->lengths[0] = (uint32_t)self->block_size_;
257
0
    split->types[0] = 0;
258
259
0
    for (i = 0; i < num_contexts; ++i) {
260
0
      last_entropy[i] =
261
0
          BitsEntropy(histograms[i].data_, self->alphabet_size_);
262
0
      last_entropy[num_contexts + i] = last_entropy[i];
263
0
    }
264
0
    ++self->num_blocks_;
265
0
    ++split->num_types;
266
0
    self->curr_histogram_ix_ += num_contexts;
267
0
    if (self->curr_histogram_ix_ < *self->histograms_size_) {
268
0
      ClearHistogramsLiteral(
269
0
          &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
270
0
    }
271
0
    self->block_size_ = 0;
272
0
  } else if (self->block_size_ > 0) {
273
    /* Try merging the set of histograms for the current block type with the
274
       respective set of histograms for the last and second last block types.
275
       Decide over the split based on the total reduction of entropy across
276
       all contexts. */
277
0
    double entropy[BROTLI_MAX_STATIC_CONTEXTS];
278
0
    HistogramLiteral* combined_histo =
279
0
        BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
280
0
    double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
281
0
    double diff[2] = { 0.0 };
282
0
    size_t i;
283
0
    if (BROTLI_IS_OOM(m)) return;
284
0
    for (i = 0; i < num_contexts; ++i) {
285
0
      size_t curr_histo_ix = self->curr_histogram_ix_ + i;
286
0
      size_t j;
287
0
      entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_,
288
0
                               self->alphabet_size_);
289
0
      for (j = 0; j < 2; ++j) {
290
0
        size_t jx = j * num_contexts + i;
291
0
        size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
292
0
        combined_histo[jx] = histograms[curr_histo_ix];
293
0
        HistogramAddHistogramLiteral(&combined_histo[jx],
294
0
            &histograms[last_histogram_ix]);
295
0
        combined_entropy[jx] = BitsEntropy(
296
0
            &combined_histo[jx].data_[0], self->alphabet_size_);
297
0
        diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
298
0
      }
299
0
    }
300
301
0
    if (split->num_types < self->max_block_types_ &&
302
0
        diff[0] > self->split_threshold_ &&
303
0
        diff[1] > self->split_threshold_) {
304
      /* Create new block. */
305
0
      split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
306
0
      split->types[self->num_blocks_] = (uint8_t)split->num_types;
307
0
      self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
308
0
      self->last_histogram_ix_[0] = split->num_types * num_contexts;
309
0
      for (i = 0; i < num_contexts; ++i) {
310
0
        last_entropy[num_contexts + i] = last_entropy[i];
311
0
        last_entropy[i] = entropy[i];
312
0
      }
313
0
      ++self->num_blocks_;
314
0
      ++split->num_types;
315
0
      self->curr_histogram_ix_ += num_contexts;
316
0
      if (self->curr_histogram_ix_ < *self->histograms_size_) {
317
0
        ClearHistogramsLiteral(
318
0
            &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
319
0
      }
320
0
      self->block_size_ = 0;
321
0
      self->merge_last_count_ = 0;
322
0
      self->target_block_size_ = self->min_block_size_;
323
0
    } else if (diff[1] < diff[0] - 20.0) {
324
      /* Combine this block with second last block. */
325
0
      split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
326
0
      split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
327
0
      BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
328
0
      for (i = 0; i < num_contexts; ++i) {
329
0
        histograms[self->last_histogram_ix_[0] + i] =
330
0
            combined_histo[num_contexts + i];
331
0
        last_entropy[num_contexts + i] = last_entropy[i];
332
0
        last_entropy[i] = combined_entropy[num_contexts + i];
333
0
        HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
334
0
      }
335
0
      ++self->num_blocks_;
336
0
      self->block_size_ = 0;
337
0
      self->merge_last_count_ = 0;
338
0
      self->target_block_size_ = self->min_block_size_;
339
0
    } else {
340
      /* Combine this block with last block. */
341
0
      split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
342
0
      for (i = 0; i < num_contexts; ++i) {
343
0
        histograms[self->last_histogram_ix_[0] + i] = combined_histo[i];
344
0
        last_entropy[i] = combined_entropy[i];
345
0
        if (split->num_types == 1) {
346
0
          last_entropy[num_contexts + i] = last_entropy[i];
347
0
        }
348
0
        HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
349
0
      }
350
0
      self->block_size_ = 0;
351
0
      if (++self->merge_last_count_ > 1) {
352
0
        self->target_block_size_ += self->min_block_size_;
353
0
      }
354
0
    }
355
0
    BROTLI_FREE(m, combined_histo);
356
0
  }
357
0
  if (is_final) {
358
0
    *self->histograms_size_ = split->num_types * num_contexts;
359
0
    split->num_blocks = self->num_blocks_;
360
0
  }
361
0
}
362
363
/* Adds the next symbol to the current block type and context. When the
364
   current block reaches the target size, decides on merging the block. */
365
static void ContextBlockSplitterAddSymbol(
366
    ContextBlockSplitter* self, MemoryManager* m,
367
0
    size_t symbol, size_t context) {
368
0
  HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
369
0
      symbol);
370
0
  ++self->block_size_;
371
0
  if (self->block_size_ == self->target_block_size_) {
372
0
    ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
373
0
    if (BROTLI_IS_OOM(m)) return;
374
0
  }
375
0
}
376
377
static void MapStaticContexts(MemoryManager* m,
378
                              size_t num_contexts,
379
                              const uint32_t* static_context_map,
380
0
                              MetaBlockSplit* mb) {
381
0
  size_t i;
382
0
  assert(mb->literal_context_map == 0);
383
0
  mb->literal_context_map_size =
384
0
      mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
385
0
  mb->literal_context_map =
386
0
      BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
387
0
  if (BROTLI_IS_OOM(m)) return;
388
389
0
  for (i = 0; i < mb->literal_split.num_types; ++i) {
390
0
    uint32_t offset = (uint32_t)(i * num_contexts);
391
0
    size_t j;
392
0
    for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
393
0
      mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
394
0
          offset + static_context_map[j];
395
0
    }
396
0
  }
397
0
}
398
399
static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
400
    MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
401
    uint8_t prev_byte, uint8_t prev_byte2, ContextType literal_context_mode,
402
    const size_t num_contexts, const uint32_t* static_context_map,
403
0
    const Command *commands, size_t n_commands, MetaBlockSplit* mb) {
404
0
  union {
405
0
    BlockSplitterLiteral plain;
406
0
    ContextBlockSplitter ctx;
407
0
  } lit_blocks;
408
0
  BlockSplitterCommand cmd_blocks;
409
0
  BlockSplitterDistance dist_blocks;
410
0
  size_t num_literals = 0;
411
0
  size_t i;
412
0
  for (i = 0; i < n_commands; ++i) {
413
0
    num_literals += commands[i].insert_len_;
414
0
  }
415
416
0
  if (num_contexts == 1) {
417
0
    InitBlockSplitterLiteral(m, &lit_blocks.plain, 256, 512, 400.0,
418
0
        num_literals, &mb->literal_split, &mb->literal_histograms,
419
0
        &mb->literal_histograms_size);
420
0
  } else {
421
0
    InitContextBlockSplitter(m, &lit_blocks.ctx, 256, num_contexts, 512, 400.0,
422
0
        num_literals, &mb->literal_split, &mb->literal_histograms,
423
0
        &mb->literal_histograms_size);
424
0
  }
425
0
  if (BROTLI_IS_OOM(m)) return;
426
0
  InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, 1024,
427
0
      500.0, n_commands, &mb->command_split, &mb->command_histograms,
428
0
      &mb->command_histograms_size);
429
0
  if (BROTLI_IS_OOM(m)) return;
430
0
  InitBlockSplitterDistance(m, &dist_blocks, 64, 512, 100.0, n_commands,
431
0
      &mb->distance_split, &mb->distance_histograms,
432
0
      &mb->distance_histograms_size);
433
0
  if (BROTLI_IS_OOM(m)) return;
434
435
0
  for (i = 0; i < n_commands; ++i) {
436
0
    const Command cmd = commands[i];
437
0
    size_t j;
438
0
    BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_);
439
0
    for (j = cmd.insert_len_; j != 0; --j) {
440
0
      uint8_t literal = ringbuffer[pos & mask];
441
0
      if (num_contexts == 1) {
442
0
        BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal);
443
0
      } else {
444
0
        size_t context = Context(prev_byte, prev_byte2, literal_context_mode);
445
0
        ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal,
446
0
                                      static_context_map[context]);
447
0
        if (BROTLI_IS_OOM(m)) return;
448
0
      }
449
0
      prev_byte2 = prev_byte;
450
0
      prev_byte = literal;
451
0
      ++pos;
452
0
    }
453
0
    pos += CommandCopyLen(&cmd);
454
0
    if (CommandCopyLen(&cmd)) {
455
0
      prev_byte2 = ringbuffer[(pos - 2) & mask];
456
0
      prev_byte = ringbuffer[(pos - 1) & mask];
457
0
      if (cmd.cmd_prefix_ >= 128) {
458
0
        BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_);
459
0
      }
460
0
    }
461
0
  }
462
463
0
  if (num_contexts == 1) {
464
0
    BlockSplitterFinishBlockLiteral(
465
0
        &lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
466
0
  } else {
467
0
    ContextBlockSplitterFinishBlock(
468
0
        &lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
469
0
    if (BROTLI_IS_OOM(m)) return;
470
0
  }
471
0
  BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE);
472
0
  BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE);
473
474
0
  if (num_contexts > 1) {
475
0
    MapStaticContexts(m, num_contexts, static_context_map, mb);
476
0
  }
477
0
}
478
479
void BrotliBuildMetaBlockGreedy(MemoryManager* m,
480
                                const uint8_t* ringbuffer,
481
                                size_t pos,
482
                                size_t mask,
483
                                uint8_t prev_byte,
484
                                uint8_t prev_byte2,
485
                                ContextType literal_context_mode,
486
                                size_t num_contexts,
487
                                const uint32_t* static_context_map,
488
                                const Command* commands,
489
                                size_t n_commands,
490
0
                                MetaBlockSplit* mb) {
491
0
  if (num_contexts == 1) {
492
0
    BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
493
0
        prev_byte2, literal_context_mode, 1, NULL, commands, n_commands, mb);
494
0
  } else {
495
0
    BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
496
0
        prev_byte2, literal_context_mode, num_contexts, static_context_map,
497
0
        commands, n_commands, mb);
498
0
  }
499
0
}
500
501
void BrotliOptimizeHistograms(size_t num_direct_distance_codes,
502
                              size_t distance_postfix_bits,
503
0
                              MetaBlockSplit* mb) {
504
0
  uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
505
0
  size_t num_distance_codes;
506
0
  size_t i;
507
0
  for (i = 0; i < mb->literal_histograms_size; ++i) {
508
0
    BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
509
0
                                      good_for_rle);
510
0
  }
511
0
  for (i = 0; i < mb->command_histograms_size; ++i) {
512
0
    BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS,
513
0
                                      mb->command_histograms[i].data_,
514
0
                                      good_for_rle);
515
0
  }
516
0
  num_distance_codes = BROTLI_NUM_DISTANCE_SHORT_CODES +
517
0
      num_direct_distance_codes +
518
0
      ((2 * BROTLI_MAX_DISTANCE_BITS) << distance_postfix_bits);
519
0
  for (i = 0; i < mb->distance_histograms_size; ++i) {
520
0
    BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
521
0
                                      mb->distance_histograms[i].data_,
522
0
                                      good_for_rle);
523
0
  }
524
0
}
525
526
#if defined(__cplusplus) || defined(c_plusplus)
527
}  /* extern "C" */
528
#endif