Coverage Report

Created: 2025-06-16 07:00

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