11cb0ef41Sopenharmony_ci/* NOLINT(build/header_guard) */ 21cb0ef41Sopenharmony_ci/* Copyright 2013 Google Inc. All Rights Reserved. 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ci Distributed under MIT license. 51cb0ef41Sopenharmony_ci See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 61cb0ef41Sopenharmony_ci*/ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci/* template parameters: FN, CODE */ 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#define HistogramType FN(Histogram) 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if 131cb0ef41Sopenharmony_ci it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */ 141cb0ef41Sopenharmony_ciBROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)( 151cb0ef41Sopenharmony_ci const HistogramType* out, const uint32_t* cluster_size, uint32_t idx1, 161cb0ef41Sopenharmony_ci uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs, 171cb0ef41Sopenharmony_ci size_t* num_pairs) CODE({ 181cb0ef41Sopenharmony_ci BROTLI_BOOL is_good_pair = BROTLI_FALSE; 191cb0ef41Sopenharmony_ci HistogramPair p; 201cb0ef41Sopenharmony_ci p.idx1 = p.idx2 = 0; 211cb0ef41Sopenharmony_ci p.cost_diff = p.cost_combo = 0; 221cb0ef41Sopenharmony_ci if (idx1 == idx2) { 231cb0ef41Sopenharmony_ci return; 241cb0ef41Sopenharmony_ci } 251cb0ef41Sopenharmony_ci if (idx2 < idx1) { 261cb0ef41Sopenharmony_ci uint32_t t = idx2; 271cb0ef41Sopenharmony_ci idx2 = idx1; 281cb0ef41Sopenharmony_ci idx1 = t; 291cb0ef41Sopenharmony_ci } 301cb0ef41Sopenharmony_ci p.idx1 = idx1; 311cb0ef41Sopenharmony_ci p.idx2 = idx2; 321cb0ef41Sopenharmony_ci p.cost_diff = 0.5 * ClusterCostDiff(cluster_size[idx1], cluster_size[idx2]); 331cb0ef41Sopenharmony_ci p.cost_diff -= out[idx1].bit_cost_; 341cb0ef41Sopenharmony_ci p.cost_diff -= out[idx2].bit_cost_; 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci if (out[idx1].total_count_ == 0) { 371cb0ef41Sopenharmony_ci p.cost_combo = out[idx2].bit_cost_; 381cb0ef41Sopenharmony_ci is_good_pair = BROTLI_TRUE; 391cb0ef41Sopenharmony_ci } else if (out[idx2].total_count_ == 0) { 401cb0ef41Sopenharmony_ci p.cost_combo = out[idx1].bit_cost_; 411cb0ef41Sopenharmony_ci is_good_pair = BROTLI_TRUE; 421cb0ef41Sopenharmony_ci } else { 431cb0ef41Sopenharmony_ci double threshold = *num_pairs == 0 ? 1e99 : 441cb0ef41Sopenharmony_ci BROTLI_MAX(double, 0.0, pairs[0].cost_diff); 451cb0ef41Sopenharmony_ci HistogramType combo = out[idx1]; 461cb0ef41Sopenharmony_ci double cost_combo; 471cb0ef41Sopenharmony_ci FN(HistogramAddHistogram)(&combo, &out[idx2]); 481cb0ef41Sopenharmony_ci cost_combo = FN(BrotliPopulationCost)(&combo); 491cb0ef41Sopenharmony_ci if (cost_combo < threshold - p.cost_diff) { 501cb0ef41Sopenharmony_ci p.cost_combo = cost_combo; 511cb0ef41Sopenharmony_ci is_good_pair = BROTLI_TRUE; 521cb0ef41Sopenharmony_ci } 531cb0ef41Sopenharmony_ci } 541cb0ef41Sopenharmony_ci if (is_good_pair) { 551cb0ef41Sopenharmony_ci p.cost_diff += p.cost_combo; 561cb0ef41Sopenharmony_ci if (*num_pairs > 0 && HistogramPairIsLess(&pairs[0], &p)) { 571cb0ef41Sopenharmony_ci /* Replace the top of the queue if needed. */ 581cb0ef41Sopenharmony_ci if (*num_pairs < max_num_pairs) { 591cb0ef41Sopenharmony_ci pairs[*num_pairs] = pairs[0]; 601cb0ef41Sopenharmony_ci ++(*num_pairs); 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci pairs[0] = p; 631cb0ef41Sopenharmony_ci } else if (*num_pairs < max_num_pairs) { 641cb0ef41Sopenharmony_ci pairs[*num_pairs] = p; 651cb0ef41Sopenharmony_ci ++(*num_pairs); 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci } 681cb0ef41Sopenharmony_ci}) 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ciBROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out, 711cb0ef41Sopenharmony_ci uint32_t* cluster_size, 721cb0ef41Sopenharmony_ci uint32_t* symbols, 731cb0ef41Sopenharmony_ci uint32_t* clusters, 741cb0ef41Sopenharmony_ci HistogramPair* pairs, 751cb0ef41Sopenharmony_ci size_t num_clusters, 761cb0ef41Sopenharmony_ci size_t symbols_size, 771cb0ef41Sopenharmony_ci size_t max_clusters, 781cb0ef41Sopenharmony_ci size_t max_num_pairs) CODE({ 791cb0ef41Sopenharmony_ci double cost_diff_threshold = 0.0; 801cb0ef41Sopenharmony_ci size_t min_cluster_size = 1; 811cb0ef41Sopenharmony_ci size_t num_pairs = 0; 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci { 841cb0ef41Sopenharmony_ci /* We maintain a vector of histogram pairs, with the property that the pair 851cb0ef41Sopenharmony_ci with the maximum bit cost reduction is the first. */ 861cb0ef41Sopenharmony_ci size_t idx1; 871cb0ef41Sopenharmony_ci for (idx1 = 0; idx1 < num_clusters; ++idx1) { 881cb0ef41Sopenharmony_ci size_t idx2; 891cb0ef41Sopenharmony_ci for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) { 901cb0ef41Sopenharmony_ci FN(BrotliCompareAndPushToQueue)(out, cluster_size, clusters[idx1], 911cb0ef41Sopenharmony_ci clusters[idx2], max_num_pairs, &pairs[0], &num_pairs); 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci while (num_clusters > min_cluster_size) { 971cb0ef41Sopenharmony_ci uint32_t best_idx1; 981cb0ef41Sopenharmony_ci uint32_t best_idx2; 991cb0ef41Sopenharmony_ci size_t i; 1001cb0ef41Sopenharmony_ci if (pairs[0].cost_diff >= cost_diff_threshold) { 1011cb0ef41Sopenharmony_ci cost_diff_threshold = 1e99; 1021cb0ef41Sopenharmony_ci min_cluster_size = max_clusters; 1031cb0ef41Sopenharmony_ci continue; 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci /* Take the best pair from the top of heap. */ 1061cb0ef41Sopenharmony_ci best_idx1 = pairs[0].idx1; 1071cb0ef41Sopenharmony_ci best_idx2 = pairs[0].idx2; 1081cb0ef41Sopenharmony_ci FN(HistogramAddHistogram)(&out[best_idx1], &out[best_idx2]); 1091cb0ef41Sopenharmony_ci out[best_idx1].bit_cost_ = pairs[0].cost_combo; 1101cb0ef41Sopenharmony_ci cluster_size[best_idx1] += cluster_size[best_idx2]; 1111cb0ef41Sopenharmony_ci for (i = 0; i < symbols_size; ++i) { 1121cb0ef41Sopenharmony_ci if (symbols[i] == best_idx2) { 1131cb0ef41Sopenharmony_ci symbols[i] = best_idx1; 1141cb0ef41Sopenharmony_ci } 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci for (i = 0; i < num_clusters; ++i) { 1171cb0ef41Sopenharmony_ci if (clusters[i] == best_idx2) { 1181cb0ef41Sopenharmony_ci memmove(&clusters[i], &clusters[i + 1], 1191cb0ef41Sopenharmony_ci (num_clusters - i - 1) * sizeof(clusters[0])); 1201cb0ef41Sopenharmony_ci break; 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci } 1231cb0ef41Sopenharmony_ci --num_clusters; 1241cb0ef41Sopenharmony_ci { 1251cb0ef41Sopenharmony_ci /* Remove pairs intersecting the just combined best pair. */ 1261cb0ef41Sopenharmony_ci size_t copy_to_idx = 0; 1271cb0ef41Sopenharmony_ci for (i = 0; i < num_pairs; ++i) { 1281cb0ef41Sopenharmony_ci HistogramPair* p = &pairs[i]; 1291cb0ef41Sopenharmony_ci if (p->idx1 == best_idx1 || p->idx2 == best_idx1 || 1301cb0ef41Sopenharmony_ci p->idx1 == best_idx2 || p->idx2 == best_idx2) { 1311cb0ef41Sopenharmony_ci /* Remove invalid pair from the queue. */ 1321cb0ef41Sopenharmony_ci continue; 1331cb0ef41Sopenharmony_ci } 1341cb0ef41Sopenharmony_ci if (HistogramPairIsLess(&pairs[0], p)) { 1351cb0ef41Sopenharmony_ci /* Replace the top of the queue if needed. */ 1361cb0ef41Sopenharmony_ci HistogramPair front = pairs[0]; 1371cb0ef41Sopenharmony_ci pairs[0] = *p; 1381cb0ef41Sopenharmony_ci pairs[copy_to_idx] = front; 1391cb0ef41Sopenharmony_ci } else { 1401cb0ef41Sopenharmony_ci pairs[copy_to_idx] = *p; 1411cb0ef41Sopenharmony_ci } 1421cb0ef41Sopenharmony_ci ++copy_to_idx; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci num_pairs = copy_to_idx; 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci /* Push new pairs formed with the combined histogram to the heap. */ 1481cb0ef41Sopenharmony_ci for (i = 0; i < num_clusters; ++i) { 1491cb0ef41Sopenharmony_ci FN(BrotliCompareAndPushToQueue)(out, cluster_size, best_idx1, clusters[i], 1501cb0ef41Sopenharmony_ci max_num_pairs, &pairs[0], &num_pairs); 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci return num_clusters; 1541cb0ef41Sopenharmony_ci}) 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci/* What is the bit cost of moving histogram from cur_symbol to candidate. */ 1571cb0ef41Sopenharmony_ciBROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)( 1581cb0ef41Sopenharmony_ci const HistogramType* histogram, const HistogramType* candidate) CODE({ 1591cb0ef41Sopenharmony_ci if (histogram->total_count_ == 0) { 1601cb0ef41Sopenharmony_ci return 0.0; 1611cb0ef41Sopenharmony_ci } else { 1621cb0ef41Sopenharmony_ci HistogramType tmp = *histogram; 1631cb0ef41Sopenharmony_ci FN(HistogramAddHistogram)(&tmp, candidate); 1641cb0ef41Sopenharmony_ci return FN(BrotliPopulationCost)(&tmp) - candidate->bit_cost_; 1651cb0ef41Sopenharmony_ci } 1661cb0ef41Sopenharmony_ci}) 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci/* Find the best 'out' histogram for each of the 'in' histograms. 1691cb0ef41Sopenharmony_ci When called, clusters[0..num_clusters) contains the unique values from 1701cb0ef41Sopenharmony_ci symbols[0..in_size), but this property is not preserved in this function. 1711cb0ef41Sopenharmony_ci Note: we assume that out[]->bit_cost_ is already up-to-date. */ 1721cb0ef41Sopenharmony_ciBROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in, 1731cb0ef41Sopenharmony_ci size_t in_size, const uint32_t* clusters, size_t num_clusters, 1741cb0ef41Sopenharmony_ci HistogramType* out, uint32_t* symbols) CODE({ 1751cb0ef41Sopenharmony_ci size_t i; 1761cb0ef41Sopenharmony_ci for (i = 0; i < in_size; ++i) { 1771cb0ef41Sopenharmony_ci uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1]; 1781cb0ef41Sopenharmony_ci double best_bits = 1791cb0ef41Sopenharmony_ci FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out]); 1801cb0ef41Sopenharmony_ci size_t j; 1811cb0ef41Sopenharmony_ci for (j = 0; j < num_clusters; ++j) { 1821cb0ef41Sopenharmony_ci const double cur_bits = 1831cb0ef41Sopenharmony_ci FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]]); 1841cb0ef41Sopenharmony_ci if (cur_bits < best_bits) { 1851cb0ef41Sopenharmony_ci best_bits = cur_bits; 1861cb0ef41Sopenharmony_ci best_out = clusters[j]; 1871cb0ef41Sopenharmony_ci } 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci symbols[i] = best_out; 1901cb0ef41Sopenharmony_ci } 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci /* Recompute each out based on raw and symbols. */ 1931cb0ef41Sopenharmony_ci for (i = 0; i < num_clusters; ++i) { 1941cb0ef41Sopenharmony_ci FN(HistogramClear)(&out[clusters[i]]); 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci for (i = 0; i < in_size; ++i) { 1971cb0ef41Sopenharmony_ci FN(HistogramAddHistogram)(&out[symbols[i]], &in[i]); 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci}) 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci/* Reorders elements of the out[0..length) array and changes values in 2021cb0ef41Sopenharmony_ci symbols[0..length) array in the following way: 2031cb0ef41Sopenharmony_ci * when called, symbols[] contains indexes into out[], and has N unique 2041cb0ef41Sopenharmony_ci values (possibly N < length) 2051cb0ef41Sopenharmony_ci * on return, symbols'[i] = f(symbols[i]) and 2061cb0ef41Sopenharmony_ci out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length, 2071cb0ef41Sopenharmony_ci where f is a bijection between the range of symbols[] and [0..N), and 2081cb0ef41Sopenharmony_ci the first occurrences of values in symbols'[i] come in consecutive 2091cb0ef41Sopenharmony_ci increasing order. 2101cb0ef41Sopenharmony_ci Returns N, the number of unique values in symbols[]. */ 2111cb0ef41Sopenharmony_ciBROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m, 2121cb0ef41Sopenharmony_ci HistogramType* out, uint32_t* symbols, size_t length) CODE({ 2131cb0ef41Sopenharmony_ci static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX; 2141cb0ef41Sopenharmony_ci uint32_t* new_index = BROTLI_ALLOC(m, uint32_t, length); 2151cb0ef41Sopenharmony_ci uint32_t next_index; 2161cb0ef41Sopenharmony_ci HistogramType* tmp; 2171cb0ef41Sopenharmony_ci size_t i; 2181cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0; 2191cb0ef41Sopenharmony_ci for (i = 0; i < length; ++i) { 2201cb0ef41Sopenharmony_ci new_index[i] = kInvalidIndex; 2211cb0ef41Sopenharmony_ci } 2221cb0ef41Sopenharmony_ci next_index = 0; 2231cb0ef41Sopenharmony_ci for (i = 0; i < length; ++i) { 2241cb0ef41Sopenharmony_ci if (new_index[symbols[i]] == kInvalidIndex) { 2251cb0ef41Sopenharmony_ci new_index[symbols[i]] = next_index; 2261cb0ef41Sopenharmony_ci ++next_index; 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci } 2291cb0ef41Sopenharmony_ci /* TODO: by using idea of "cycle-sort" we can avoid allocation of 2301cb0ef41Sopenharmony_ci tmp and reduce the number of copying by the factor of 2. */ 2311cb0ef41Sopenharmony_ci tmp = BROTLI_ALLOC(m, HistogramType, next_index); 2321cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0; 2331cb0ef41Sopenharmony_ci next_index = 0; 2341cb0ef41Sopenharmony_ci for (i = 0; i < length; ++i) { 2351cb0ef41Sopenharmony_ci if (new_index[symbols[i]] == next_index) { 2361cb0ef41Sopenharmony_ci tmp[next_index] = out[symbols[i]]; 2371cb0ef41Sopenharmony_ci ++next_index; 2381cb0ef41Sopenharmony_ci } 2391cb0ef41Sopenharmony_ci symbols[i] = new_index[symbols[i]]; 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci BROTLI_FREE(m, new_index); 2421cb0ef41Sopenharmony_ci for (i = 0; i < next_index; ++i) { 2431cb0ef41Sopenharmony_ci out[i] = tmp[i]; 2441cb0ef41Sopenharmony_ci } 2451cb0ef41Sopenharmony_ci BROTLI_FREE(m, tmp); 2461cb0ef41Sopenharmony_ci return next_index; 2471cb0ef41Sopenharmony_ci}) 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ciBROTLI_INTERNAL void FN(BrotliClusterHistograms)( 2501cb0ef41Sopenharmony_ci MemoryManager* m, const HistogramType* in, const size_t in_size, 2511cb0ef41Sopenharmony_ci size_t max_histograms, HistogramType* out, size_t* out_size, 2521cb0ef41Sopenharmony_ci uint32_t* histogram_symbols) CODE({ 2531cb0ef41Sopenharmony_ci uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, in_size); 2541cb0ef41Sopenharmony_ci uint32_t* clusters = BROTLI_ALLOC(m, uint32_t, in_size); 2551cb0ef41Sopenharmony_ci size_t num_clusters = 0; 2561cb0ef41Sopenharmony_ci const size_t max_input_histograms = 64; 2571cb0ef41Sopenharmony_ci size_t pairs_capacity = max_input_histograms * max_input_histograms / 2; 2581cb0ef41Sopenharmony_ci /* For the first pass of clustering, we allow all pairs. */ 2591cb0ef41Sopenharmony_ci HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1); 2601cb0ef41Sopenharmony_ci size_t i; 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) || 2631cb0ef41Sopenharmony_ci BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) { 2641cb0ef41Sopenharmony_ci return; 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ci for (i = 0; i < in_size; ++i) { 2681cb0ef41Sopenharmony_ci cluster_size[i] = 1; 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci 2711cb0ef41Sopenharmony_ci for (i = 0; i < in_size; ++i) { 2721cb0ef41Sopenharmony_ci out[i] = in[i]; 2731cb0ef41Sopenharmony_ci out[i].bit_cost_ = FN(BrotliPopulationCost)(&in[i]); 2741cb0ef41Sopenharmony_ci histogram_symbols[i] = (uint32_t)i; 2751cb0ef41Sopenharmony_ci } 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci for (i = 0; i < in_size; i += max_input_histograms) { 2781cb0ef41Sopenharmony_ci size_t num_to_combine = 2791cb0ef41Sopenharmony_ci BROTLI_MIN(size_t, in_size - i, max_input_histograms); 2801cb0ef41Sopenharmony_ci size_t num_new_clusters; 2811cb0ef41Sopenharmony_ci size_t j; 2821cb0ef41Sopenharmony_ci for (j = 0; j < num_to_combine; ++j) { 2831cb0ef41Sopenharmony_ci clusters[num_clusters + j] = (uint32_t)(i + j); 2841cb0ef41Sopenharmony_ci } 2851cb0ef41Sopenharmony_ci num_new_clusters = 2861cb0ef41Sopenharmony_ci FN(BrotliHistogramCombine)(out, cluster_size, 2871cb0ef41Sopenharmony_ci &histogram_symbols[i], 2881cb0ef41Sopenharmony_ci &clusters[num_clusters], pairs, 2891cb0ef41Sopenharmony_ci num_to_combine, num_to_combine, 2901cb0ef41Sopenharmony_ci max_histograms, pairs_capacity); 2911cb0ef41Sopenharmony_ci num_clusters += num_new_clusters; 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci { 2951cb0ef41Sopenharmony_ci /* For the second pass, we limit the total number of histogram pairs. 2961cb0ef41Sopenharmony_ci After this limit is reached, we only keep searching for the best pair. */ 2971cb0ef41Sopenharmony_ci size_t max_num_pairs = BROTLI_MIN(size_t, 2981cb0ef41Sopenharmony_ci 64 * num_clusters, (num_clusters / 2) * num_clusters); 2991cb0ef41Sopenharmony_ci BROTLI_ENSURE_CAPACITY( 3001cb0ef41Sopenharmony_ci m, HistogramPair, pairs, pairs_capacity, max_num_pairs + 1); 3011cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 3021cb0ef41Sopenharmony_ci 3031cb0ef41Sopenharmony_ci /* Collapse similar histograms. */ 3041cb0ef41Sopenharmony_ci num_clusters = FN(BrotliHistogramCombine)(out, cluster_size, 3051cb0ef41Sopenharmony_ci histogram_symbols, clusters, 3061cb0ef41Sopenharmony_ci pairs, num_clusters, in_size, 3071cb0ef41Sopenharmony_ci max_histograms, max_num_pairs); 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci BROTLI_FREE(m, pairs); 3101cb0ef41Sopenharmony_ci BROTLI_FREE(m, cluster_size); 3111cb0ef41Sopenharmony_ci /* Find the optimal map from original histograms to the final ones. */ 3121cb0ef41Sopenharmony_ci FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters, 3131cb0ef41Sopenharmony_ci out, histogram_symbols); 3141cb0ef41Sopenharmony_ci BROTLI_FREE(m, clusters); 3151cb0ef41Sopenharmony_ci /* Convert the context map to a canonical form. */ 3161cb0ef41Sopenharmony_ci *out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size); 3171cb0ef41Sopenharmony_ci if (BROTLI_IS_OOM(m)) return; 3181cb0ef41Sopenharmony_ci}) 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci#undef HistogramType 321