Coverage Report

Created: 2026-09-13 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/lib/jxl/enc_ans_params.h
Line
Count
Source
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#ifndef LIB_JXL_ENC_ANS_PARAMS_H_
7
#define LIB_JXL_ENC_ANS_PARAMS_H_
8
9
// Encoder-only parameter needed for ANS entropy encoding methods.
10
11
#include <cstdint>
12
#include <cstdlib>
13
#include <utility>
14
#include <vector>
15
16
#include "lib/jxl/ans_common.h"
17
#include "lib/jxl/base/common.h"
18
#include "lib/jxl/base/status.h"
19
#include "lib/jxl/common.h"
20
#include "lib/jxl/dec_ans.h"
21
22
namespace jxl {
23
24
// Forward declaration to break include cycle.
25
struct CompressParams;
26
27
// RebalanceHistogram requires a signed type.
28
using ANSHistBin = int32_t;
29
30
struct HistogramParams {
31
  enum class ClusteringType {
32
    kFastest,  // Only 4 clusters.
33
    kFast,
34
    kBest,
35
  };
36
37
  enum class HybridUintMethod {
38
    kNone,        // just use kHybridUint420Config.
39
    k000,         // force the fastest option.
40
    kFast,        // just try a couple of options.
41
    kContextMap,  // fast choice for ctx map.
42
    kBest,
43
  };
44
45
  enum class LZ77Method {
46
    kNone,          // do not try lz77.
47
    kRLE,           // only try doing RLE.
48
    kLZ77b1w3f,     // lz77 fast without runtime cost comparison
49
    kLZ77b3w3f,     // lz77
50
    kLZ77b7w3f,     // lz77
51
    kLZ77b15w3f,    // lz77
52
    kLZ77b31w3f,    // lz77 slow
53
    kLZ77b1w3t,     // lz77 fast with runtime cost comparison (almost always worse)
54
    kLZ77b3w3t,     // lz77
55
    kLZ77b7w3t,     // lz77
56
    kLZ77b15w3t,    // lz77
57
    kLZ77b31w3t,    // lz77 slow
58
    kOptc1,         // optimal-matching LZ77 fast.
59
    kOptc3,         // optimal-matching LZ77
60
    kOptc8,         // optimal-matching LZ77
61
    kOptc256,       // optimal-matching LZ77 parsing big chain length.
62
  };
63
64
  enum class ANSHistogramStrategy {
65
    kFast,         // Only try some methods, early exit.
66
    kApproximate,  // Only try some methods.
67
    kPrecise,      // Try all methods.
68
  };
69
70
90.8k
  HistogramParams() = default;
71
72
2.84k
  HistogramParams(SpeedTier tier, size_t num_ctx) {
73
2.84k
    if (tier > SpeedTier::kFalcon) {
74
0
      clustering = ClusteringType::kFastest;
75
0
      lz77_method = LZ77Method::kNone;
76
2.84k
    } else if (tier > SpeedTier::kTortoise) {
77
2.84k
      clustering = ClusteringType::kFast;
78
2.84k
    } else {
79
0
      clustering = ClusteringType::kBest;
80
0
    }
81
2.84k
    if (tier > SpeedTier::kTortoise) {
82
2.84k
      uint_method = HybridUintMethod::kNone;
83
2.84k
    }
84
2.84k
    if (tier >= SpeedTier::kSquirrel) {
85
2.84k
      ans_histogram_strategy = ANSHistogramStrategy::kApproximate;
86
2.84k
    }
87
2.84k
  }
88
89
  static HistogramParams ForModular(
90
      const CompressParams& cparams,
91
      const std::vector<uint8_t>& extra_dc_precision, bool streaming_mode);
92
93
96.2k
  HybridUintConfig UintConfig() const {
94
96.2k
    if (uint_method == HistogramParams::HybridUintMethod::kContextMap) {
95
65.5k
      return HybridUintConfig(2, 0, 1);
96
65.5k
    }
97
30.7k
    if (uint_method == HistogramParams::HybridUintMethod::k000) {
98
0
      return HybridUintConfig(0, 0, 0);
99
0
    }
100
    // Default config for clustering.
101
30.7k
    return HybridUintConfig();
102
30.7k
  }
103
104
  ClusteringType clustering = ClusteringType::kBest;
105
  HybridUintMethod uint_method = HybridUintMethod::kBest;
106
  LZ77Method lz77_method = LZ77Method::kRLE;
107
  ANSHistogramStrategy ans_histogram_strategy = ANSHistogramStrategy::kPrecise;
108
  std::vector<size_t> image_widths;
109
  size_t max_histograms = ~0;
110
  bool force_huffman = false;
111
  bool initialize_global_state = true;
112
  bool streaming_mode = false;
113
  bool add_missing_symbols = false;
114
  bool add_fixed_histograms = false;
115
};
116
117
struct Histogram {
118
16.2M
  Histogram() = default;
119
120
0
  explicit Histogram(size_t length) { EnsureCapacity(length); }
121
122
  // Create flat histogram
123
184
  static Histogram Flat(int length, int total_count) {
124
184
    Histogram flat;
125
184
    flat.counts = CreateFlatHistogram(length, total_count);
126
184
    flat.total_count = static_cast<size_t>(total_count);
127
184
    return flat;
128
184
  }
129
60.0k
  void Clear() {
130
60.0k
    counts.clear();
131
60.0k
    total_count = 0;
132
60.0k
    entropy = 0.0;
133
60.0k
  }
134
462M
  void Add(size_t symbol) {
135
462M
    if (counts.size() <= symbol) {
136
3.27M
      counts.resize(DivCeil(symbol + 1, kRounding) * kRounding);
137
3.27M
    }
138
462M
    ++counts[symbol];
139
462M
    ++total_count;
140
462M
  }
141
142
  // Use this before FastAdd sequence.
143
583k
  void EnsureCapacity(size_t length) {
144
583k
    counts.resize(DivCeil(length, kRounding) * kRounding);
145
583k
  }
146
  // Just increment symbol counter; caller must stretch Histogram beforehead.
147
728M
  void FastAdd(size_t symbol) { (*(counts.data() + symbol))++; }
148
  // Should be called after sequence of FastAdd to actualize total_count.
149
  void Condition();
150
151
1.79M
  void AddHistogram(const Histogram& other) {
152
1.79M
    if (other.counts.size() > counts.size()) {
153
66.8k
      counts.resize(other.counts.size());
154
66.8k
    }
155
32.7M
    for (size_t i = 0; i < other.counts.size(); ++i) {
156
30.9M
      counts[i] += other.counts[i];
157
30.9M
    }
158
1.79M
    total_count += other.total_count;
159
1.79M
  }
160
2.05M
  size_t alphabet_size() const {
161
9.43M
    for (int i = counts.size() - 1; i >= 0; --i) {
162
9.43M
      if (counts[i] > 0) {
163
2.05M
        return i + 1;
164
2.05M
      }
165
9.43M
    }
166
111
    return 0;
167
2.05M
  }
168
169
88.1k
  size_t MaxSymbol() const {
170
88.1k
    if (total_count == 0) return 0;
171
390k
    for (int i = counts.size() - 1; i > 0; --i) {
172
389k
      if (counts[i]) return i;
173
389k
    }
174
1.01k
    return 0;
175
88.1k
  }
176
177
  // Returns an estimate of the number of bits required to encode the given
178
  // histogram (header bits plus data bits).
179
  StatusOr<float> ANSPopulationCost() const;
180
181
  float ShannonEntropy() const;
182
183
181k
  void swap(Histogram& other) {
184
181k
    counts.swap(other.counts);
185
181k
    std::swap(total_count, other.total_count);
186
181k
    std::swap(entropy, other.entropy);
187
181k
  }
188
189
  std::vector<ANSHistBin> counts;
190
  size_t total_count = 0;
191
  mutable float entropy = 0;  // WARNING: not kept up-to-date.
192
  static constexpr size_t kRounding = 8;
193
};
194
195
}  // namespace jxl
196
197
#endif  // LIB_JXL_ENC_ANS_PARAMS_H_