11cb0ef41Sopenharmony_ci/* Copyright 2015 Google Inc. All Rights Reserved. 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci Distributed under MIT license. 41cb0ef41Sopenharmony_ci See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 51cb0ef41Sopenharmony_ci*/ 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci/* Algorithms for distributing the literals and commands of a metablock between 81cb0ef41Sopenharmony_ci block types and contexts. */ 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include "./metablock.h" 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci#include "../common/constants.h" 131cb0ef41Sopenharmony_ci#include "../common/context.h" 141cb0ef41Sopenharmony_ci#include "../common/platform.h" 151cb0ef41Sopenharmony_ci#include <brotli/types.h> 161cb0ef41Sopenharmony_ci#include "./bit_cost.h" 171cb0ef41Sopenharmony_ci#include "./block_splitter.h" 181cb0ef41Sopenharmony_ci#include "./cluster.h" 191cb0ef41Sopenharmony_ci#include "./entropy_encode.h" 201cb0ef41Sopenharmony_ci#include "./histogram.h" 211cb0ef41Sopenharmony_ci#include "./memory.h" 221cb0ef41Sopenharmony_ci#include "./quality.h" 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci#if defined(__cplusplus) || defined(c_plusplus) 251cb0ef41Sopenharmony_ciextern "C" { 261cb0ef41Sopenharmony_ci#endif 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_civoid BrotliInitDistanceParams(BrotliEncoderParams* params, 291cb0ef41Sopenharmony_ci uint32_t npostfix, uint32_t ndirect) { 301cb0ef41Sopenharmony_ci BrotliDistanceParams* dist_params = ¶ms->dist; 311cb0ef41Sopenharmony_ci uint32_t alphabet_size_max; 321cb0ef41Sopenharmony_ci uint32_t alphabet_size_limit; 331cb0ef41Sopenharmony_ci uint32_t max_distance; 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci dist_params->distance_postfix_bits = npostfix; 361cb0ef41Sopenharmony_ci dist_params->num_direct_distance_codes = ndirect; 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( 391cb0ef41Sopenharmony_ci npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS); 401cb0ef41Sopenharmony_ci alphabet_size_limit = alphabet_size_max; 411cb0ef41Sopenharmony_ci max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) - 421cb0ef41Sopenharmony_ci (1U << (npostfix + 2)); 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci if (params->large_window) { 451cb0ef41Sopenharmony_ci BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit( 461cb0ef41Sopenharmony_ci BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect); 471cb0ef41Sopenharmony_ci alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( 481cb0ef41Sopenharmony_ci npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS); 491cb0ef41Sopenharmony_ci alphabet_size_limit = limit.max_alphabet_size; 501cb0ef41Sopenharmony_ci max_distance = limit.max_distance; 511cb0ef41Sopenharmony_ci } 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci dist_params->alphabet_size_max = alphabet_size_max; 541cb0ef41Sopenharmony_ci dist_params->alphabet_size_limit = alphabet_size_limit; 551cb0ef41Sopenharmony_ci dist_params->max_distance = max_distance; 561cb0ef41Sopenharmony_ci} 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_cistatic void RecomputeDistancePrefixes(Command* cmds, 591cb0ef41Sopenharmony_ci size_t num_commands, 601cb0ef41Sopenharmony_ci const BrotliDistanceParams* orig_params, 611cb0ef41Sopenharmony_ci const BrotliDistanceParams* new_params) { 621cb0ef41Sopenharmony_ci size_t i; 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits && 651cb0ef41Sopenharmony_ci orig_params->num_direct_distance_codes == 661cb0ef41Sopenharmony_ci new_params->num_direct_distance_codes) { 671cb0ef41Sopenharmony_ci return; 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci for (i = 0; i < num_commands; ++i) { 711cb0ef41Sopenharmony_ci Command* cmd = &cmds[i]; 721cb0ef41Sopenharmony_ci if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) { 731cb0ef41Sopenharmony_ci PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params), 741cb0ef41Sopenharmony_ci new_params->num_direct_distance_codes, 751cb0ef41Sopenharmony_ci new_params->distance_postfix_bits, 761cb0ef41Sopenharmony_ci &cmd->dist_prefix_, 771cb0ef41Sopenharmony_ci &cmd->dist_extra_); 781cb0ef41Sopenharmony_ci } 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_cistatic BROTLI_BOOL ComputeDistanceCost(const Command* cmds, 831cb0ef41Sopenharmony_ci size_t num_commands, 841cb0ef41Sopenharmony_ci const BrotliDistanceParams* orig_params, 851cb0ef41Sopenharmony_ci const BrotliDistanceParams* new_params, 861cb0ef41Sopenharmony_ci double* cost) { 871cb0ef41Sopenharmony_ci size_t i; 881cb0ef41Sopenharmony_ci BROTLI_BOOL equal_params = BROTLI_FALSE; 891cb0ef41Sopenharmony_ci uint16_t dist_prefix; 901cb0ef41Sopenharmony_ci uint32_t dist_extra; 911cb0ef41Sopenharmony_ci double extra_bits = 0.0; 921cb0ef41Sopenharmony_ci HistogramDistance histo; 931cb0ef41Sopenharmony_ci HistogramClearDistance(&histo); 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits && 961cb0ef41Sopenharmony_ci orig_params->num_direct_distance_codes == 971cb0ef41Sopenharmony_ci new_params->num_direct_distance_codes) { 981cb0ef41Sopenharmony_ci equal_params = BROTLI_TRUE; 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci for (i = 0; i < num_commands; i++) { 1021cb0ef41Sopenharmony_ci const Command* cmd = &cmds[i]; 1031cb0ef41Sopenharmony_ci if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) { 1041cb0ef41Sopenharmony_ci if (equal_params) { 1051cb0ef41Sopenharmony_ci dist_prefix = cmd->dist_prefix_; 1061cb0ef41Sopenharmony_ci } else { 1071cb0ef41Sopenharmony_ci uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params); 1081cb0ef41Sopenharmony_ci if (distance > new_params->max_distance) { 1091cb0ef41Sopenharmony_ci return BROTLI_FALSE; 1101cb0ef41Sopenharmony_ci } 1111cb0ef41Sopenharmony_ci PrefixEncodeCopyDistance(distance, 1121cb0ef41Sopenharmony_ci new_params->num_direct_distance_codes, 1131cb0ef41Sopenharmony_ci new_params->distance_postfix_bits, 1141cb0ef41Sopenharmony_ci &dist_prefix, 1151cb0ef41Sopenharmony_ci &dist_extra); 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci HistogramAddDistance(&histo, dist_prefix & 0x3FF); 1181cb0ef41Sopenharmony_ci extra_bits += dist_prefix >> 10; 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci *cost = BrotliPopulationCostDistance(&histo) + extra_bits; 1231cb0ef41Sopenharmony_ci return BROTLI_TRUE; 1241cb0ef41Sopenharmony_ci} 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_civoid BrotliBuildMetaBlock(MemoryManager* m, 1271cb0ef41Sopenharmony_ci const uint8_t* ringbuffer, 1281cb0ef41Sopenharmony_ci const size_t pos, 1291cb0ef41Sopenharmony_ci const size_t mask, 1301cb0ef41Sopenharmony_ci BrotliEncoderParams* params, 1311cb0ef41Sopenharmony_ci uint8_t prev_byte, 1321cb0ef41Sopenharmony_ci uint8_t prev_byte2, 1331cb0ef41Sopenharmony_ci Command* cmds, 1341cb0ef41Sopenharmony_ci size_t num_commands, 1351cb0ef41Sopenharmony_ci ContextType literal_context_mode, 1361cb0ef41Sopenharmony_ci MetaBlockSplit* mb) { 1371cb0ef41Sopenharmony_ci /* Histogram ids need to fit in one byte. */ 1381cb0ef41Sopenharmony_ci static const size_t kMaxNumberOfHistograms = 256; 1391cb0ef41Sopenharmony_ci HistogramDistance* distance_histograms; 1401cb0ef41Sopenharmony_ci HistogramLiteral* literal_histograms; 1411cb0ef41Sopenharmony_ci ContextType* literal_context_modes = NULL; 1421cb0ef41Sopenharmony_ci size_t literal_histograms_size; 1431cb0ef41Sopenharmony_ci size_t distance_histograms_size; 1441cb0ef41Sopenharmony_ci size_t i; 1451cb0ef41Sopenharmony_ci size_t literal_context_multiplier = 1; 1461cb0ef41Sopenharmony_ci uint32_t npostfix; 1471cb0ef41Sopenharmony_ci uint32_t ndirect_msb = 0; 1481cb0ef41Sopenharmony_ci BROTLI_BOOL check_orig = BROTLI_TRUE; 1491cb0ef41Sopenharmony_ci double best_dist_cost = 1e99; 1501cb0ef41Sopenharmony_ci BrotliEncoderParams orig_params = *params; 1511cb0ef41Sopenharmony_ci BrotliEncoderParams new_params = *params; 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) { 1541cb0ef41Sopenharmony_ci for (; ndirect_msb < 16; ndirect_msb++) { 1551cb0ef41Sopenharmony_ci uint32_t ndirect = ndirect_msb << npostfix; 1561cb0ef41Sopenharmony_ci BROTLI_BOOL skip; 1571cb0ef41Sopenharmony_ci double dist_cost; 1581cb0ef41Sopenharmony_ci BrotliInitDistanceParams(&new_params, npostfix, ndirect); 1591cb0ef41Sopenharmony_ci if (npostfix == orig_params.dist.distance_postfix_bits && 1601cb0ef41Sopenharmony_ci ndirect == orig_params.dist.num_direct_distance_codes) { 1611cb0ef41Sopenharmony_ci check_orig = BROTLI_FALSE; 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci skip = !ComputeDistanceCost( 1641cb0ef41Sopenharmony_ci cmds, num_commands, 1651cb0ef41Sopenharmony_ci &orig_params.dist, &new_params.dist, &dist_cost); 1661cb0ef41Sopenharmony_ci if (skip || (dist_cost > best_dist_cost)) { 1671cb0ef41Sopenharmony_ci break; 1681cb0ef41Sopenharmony_ci } 1691cb0ef41Sopenharmony_ci best_dist_cost = dist_cost; 1701cb0ef41Sopenharmony_ci params->dist = new_params.dist; 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci if (ndirect_msb > 0) ndirect_msb--; 1731cb0ef41Sopenharmony_ci ndirect_msb /= 2; 1741cb0ef41Sopenharmony_ci } 1751cb0ef41Sopenharmony_ci if (check_orig) { 1761cb0ef41Sopenharmony_ci double dist_cost; 1771cb0ef41Sopenharmony_ci ComputeDistanceCost(cmds, num_commands, 1781cb0ef41Sopenharmony_ci &orig_params.dist, &orig_params.dist, &dist_cost); 1791cb0ef41Sopenharmony_ci if (dist_cost < best_dist_cost) { 1801cb0ef41Sopenharmony_ci /* NB: currently unused; uncomment when more param tuning is added. */ 1811cb0ef41Sopenharmony_ci /* best_dist_cost = dist_cost; */ 1821cb0ef41Sopenharmony_ci params->dist = orig_params.dist; 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci RecomputeDistancePrefixes(cmds, num_commands, 1861cb0ef41Sopenharmony_ci &orig_params.dist, ¶ms->dist); 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci BrotliSplitBlock(m, cmds, num_commands, 1891cb0ef41Sopenharmony_ci ringbuffer, pos, mask, params, 1901cb0ef41Sopenharmony_ci &mb->literal_split, 1911cb0ef41Sopenharmony_ci &mb->command_split, 1921cb0ef41Sopenharmony_ci &mb->distance_split); 1931cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ci if (!params->disable_literal_context_modeling) { 1961cb0ef41Sopenharmony_ci literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS; 1971cb0ef41Sopenharmony_ci literal_context_modes = 1981cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types); 1991cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return; 2001cb0ef41Sopenharmony_ci for (i = 0; i < mb->literal_split.num_types; ++i) { 2011cb0ef41Sopenharmony_ci literal_context_modes[i] = literal_context_mode; 2021cb0ef41Sopenharmony_ci } 2031cb0ef41Sopenharmony_ci } 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci literal_histograms_size = 2061cb0ef41Sopenharmony_ci mb->literal_split.num_types * literal_context_multiplier; 2071cb0ef41Sopenharmony_ci literal_histograms = 2081cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size); 2091cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return; 2101cb0ef41Sopenharmony_ci ClearHistogramsLiteral(literal_histograms, literal_histograms_size); 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ci distance_histograms_size = 2131cb0ef41Sopenharmony_ci mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS; 2141cb0ef41Sopenharmony_ci distance_histograms = 2151cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size); 2161cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return; 2171cb0ef41Sopenharmony_ci ClearHistogramsDistance(distance_histograms, distance_histograms_size); 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci BROTLI_DCHECK(mb->command_histograms == 0); 2201cb0ef41Sopenharmony_ci mb->command_histograms_size = mb->command_split.num_types; 2211cb0ef41Sopenharmony_ci mb->command_histograms = 2221cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size); 2231cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return; 2241cb0ef41Sopenharmony_ci ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size); 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci BrotliBuildHistogramsWithContext(cmds, num_commands, 2271cb0ef41Sopenharmony_ci &mb->literal_split, &mb->command_split, &mb->distance_split, 2281cb0ef41Sopenharmony_ci ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes, 2291cb0ef41Sopenharmony_ci literal_histograms, mb->command_histograms, distance_histograms); 2301cb0ef41Sopenharmony_ci BROTLI_FREE(m, literal_context_modes); 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_ci BROTLI_DCHECK(mb->literal_context_map == 0); 2331cb0ef41Sopenharmony_ci mb->literal_context_map_size = 2341cb0ef41Sopenharmony_ci mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS; 2351cb0ef41Sopenharmony_ci mb->literal_context_map = 2361cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size); 2371cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return; 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci BROTLI_DCHECK(mb->literal_histograms == 0); 2401cb0ef41Sopenharmony_ci mb->literal_histograms_size = mb->literal_context_map_size; 2411cb0ef41Sopenharmony_ci mb->literal_histograms = 2421cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size); 2431cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return; 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size, 2461cb0ef41Sopenharmony_ci kMaxNumberOfHistograms, mb->literal_histograms, 2471cb0ef41Sopenharmony_ci &mb->literal_histograms_size, mb->literal_context_map); 2481cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 2491cb0ef41Sopenharmony_ci BROTLI_FREE(m, literal_histograms); 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci if (params->disable_literal_context_modeling) { 2521cb0ef41Sopenharmony_ci /* Distribute assignment to all contexts. */ 2531cb0ef41Sopenharmony_ci for (i = mb->literal_split.num_types; i != 0;) { 2541cb0ef41Sopenharmony_ci size_t j = 0; 2551cb0ef41Sopenharmony_ci i--; 2561cb0ef41Sopenharmony_ci for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) { 2571cb0ef41Sopenharmony_ci mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] = 2581cb0ef41Sopenharmony_ci mb->literal_context_map[i]; 2591cb0ef41Sopenharmony_ci } 2601cb0ef41Sopenharmony_ci } 2611cb0ef41Sopenharmony_ci } 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci BROTLI_DCHECK(mb->distance_context_map == 0); 2641cb0ef41Sopenharmony_ci mb->distance_context_map_size = 2651cb0ef41Sopenharmony_ci mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS; 2661cb0ef41Sopenharmony_ci mb->distance_context_map = 2671cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size); 2681cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return; 2691cb0ef41Sopenharmony_ci 2701cb0ef41Sopenharmony_ci BROTLI_DCHECK(mb->distance_histograms == 0); 2711cb0ef41Sopenharmony_ci mb->distance_histograms_size = mb->distance_context_map_size; 2721cb0ef41Sopenharmony_ci mb->distance_histograms = 2731cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size); 2741cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return; 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci BrotliClusterHistogramsDistance(m, distance_histograms, 2771cb0ef41Sopenharmony_ci mb->distance_context_map_size, 2781cb0ef41Sopenharmony_ci kMaxNumberOfHistograms, 2791cb0ef41Sopenharmony_ci mb->distance_histograms, 2801cb0ef41Sopenharmony_ci &mb->distance_histograms_size, 2811cb0ef41Sopenharmony_ci mb->distance_context_map); 2821cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 2831cb0ef41Sopenharmony_ci BROTLI_FREE(m, distance_histograms); 2841cb0ef41Sopenharmony_ci} 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci#define FN(X) X ## Literal 2871cb0ef41Sopenharmony_ci#include "./metablock_inc.h" /* NOLINT(build/include) */ 2881cb0ef41Sopenharmony_ci#undef FN 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci#define FN(X) X ## Command 2911cb0ef41Sopenharmony_ci#include "./metablock_inc.h" /* NOLINT(build/include) */ 2921cb0ef41Sopenharmony_ci#undef FN 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci#define FN(X) X ## Distance 2951cb0ef41Sopenharmony_ci#include "./metablock_inc.h" /* NOLINT(build/include) */ 2961cb0ef41Sopenharmony_ci#undef FN 2971cb0ef41Sopenharmony_ci 2981cb0ef41Sopenharmony_ci#define BROTLI_MAX_STATIC_CONTEXTS 13 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_ci/* Greedy block splitter for one block category (literal, command or distance). 3011cb0ef41Sopenharmony_ci Gathers histograms for all context buckets. */ 3021cb0ef41Sopenharmony_citypedef struct ContextBlockSplitter { 3031cb0ef41Sopenharmony_ci /* Alphabet size of particular block category. */ 3041cb0ef41Sopenharmony_ci size_t alphabet_size_; 3051cb0ef41Sopenharmony_ci size_t num_contexts_; 3061cb0ef41Sopenharmony_ci size_t max_block_types_; 3071cb0ef41Sopenharmony_ci /* We collect at least this many symbols for each block. */ 3081cb0ef41Sopenharmony_ci size_t min_block_size_; 3091cb0ef41Sopenharmony_ci /* We merge histograms A and B if 3101cb0ef41Sopenharmony_ci entropy(A+B) < entropy(A) + entropy(B) + split_threshold_, 3111cb0ef41Sopenharmony_ci where A is the current histogram and B is the histogram of the last or the 3121cb0ef41Sopenharmony_ci second last block type. */ 3131cb0ef41Sopenharmony_ci double split_threshold_; 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci size_t num_blocks_; 3161cb0ef41Sopenharmony_ci BlockSplit* split_; /* not owned */ 3171cb0ef41Sopenharmony_ci HistogramLiteral* histograms_; /* not owned */ 3181cb0ef41Sopenharmony_ci size_t* histograms_size_; /* not owned */ 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci /* The number of symbols that we want to collect before deciding on whether 3211cb0ef41Sopenharmony_ci or not to merge the block with a previous one or emit a new block. */ 3221cb0ef41Sopenharmony_ci size_t target_block_size_; 3231cb0ef41Sopenharmony_ci /* The number of symbols in the current histogram. */ 3241cb0ef41Sopenharmony_ci size_t block_size_; 3251cb0ef41Sopenharmony_ci /* Offset of the current histogram. */ 3261cb0ef41Sopenharmony_ci size_t curr_histogram_ix_; 3271cb0ef41Sopenharmony_ci /* Offset of the histograms of the previous two block types. */ 3281cb0ef41Sopenharmony_ci size_t last_histogram_ix_[2]; 3291cb0ef41Sopenharmony_ci /* Entropy of the previous two block types. */ 3301cb0ef41Sopenharmony_ci double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS]; 3311cb0ef41Sopenharmony_ci /* The number of times we merged the current block with the last one. */ 3321cb0ef41Sopenharmony_ci size_t merge_last_count_; 3331cb0ef41Sopenharmony_ci} ContextBlockSplitter; 3341cb0ef41Sopenharmony_ci 3351cb0ef41Sopenharmony_cistatic void InitContextBlockSplitter( 3361cb0ef41Sopenharmony_ci MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size, 3371cb0ef41Sopenharmony_ci size_t num_contexts, size_t min_block_size, double split_threshold, 3381cb0ef41Sopenharmony_ci size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms, 3391cb0ef41Sopenharmony_ci size_t* histograms_size) { 3401cb0ef41Sopenharmony_ci size_t max_num_blocks = num_symbols / min_block_size + 1; 3411cb0ef41Sopenharmony_ci size_t max_num_types; 3421cb0ef41Sopenharmony_ci BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS); 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci self->alphabet_size_ = alphabet_size; 3451cb0ef41Sopenharmony_ci self->num_contexts_ = num_contexts; 3461cb0ef41Sopenharmony_ci self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts; 3471cb0ef41Sopenharmony_ci self->min_block_size_ = min_block_size; 3481cb0ef41Sopenharmony_ci self->split_threshold_ = split_threshold; 3491cb0ef41Sopenharmony_ci self->num_blocks_ = 0; 3501cb0ef41Sopenharmony_ci self->split_ = split; 3511cb0ef41Sopenharmony_ci self->histograms_size_ = histograms_size; 3521cb0ef41Sopenharmony_ci self->target_block_size_ = min_block_size; 3531cb0ef41Sopenharmony_ci self->block_size_ = 0; 3541cb0ef41Sopenharmony_ci self->curr_histogram_ix_ = 0; 3551cb0ef41Sopenharmony_ci self->merge_last_count_ = 0; 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci /* We have to allocate one more histogram than the maximum number of block 3581cb0ef41Sopenharmony_ci types for the current histogram when the meta-block is too big. */ 3591cb0ef41Sopenharmony_ci max_num_types = 3601cb0ef41Sopenharmony_ci BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1); 3611cb0ef41Sopenharmony_ci BROTLI_ENSURE_CAPACITY(m, uint8_t, 3621cb0ef41Sopenharmony_ci split->types, split->types_alloc_size, max_num_blocks); 3631cb0ef41Sopenharmony_ci BROTLI_ENSURE_CAPACITY(m, uint32_t, 3641cb0ef41Sopenharmony_ci split->lengths, split->lengths_alloc_size, max_num_blocks); 3651cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 3661cb0ef41Sopenharmony_ci split->num_blocks = max_num_blocks; 3671cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 3681cb0ef41Sopenharmony_ci BROTLI_DCHECK(*histograms == 0); 3691cb0ef41Sopenharmony_ci *histograms_size = max_num_types * num_contexts; 3701cb0ef41Sopenharmony_ci *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size); 3711cb0ef41Sopenharmony_ci self->histograms_ = *histograms; 3721cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return; 3731cb0ef41Sopenharmony_ci /* Clear only current histogram. */ 3741cb0ef41Sopenharmony_ci ClearHistogramsLiteral(&self->histograms_[0], num_contexts); 3751cb0ef41Sopenharmony_ci self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0; 3761cb0ef41Sopenharmony_ci} 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_ci/* Does either of three things: 3791cb0ef41Sopenharmony_ci (1) emits the current block with a new block type; 3801cb0ef41Sopenharmony_ci (2) emits the current block with the type of the second last block; 3811cb0ef41Sopenharmony_ci (3) merges the current block with the last block. */ 3821cb0ef41Sopenharmony_cistatic void ContextBlockSplitterFinishBlock( 3831cb0ef41Sopenharmony_ci ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) { 3841cb0ef41Sopenharmony_ci BlockSplit* split = self->split_; 3851cb0ef41Sopenharmony_ci const size_t num_contexts = self->num_contexts_; 3861cb0ef41Sopenharmony_ci double* last_entropy = self->last_entropy_; 3871cb0ef41Sopenharmony_ci HistogramLiteral* histograms = self->histograms_; 3881cb0ef41Sopenharmony_ci 3891cb0ef41Sopenharmony_ci if (self->block_size_ < self->min_block_size_) { 3901cb0ef41Sopenharmony_ci self->block_size_ = self->min_block_size_; 3911cb0ef41Sopenharmony_ci } 3921cb0ef41Sopenharmony_ci if (self->num_blocks_ == 0) { 3931cb0ef41Sopenharmony_ci size_t i; 3941cb0ef41Sopenharmony_ci /* Create first block. */ 3951cb0ef41Sopenharmony_ci split->lengths[0] = (uint32_t)self->block_size_; 3961cb0ef41Sopenharmony_ci split->types[0] = 0; 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci for (i = 0; i < num_contexts; ++i) { 3991cb0ef41Sopenharmony_ci last_entropy[i] = 4001cb0ef41Sopenharmony_ci BitsEntropy(histograms[i].data_, self->alphabet_size_); 4011cb0ef41Sopenharmony_ci last_entropy[num_contexts + i] = last_entropy[i]; 4021cb0ef41Sopenharmony_ci } 4031cb0ef41Sopenharmony_ci ++self->num_blocks_; 4041cb0ef41Sopenharmony_ci ++split->num_types; 4051cb0ef41Sopenharmony_ci self->curr_histogram_ix_ += num_contexts; 4061cb0ef41Sopenharmony_ci if (self->curr_histogram_ix_ < *self->histograms_size_) { 4071cb0ef41Sopenharmony_ci ClearHistogramsLiteral( 4081cb0ef41Sopenharmony_ci &self->histograms_[self->curr_histogram_ix_], self->num_contexts_); 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci self->block_size_ = 0; 4111cb0ef41Sopenharmony_ci } else if (self->block_size_ > 0) { 4121cb0ef41Sopenharmony_ci /* Try merging the set of histograms for the current block type with the 4131cb0ef41Sopenharmony_ci respective set of histograms for the last and second last block types. 4141cb0ef41Sopenharmony_ci Decide over the split based on the total reduction of entropy across 4151cb0ef41Sopenharmony_ci all contexts. */ 4161cb0ef41Sopenharmony_ci double entropy[BROTLI_MAX_STATIC_CONTEXTS]; 4171cb0ef41Sopenharmony_ci HistogramLiteral* combined_histo = 4181cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts); 4191cb0ef41Sopenharmony_ci double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS]; 4201cb0ef41Sopenharmony_ci double diff[2] = { 0.0 }; 4211cb0ef41Sopenharmony_ci size_t i; 4221cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return; 4231cb0ef41Sopenharmony_ci for (i = 0; i < num_contexts; ++i) { 4241cb0ef41Sopenharmony_ci size_t curr_histo_ix = self->curr_histogram_ix_ + i; 4251cb0ef41Sopenharmony_ci size_t j; 4261cb0ef41Sopenharmony_ci entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_, 4271cb0ef41Sopenharmony_ci self->alphabet_size_); 4281cb0ef41Sopenharmony_ci for (j = 0; j < 2; ++j) { 4291cb0ef41Sopenharmony_ci size_t jx = j * num_contexts + i; 4301cb0ef41Sopenharmony_ci size_t last_histogram_ix = self->last_histogram_ix_[j] + i; 4311cb0ef41Sopenharmony_ci combined_histo[jx] = histograms[curr_histo_ix]; 4321cb0ef41Sopenharmony_ci HistogramAddHistogramLiteral(&combined_histo[jx], 4331cb0ef41Sopenharmony_ci &histograms[last_histogram_ix]); 4341cb0ef41Sopenharmony_ci combined_entropy[jx] = BitsEntropy( 4351cb0ef41Sopenharmony_ci &combined_histo[jx].data_[0], self->alphabet_size_); 4361cb0ef41Sopenharmony_ci diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx]; 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci } 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci if (split->num_types < self->max_block_types_ && 4411cb0ef41Sopenharmony_ci diff[0] > self->split_threshold_ && 4421cb0ef41Sopenharmony_ci diff[1] > self->split_threshold_) { 4431cb0ef41Sopenharmony_ci /* Create new block. */ 4441cb0ef41Sopenharmony_ci split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; 4451cb0ef41Sopenharmony_ci split->types[self->num_blocks_] = (uint8_t)split->num_types; 4461cb0ef41Sopenharmony_ci self->last_histogram_ix_[1] = self->last_histogram_ix_[0]; 4471cb0ef41Sopenharmony_ci self->last_histogram_ix_[0] = split->num_types * num_contexts; 4481cb0ef41Sopenharmony_ci for (i = 0; i < num_contexts; ++i) { 4491cb0ef41Sopenharmony_ci last_entropy[num_contexts + i] = last_entropy[i]; 4501cb0ef41Sopenharmony_ci last_entropy[i] = entropy[i]; 4511cb0ef41Sopenharmony_ci } 4521cb0ef41Sopenharmony_ci ++self->num_blocks_; 4531cb0ef41Sopenharmony_ci ++split->num_types; 4541cb0ef41Sopenharmony_ci self->curr_histogram_ix_ += num_contexts; 4551cb0ef41Sopenharmony_ci if (self->curr_histogram_ix_ < *self->histograms_size_) { 4561cb0ef41Sopenharmony_ci ClearHistogramsLiteral( 4571cb0ef41Sopenharmony_ci &self->histograms_[self->curr_histogram_ix_], self->num_contexts_); 4581cb0ef41Sopenharmony_ci } 4591cb0ef41Sopenharmony_ci self->block_size_ = 0; 4601cb0ef41Sopenharmony_ci self->merge_last_count_ = 0; 4611cb0ef41Sopenharmony_ci self->target_block_size_ = self->min_block_size_; 4621cb0ef41Sopenharmony_ci } else if (diff[1] < diff[0] - 20.0) { 4631cb0ef41Sopenharmony_ci /* Combine this block with second last block. */ 4641cb0ef41Sopenharmony_ci split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; 4651cb0ef41Sopenharmony_ci split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2]; 4661cb0ef41Sopenharmony_ci BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1); 4671cb0ef41Sopenharmony_ci for (i = 0; i < num_contexts; ++i) { 4681cb0ef41Sopenharmony_ci histograms[self->last_histogram_ix_[0] + i] = 4691cb0ef41Sopenharmony_ci combined_histo[num_contexts + i]; 4701cb0ef41Sopenharmony_ci last_entropy[num_contexts + i] = last_entropy[i]; 4711cb0ef41Sopenharmony_ci last_entropy[i] = combined_entropy[num_contexts + i]; 4721cb0ef41Sopenharmony_ci HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]); 4731cb0ef41Sopenharmony_ci } 4741cb0ef41Sopenharmony_ci ++self->num_blocks_; 4751cb0ef41Sopenharmony_ci self->block_size_ = 0; 4761cb0ef41Sopenharmony_ci self->merge_last_count_ = 0; 4771cb0ef41Sopenharmony_ci self->target_block_size_ = self->min_block_size_; 4781cb0ef41Sopenharmony_ci } else { 4791cb0ef41Sopenharmony_ci /* Combine this block with last block. */ 4801cb0ef41Sopenharmony_ci split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_; 4811cb0ef41Sopenharmony_ci for (i = 0; i < num_contexts; ++i) { 4821cb0ef41Sopenharmony_ci histograms[self->last_histogram_ix_[0] + i] = combined_histo[i]; 4831cb0ef41Sopenharmony_ci last_entropy[i] = combined_entropy[i]; 4841cb0ef41Sopenharmony_ci if (split->num_types == 1) { 4851cb0ef41Sopenharmony_ci last_entropy[num_contexts + i] = last_entropy[i]; 4861cb0ef41Sopenharmony_ci } 4871cb0ef41Sopenharmony_ci HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]); 4881cb0ef41Sopenharmony_ci } 4891cb0ef41Sopenharmony_ci self->block_size_ = 0; 4901cb0ef41Sopenharmony_ci if (++self->merge_last_count_ > 1) { 4911cb0ef41Sopenharmony_ci self->target_block_size_ += self->min_block_size_; 4921cb0ef41Sopenharmony_ci } 4931cb0ef41Sopenharmony_ci } 4941cb0ef41Sopenharmony_ci BROTLI_FREE(m, combined_histo); 4951cb0ef41Sopenharmony_ci } 4961cb0ef41Sopenharmony_ci if (is_final) { 4971cb0ef41Sopenharmony_ci *self->histograms_size_ = split->num_types * num_contexts; 4981cb0ef41Sopenharmony_ci split->num_blocks = self->num_blocks_; 4991cb0ef41Sopenharmony_ci } 5001cb0ef41Sopenharmony_ci} 5011cb0ef41Sopenharmony_ci 5021cb0ef41Sopenharmony_ci/* Adds the next symbol to the current block type and context. When the 5031cb0ef41Sopenharmony_ci current block reaches the target size, decides on merging the block. */ 5041cb0ef41Sopenharmony_cistatic void ContextBlockSplitterAddSymbol( 5051cb0ef41Sopenharmony_ci ContextBlockSplitter* self, MemoryManager* m, 5061cb0ef41Sopenharmony_ci size_t symbol, size_t context) { 5071cb0ef41Sopenharmony_ci HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context], 5081cb0ef41Sopenharmony_ci symbol); 5091cb0ef41Sopenharmony_ci ++self->block_size_; 5101cb0ef41Sopenharmony_ci if (self->block_size_ == self->target_block_size_) { 5111cb0ef41Sopenharmony_ci ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE); 5121cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 5131cb0ef41Sopenharmony_ci } 5141cb0ef41Sopenharmony_ci} 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_cistatic void MapStaticContexts(MemoryManager* m, 5171cb0ef41Sopenharmony_ci size_t num_contexts, 5181cb0ef41Sopenharmony_ci const uint32_t* static_context_map, 5191cb0ef41Sopenharmony_ci MetaBlockSplit* mb) { 5201cb0ef41Sopenharmony_ci size_t i; 5211cb0ef41Sopenharmony_ci BROTLI_DCHECK(mb->literal_context_map == 0); 5221cb0ef41Sopenharmony_ci mb->literal_context_map_size = 5231cb0ef41Sopenharmony_ci mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS; 5241cb0ef41Sopenharmony_ci mb->literal_context_map = 5251cb0ef41Sopenharmony_ci BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size); 5261cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return; 5271cb0ef41Sopenharmony_ci 5281cb0ef41Sopenharmony_ci for (i = 0; i < mb->literal_split.num_types; ++i) { 5291cb0ef41Sopenharmony_ci uint32_t offset = (uint32_t)(i * num_contexts); 5301cb0ef41Sopenharmony_ci size_t j; 5311cb0ef41Sopenharmony_ci for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) { 5321cb0ef41Sopenharmony_ci mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] = 5331cb0ef41Sopenharmony_ci offset + static_context_map[j]; 5341cb0ef41Sopenharmony_ci } 5351cb0ef41Sopenharmony_ci } 5361cb0ef41Sopenharmony_ci} 5371cb0ef41Sopenharmony_ci 5381cb0ef41Sopenharmony_cistatic BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal( 5391cb0ef41Sopenharmony_ci MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask, 5401cb0ef41Sopenharmony_ci uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut, 5411cb0ef41Sopenharmony_ci const size_t num_contexts, const uint32_t* static_context_map, 5421cb0ef41Sopenharmony_ci const Command* commands, size_t n_commands, MetaBlockSplit* mb) { 5431cb0ef41Sopenharmony_ci union { 5441cb0ef41Sopenharmony_ci BlockSplitterLiteral plain; 5451cb0ef41Sopenharmony_ci ContextBlockSplitter ctx; 5461cb0ef41Sopenharmony_ci } lit_blocks; 5471cb0ef41Sopenharmony_ci BlockSplitterCommand cmd_blocks; 5481cb0ef41Sopenharmony_ci BlockSplitterDistance dist_blocks; 5491cb0ef41Sopenharmony_ci size_t num_literals = 0; 5501cb0ef41Sopenharmony_ci size_t i; 5511cb0ef41Sopenharmony_ci for (i = 0; i < n_commands; ++i) { 5521cb0ef41Sopenharmony_ci num_literals += commands[i].insert_len_; 5531cb0ef41Sopenharmony_ci } 5541cb0ef41Sopenharmony_ci 5551cb0ef41Sopenharmony_ci if (num_contexts == 1) { 5561cb0ef41Sopenharmony_ci InitBlockSplitterLiteral(m, &lit_blocks.plain, 256, 512, 400.0, 5571cb0ef41Sopenharmony_ci num_literals, &mb->literal_split, &mb->literal_histograms, 5581cb0ef41Sopenharmony_ci &mb->literal_histograms_size); 5591cb0ef41Sopenharmony_ci } else { 5601cb0ef41Sopenharmony_ci InitContextBlockSplitter(m, &lit_blocks.ctx, 256, num_contexts, 512, 400.0, 5611cb0ef41Sopenharmony_ci num_literals, &mb->literal_split, &mb->literal_histograms, 5621cb0ef41Sopenharmony_ci &mb->literal_histograms_size); 5631cb0ef41Sopenharmony_ci } 5641cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 5651cb0ef41Sopenharmony_ci InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, 1024, 5661cb0ef41Sopenharmony_ci 500.0, n_commands, &mb->command_split, &mb->command_histograms, 5671cb0ef41Sopenharmony_ci &mb->command_histograms_size); 5681cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 5691cb0ef41Sopenharmony_ci InitBlockSplitterDistance(m, &dist_blocks, 64, 512, 100.0, n_commands, 5701cb0ef41Sopenharmony_ci &mb->distance_split, &mb->distance_histograms, 5711cb0ef41Sopenharmony_ci &mb->distance_histograms_size); 5721cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 5731cb0ef41Sopenharmony_ci 5741cb0ef41Sopenharmony_ci for (i = 0; i < n_commands; ++i) { 5751cb0ef41Sopenharmony_ci const Command cmd = commands[i]; 5761cb0ef41Sopenharmony_ci size_t j; 5771cb0ef41Sopenharmony_ci BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_); 5781cb0ef41Sopenharmony_ci for (j = cmd.insert_len_; j != 0; --j) { 5791cb0ef41Sopenharmony_ci uint8_t literal = ringbuffer[pos & mask]; 5801cb0ef41Sopenharmony_ci if (num_contexts == 1) { 5811cb0ef41Sopenharmony_ci BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal); 5821cb0ef41Sopenharmony_ci } else { 5831cb0ef41Sopenharmony_ci size_t context = 5841cb0ef41Sopenharmony_ci BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut); 5851cb0ef41Sopenharmony_ci ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal, 5861cb0ef41Sopenharmony_ci static_context_map[context]); 5871cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 5881cb0ef41Sopenharmony_ci } 5891cb0ef41Sopenharmony_ci prev_byte2 = prev_byte; 5901cb0ef41Sopenharmony_ci prev_byte = literal; 5911cb0ef41Sopenharmony_ci ++pos; 5921cb0ef41Sopenharmony_ci } 5931cb0ef41Sopenharmony_ci pos += CommandCopyLen(&cmd); 5941cb0ef41Sopenharmony_ci if (CommandCopyLen(&cmd)) { 5951cb0ef41Sopenharmony_ci prev_byte2 = ringbuffer[(pos - 2) & mask]; 5961cb0ef41Sopenharmony_ci prev_byte = ringbuffer[(pos - 1) & mask]; 5971cb0ef41Sopenharmony_ci if (cmd.cmd_prefix_ >= 128) { 5981cb0ef41Sopenharmony_ci BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_ & 0x3FF); 5991cb0ef41Sopenharmony_ci } 6001cb0ef41Sopenharmony_ci } 6011cb0ef41Sopenharmony_ci } 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ci if (num_contexts == 1) { 6041cb0ef41Sopenharmony_ci BlockSplitterFinishBlockLiteral( 6051cb0ef41Sopenharmony_ci &lit_blocks.plain, /* is_final = */ BROTLI_TRUE); 6061cb0ef41Sopenharmony_ci } else { 6071cb0ef41Sopenharmony_ci ContextBlockSplitterFinishBlock( 6081cb0ef41Sopenharmony_ci &lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE); 6091cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 6101cb0ef41Sopenharmony_ci } 6111cb0ef41Sopenharmony_ci BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE); 6121cb0ef41Sopenharmony_ci BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE); 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci if (num_contexts > 1) { 6151cb0ef41Sopenharmony_ci MapStaticContexts(m, num_contexts, static_context_map, mb); 6161cb0ef41Sopenharmony_ci } 6171cb0ef41Sopenharmony_ci} 6181cb0ef41Sopenharmony_ci 6191cb0ef41Sopenharmony_civoid BrotliBuildMetaBlockGreedy(MemoryManager* m, 6201cb0ef41Sopenharmony_ci const uint8_t* ringbuffer, 6211cb0ef41Sopenharmony_ci size_t pos, 6221cb0ef41Sopenharmony_ci size_t mask, 6231cb0ef41Sopenharmony_ci uint8_t prev_byte, 6241cb0ef41Sopenharmony_ci uint8_t prev_byte2, 6251cb0ef41Sopenharmony_ci ContextLut literal_context_lut, 6261cb0ef41Sopenharmony_ci size_t num_contexts, 6271cb0ef41Sopenharmony_ci const uint32_t* static_context_map, 6281cb0ef41Sopenharmony_ci const Command* commands, 6291cb0ef41Sopenharmony_ci size_t n_commands, 6301cb0ef41Sopenharmony_ci MetaBlockSplit* mb) { 6311cb0ef41Sopenharmony_ci if (num_contexts == 1) { 6321cb0ef41Sopenharmony_ci BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte, 6331cb0ef41Sopenharmony_ci prev_byte2, literal_context_lut, 1, NULL, commands, n_commands, mb); 6341cb0ef41Sopenharmony_ci } else { 6351cb0ef41Sopenharmony_ci BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte, 6361cb0ef41Sopenharmony_ci prev_byte2, literal_context_lut, num_contexts, static_context_map, 6371cb0ef41Sopenharmony_ci commands, n_commands, mb); 6381cb0ef41Sopenharmony_ci } 6391cb0ef41Sopenharmony_ci} 6401cb0ef41Sopenharmony_ci 6411cb0ef41Sopenharmony_civoid BrotliOptimizeHistograms(uint32_t num_distance_codes, 6421cb0ef41Sopenharmony_ci MetaBlockSplit* mb) { 6431cb0ef41Sopenharmony_ci uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS]; 6441cb0ef41Sopenharmony_ci size_t i; 6451cb0ef41Sopenharmony_ci for (i = 0; i < mb->literal_histograms_size; ++i) { 6461cb0ef41Sopenharmony_ci BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_, 6471cb0ef41Sopenharmony_ci good_for_rle); 6481cb0ef41Sopenharmony_ci } 6491cb0ef41Sopenharmony_ci for (i = 0; i < mb->command_histograms_size; ++i) { 6501cb0ef41Sopenharmony_ci BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS, 6511cb0ef41Sopenharmony_ci mb->command_histograms[i].data_, 6521cb0ef41Sopenharmony_ci good_for_rle); 6531cb0ef41Sopenharmony_ci } 6541cb0ef41Sopenharmony_ci for (i = 0; i < mb->distance_histograms_size; ++i) { 6551cb0ef41Sopenharmony_ci BrotliOptimizeHuffmanCountsForRle(num_distance_codes, 6561cb0ef41Sopenharmony_ci mb->distance_histograms[i].data_, 6571cb0ef41Sopenharmony_ci good_for_rle); 6581cb0ef41Sopenharmony_ci } 6591cb0ef41Sopenharmony_ci} 6601cb0ef41Sopenharmony_ci 6611cb0ef41Sopenharmony_ci#if defined(__cplusplus) || defined(c_plusplus) 6621cb0ef41Sopenharmony_ci} /* extern "C" */ 6631cb0ef41Sopenharmony_ci#endif 664