Coverage Report

Created: 2025-11-14 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/third_party/brotli/c/enc/metablock.c
Line
Count
Source
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 "bit_cost.h"
16
#include "block_splitter.h"
17
#include "cluster.h"
18
#include "command.h"
19
#include "entropy_encode.h"
20
#include "histogram.h"
21
#include "memory.h"
22
#include "params.h"
23
#include "prefix.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
/* Greedy block splitter for one block category (literal, command or distance).
302
   Gathers histograms for all context buckets. */
303
typedef struct ContextBlockSplitter {
304
  /* Alphabet size of particular block category. */
305
  size_t alphabet_size_;
306
  size_t num_contexts_;
307
  size_t max_block_types_;
308
  /* We collect at least this many symbols for each block. */
309
  size_t min_block_size_;
310
  /* We merge histograms A and B if
311
       entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
312
     where A is the current histogram and B is the histogram of the last or the
313
     second last block type. */
314
  double split_threshold_;
315
316
  size_t num_blocks_;
317
  BlockSplit* split_;  /* not owned */
318
  HistogramLiteral* histograms_;  /* not owned */
319
  size_t* histograms_size_;  /* not owned */
320
321
  /* The number of symbols that we want to collect before deciding on whether
322
     or not to merge the block with a previous one or emit a new block. */
323
  size_t target_block_size_;
324
  /* The number of symbols in the current histogram. */
325
  size_t block_size_;
326
  /* Offset of the current histogram. */
327
  size_t curr_histogram_ix_;
328
  /* Offset of the histograms of the previous two block types. */
329
  size_t last_histogram_ix_[2];
330
  /* Entropy of the previous two block types. */
331
  double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
332
  /* The number of times we merged the current block with the last one. */
333
  size_t merge_last_count_;
334
} ContextBlockSplitter;
335
336
static void InitContextBlockSplitter(
337
    MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size,
338
    size_t num_contexts, size_t min_block_size, double split_threshold,
339
    size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms,
340
    size_t* histograms_size) {
341
  size_t max_num_blocks = num_symbols / min_block_size + 1;
342
  size_t max_num_types;
343
  BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
344
345
  self->alphabet_size_ = alphabet_size;
346
  self->num_contexts_ = num_contexts;
347
  self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts;
348
  self->min_block_size_ = min_block_size;
349
  self->split_threshold_ = split_threshold;
350
  self->num_blocks_ = 0;
351
  self->split_ = split;
352
  self->histograms_size_ = histograms_size;
353
  self->target_block_size_ = min_block_size;
354
  self->block_size_ = 0;
355
  self->curr_histogram_ix_ = 0;
356
  self->merge_last_count_ = 0;
357
358
  /* We have to allocate one more histogram than the maximum number of block
359
     types for the current histogram when the meta-block is too big. */
360
  max_num_types =
361
      BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1);
362
  BROTLI_ENSURE_CAPACITY(m, uint8_t,
363
      split->types, split->types_alloc_size, max_num_blocks);
364
  BROTLI_ENSURE_CAPACITY(m, uint32_t,
365
      split->lengths, split->lengths_alloc_size, max_num_blocks);
366
  if (BROTLI_IS_OOM(m)) return;
367
  split->num_blocks = max_num_blocks;
368
  if (BROTLI_IS_OOM(m)) return;
369
  BROTLI_DCHECK(*histograms == 0);
370
  *histograms_size = max_num_types * num_contexts;
371
  *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
372
  self->histograms_ = *histograms;
373
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
374
  /* Clear only current histogram. */
375
  ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
376
  self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
377
}
378
379
/* Does either of three things:
380
     (1) emits the current block with a new block type;
381
     (2) emits the current block with the type of the second last block;
382
     (3) merges the current block with the last block. */
383
static void ContextBlockSplitterFinishBlock(
384
0
    ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
385
0
  BlockSplit* split = self->split_;
386
0
  const size_t num_contexts = self->num_contexts_;
387
0
  double* last_entropy = self->last_entropy_;
388
0
  HistogramLiteral* histograms = self->histograms_;
389
390
0
  if (self->block_size_ < self->min_block_size_) {
391
0
    self->block_size_ = self->min_block_size_;
392
0
  }
393
0
  if (self->num_blocks_ == 0) {
394
0
    size_t i;
395
    /* Create first block. */
396
0
    split->lengths[0] = (uint32_t)self->block_size_;
397
0
    split->types[0] = 0;
398
399
0
    for (i = 0; i < num_contexts; ++i) {
400
0
      last_entropy[i] =
401
0
          BrotliBitsEntropy(histograms[i].data_, self->alphabet_size_);
402
0
      last_entropy[num_contexts + i] = last_entropy[i];
403
0
    }
404
0
    ++self->num_blocks_;
405
0
    ++split->num_types;
406
0
    self->curr_histogram_ix_ += num_contexts;
407
0
    if (self->curr_histogram_ix_ < *self->histograms_size_) {
408
0
      ClearHistogramsLiteral(
409
0
          &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
410
0
    }
411
0
    self->block_size_ = 0;
412
0
  } else if (self->block_size_ > 0) {
413
    /* Try merging the set of histograms for the current block type with the
414
       respective set of histograms for the last and second last block types.
415
       Decide over the split based on the total reduction of entropy across
416
       all contexts. */
417
0
    double entropy[BROTLI_MAX_STATIC_CONTEXTS];
418
0
    HistogramLiteral* combined_histo =
419
0
        BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
420
0
    double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
421
0
    double diff[2] = { 0.0 };
422
0
    size_t i;
423
0
    if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
424
0
    for (i = 0; i < num_contexts; ++i) {
425
0
      size_t curr_histo_ix = self->curr_histogram_ix_ + i;
426
0
      size_t j;
427
0
      entropy[i] = BrotliBitsEntropy(histograms[curr_histo_ix].data_,
428
0
                                     self->alphabet_size_);
429
0
      for (j = 0; j < 2; ++j) {
430
0
        size_t jx = j * num_contexts + i;
431
0
        size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
432
0
        combined_histo[jx] = histograms[curr_histo_ix];
433
0
        HistogramAddHistogramLiteral(&combined_histo[jx],
434
0
            &histograms[last_histogram_ix]);
435
0
        combined_entropy[jx] = BrotliBitsEntropy(
436
0
            &combined_histo[jx].data_[0], self->alphabet_size_);
437
0
        diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
438
0
      }
439
0
    }
440
441
0
    if (split->num_types < self->max_block_types_ &&
442
0
        diff[0] > self->split_threshold_ &&
443
0
        diff[1] > self->split_threshold_) {
444
      /* Create new block. */
445
0
      split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
446
0
      split->types[self->num_blocks_] = (uint8_t)split->num_types;
447
0
      self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
448
0
      self->last_histogram_ix_[0] = split->num_types * num_contexts;
449
0
      for (i = 0; i < num_contexts; ++i) {
450
0
        last_entropy[num_contexts + i] = last_entropy[i];
451
0
        last_entropy[i] = entropy[i];
452
0
      }
453
0
      ++self->num_blocks_;
454
0
      ++split->num_types;
455
0
      self->curr_histogram_ix_ += num_contexts;
456
0
      if (self->curr_histogram_ix_ < *self->histograms_size_) {
457
0
        ClearHistogramsLiteral(
458
0
            &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
459
0
      }
460
0
      self->block_size_ = 0;
461
0
      self->merge_last_count_ = 0;
462
0
      self->target_block_size_ = self->min_block_size_;
463
0
    } else if (diff[1] < diff[0] - 20.0) {
464
      /* Combine this block with second last block. */
465
0
      split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
466
0
      split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
467
0
      BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
468
0
      for (i = 0; i < num_contexts; ++i) {
469
0
        histograms[self->last_histogram_ix_[0] + i] =
470
0
            combined_histo[num_contexts + i];
471
0
        last_entropy[num_contexts + i] = last_entropy[i];
472
0
        last_entropy[i] = combined_entropy[num_contexts + i];
473
0
        HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
474
0
      }
475
0
      ++self->num_blocks_;
476
0
      self->block_size_ = 0;
477
0
      self->merge_last_count_ = 0;
478
0
      self->target_block_size_ = self->min_block_size_;
479
0
    } else {
480
      /* Combine this block with last block. */
481
0
      split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
482
0
      for (i = 0; i < num_contexts; ++i) {
483
0
        histograms[self->last_histogram_ix_[0] + i] = combined_histo[i];
484
0
        last_entropy[i] = combined_entropy[i];
485
0
        if (split->num_types == 1) {
486
0
          last_entropy[num_contexts + i] = last_entropy[i];
487
0
        }
488
0
        HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
489
0
      }
490
0
      self->block_size_ = 0;
491
0
      if (++self->merge_last_count_ > 1) {
492
0
        self->target_block_size_ += self->min_block_size_;
493
0
      }
494
0
    }
495
0
    BROTLI_FREE(m, combined_histo);
496
0
  }
497
0
  if (is_final) {
498
0
    *self->histograms_size_ = split->num_types * num_contexts;
499
0
    split->num_blocks = self->num_blocks_;
500
0
  }
501
0
}
502
503
/* Adds the next symbol to the current block type and context. When the
504
   current block reaches the target size, decides on merging the block. */
505
static void ContextBlockSplitterAddSymbol(
506
    ContextBlockSplitter* self, MemoryManager* m,
507
0
    size_t symbol, size_t context) {
508
0
  HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
509
0
      symbol);
510
0
  ++self->block_size_;
511
0
  if (self->block_size_ == self->target_block_size_) {
512
0
    ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
513
0
    if (BROTLI_IS_OOM(m)) return;
514
0
  }
515
0
}
516
517
static void MapStaticContexts(MemoryManager* m,
518
                              size_t num_contexts,
519
                              const uint32_t* static_context_map,
520
0
                              MetaBlockSplit* mb) {
521
0
  size_t i;
522
0
  BROTLI_DCHECK(mb->literal_context_map == 0);
523
0
  mb->literal_context_map_size =
524
0
      mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
525
0
  mb->literal_context_map =
526
0
      BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
527
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
528
529
0
  for (i = 0; i < mb->literal_split.num_types; ++i) {
530
0
    uint32_t offset = (uint32_t)(i * num_contexts);
531
0
    size_t j;
532
0
    for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
533
0
      mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
534
0
          offset + static_context_map[j];
535
0
    }
536
0
  }
537
0
}
538
539
typedef struct GreedyMetablockArena {
540
  union {
541
    BlockSplitterLiteral plain;
542
    ContextBlockSplitter ctx;
543
  } lit_blocks;
544
  BlockSplitterCommand cmd_blocks;
545
  BlockSplitterDistance dist_blocks;
546
} GreedyMetablockArena;
547
548
static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
549
    MemoryManager* m, GreedyMetablockArena* arena, const uint8_t* ringbuffer,
550
    size_t pos, size_t mask, uint8_t prev_byte, uint8_t prev_byte2,
551
    ContextLut literal_context_lut, const size_t num_contexts,
552
    const uint32_t* static_context_map, const Command* commands,
553
0
    size_t n_commands, MetaBlockSplit* mb) {
554
0
  size_t num_literals = 0;
555
0
  size_t i;
556
0
  for (i = 0; i < n_commands; ++i) {
557
0
    num_literals += commands[i].insert_len_;
558
0
  }
559
560
0
  if (num_contexts == 1) {
561
0
    InitBlockSplitterLiteral(m, &arena->lit_blocks.plain, 256, 512, 400.0,
562
0
        num_literals, &mb->literal_split, &mb->literal_histograms,
563
0
        &mb->literal_histograms_size);
564
0
  } else {
565
0
    InitContextBlockSplitter(m, &arena->lit_blocks.ctx, 256, num_contexts, 512,
566
0
        400.0, num_literals, &mb->literal_split, &mb->literal_histograms,
567
0
        &mb->literal_histograms_size);
568
0
  }
569
0
  if (BROTLI_IS_OOM(m)) return;
570
0
  InitBlockSplitterCommand(m, &arena->cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS,
571
0
      1024, 500.0, n_commands, &mb->command_split, &mb->command_histograms,
572
0
      &mb->command_histograms_size);
573
0
  if (BROTLI_IS_OOM(m)) return;
574
0
  InitBlockSplitterDistance(m, &arena->dist_blocks, 64, 512, 100.0, n_commands,
575
0
      &mb->distance_split, &mb->distance_histograms,
576
0
      &mb->distance_histograms_size);
577
0
  if (BROTLI_IS_OOM(m)) return;
578
579
0
  for (i = 0; i < n_commands; ++i) {
580
0
    const Command cmd = commands[i];
581
0
    size_t j;
582
0
    BlockSplitterAddSymbolCommand(&arena->cmd_blocks, cmd.cmd_prefix_);
583
0
    for (j = cmd.insert_len_; j != 0; --j) {
584
0
      uint8_t literal = ringbuffer[pos & mask];
585
0
      if (num_contexts == 1) {
586
0
        BlockSplitterAddSymbolLiteral(&arena->lit_blocks.plain, literal);
587
0
      } else {
588
0
        size_t context =
589
0
            BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
590
0
        ContextBlockSplitterAddSymbol(&arena->lit_blocks.ctx, m, literal,
591
0
                                      static_context_map[context]);
592
0
        if (BROTLI_IS_OOM(m)) return;
593
0
      }
594
0
      prev_byte2 = prev_byte;
595
0
      prev_byte = literal;
596
0
      ++pos;
597
0
    }
598
0
    pos += CommandCopyLen(&cmd);
599
0
    if (CommandCopyLen(&cmd)) {
600
0
      prev_byte2 = ringbuffer[(pos - 2) & mask];
601
0
      prev_byte = ringbuffer[(pos - 1) & mask];
602
0
      if (cmd.cmd_prefix_ >= 128) {
603
0
        BlockSplitterAddSymbolDistance(
604
0
            &arena->dist_blocks, cmd.dist_prefix_ & 0x3FF);
605
0
      }
606
0
    }
607
0
  }
608
609
0
  if (num_contexts == 1) {
610
0
    BlockSplitterFinishBlockLiteral(
611
0
        &arena->lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
612
0
  } else {
613
0
    ContextBlockSplitterFinishBlock(
614
0
        &arena->lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
615
0
    if (BROTLI_IS_OOM(m)) return;
616
0
  }
617
0
  BlockSplitterFinishBlockCommand(
618
0
      &arena->cmd_blocks, /* is_final = */ BROTLI_TRUE);
619
0
  BlockSplitterFinishBlockDistance(
620
0
      &arena->dist_blocks, /* is_final = */ BROTLI_TRUE);
621
622
0
  if (num_contexts > 1) {
623
0
    MapStaticContexts(m, num_contexts, static_context_map, mb);
624
0
  }
625
0
}
626
627
void BrotliBuildMetaBlockGreedy(MemoryManager* m,
628
                                const uint8_t* ringbuffer,
629
                                size_t pos,
630
                                size_t mask,
631
                                uint8_t prev_byte,
632
                                uint8_t prev_byte2,
633
                                ContextLut literal_context_lut,
634
                                size_t num_contexts,
635
                                const uint32_t* static_context_map,
636
                                const Command* commands,
637
                                size_t n_commands,
638
0
                                MetaBlockSplit* mb) {
639
0
  GreedyMetablockArena* arena = BROTLI_ALLOC(m, GreedyMetablockArena, 1);
640
0
  if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
641
0
  if (num_contexts == 1) {
642
0
    BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask,
643
0
        prev_byte, prev_byte2, literal_context_lut, 1, NULL, commands,
644
0
        n_commands, mb);
645
0
  } else {
646
0
    BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask,
647
0
        prev_byte, prev_byte2, literal_context_lut, num_contexts,
648
0
        static_context_map, commands, n_commands, mb);
649
0
  }
650
0
  BROTLI_FREE(m, arena);
651
0
}
652
653
void BrotliOptimizeHistograms(uint32_t num_distance_codes,
654
0
                              MetaBlockSplit* mb) {
655
0
  uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
656
0
  size_t i;
657
0
  for (i = 0; i < mb->literal_histograms_size; ++i) {
658
0
    BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
659
0
                                      good_for_rle);
660
0
  }
661
0
  for (i = 0; i < mb->command_histograms_size; ++i) {
662
0
    BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS,
663
0
                                      mb->command_histograms[i].data_,
664
0
                                      good_for_rle);
665
0
  }
666
0
  for (i = 0; i < mb->distance_histograms_size; ++i) {
667
0
    BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
668
0
                                      mb->distance_histograms[i].data_,
669
0
                                      good_for_rle);
670
0
  }
671
0
}
672
673
#if defined(__cplusplus) || defined(c_plusplus)
674
}  /* extern "C" */
675
#endif