Coverage Report

Created: 2025-11-24 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brunsli/c/dec/histogram_decode.cc
Line
Count
Source
1
// Copyright (c) Google LLC 2019
2
//
3
// Use of this source code is governed by an MIT-style
4
// license that can be found in the LICENSE file or at
5
// https://opensource.org/licenses/MIT.
6
7
#include "./histogram_decode.h"
8
9
#include "../common/ans_params.h"
10
#include "../common/histogram.h"
11
#include "../common/platform.h"
12
#include <brunsli/types.h>
13
#include "./bit_reader.h"
14
15
namespace brunsli {
16
17
namespace {
18
19
// Binary trees; positive - offset to child nodes; other - minus leaf value.
20
// 3-8 bits encoding value 3..18.
21
const int8_t kLengthTree[] = {1, 2, 3, 4, 5, 6, 7, -10, -11, -12, -13,
22
  -14, -15, 2, 3, -9, -16, 2, 3, -8, -17, 2, 3, -5, -6, -7, 1, -18, 1, -3, -4};
23
// 2..6 bits encoding value 0..10.
24
const int8_t kLogCountTree[] = {1, 2, 3, -6, 3, 4, 5, -4, -5, -7, -8, 2,
25
  3, -1, -2, -3, 1, 0, 1, -9, -10};
26
27
50.1k
size_t ReadShortHuffmanCode(BrunsliBitReader* br, const int8_t* tree) {
28
50.1k
  size_t pos = 0;
29
50.1k
  int8_t delta = 1;
30
196k
  while (delta > 0) {
31
145k
    pos += delta + BrunsliBitReaderRead(br, 1);
32
145k
    delta = tree[pos];
33
145k
  }
34
50.1k
  return static_cast<size_t>(-delta);
35
50.1k
}
36
37
}  // namespace
38
39
bool ReadHistogram(uint32_t precision_bits, std::vector<uint32_t>* counts,
40
22.6k
                   BrunsliBitReader* br) {
41
22.6k
  BRUNSLI_DCHECK(!counts->empty());
42
22.6k
  uint32_t space = 1u << precision_bits;
43
22.6k
  const size_t length = counts->size();
44
22.6k
  std::fill(counts->begin(), counts->end(), 0);
45
22.6k
  uint32_t* histogram = counts->data();
46
22.6k
  int simple_code = BrunsliBitReaderRead(br, 1);
47
22.6k
  if (simple_code == 1) {
48
18.6k
    size_t max_bits_counter = length - 1;
49
18.6k
    uint32_t max_bits = 0;
50
18.6k
    int symbols[2] = {0};
51
18.6k
    const size_t num_symbols = BrunsliBitReaderRead(br, 1) + 1u;
52
111k
    while (max_bits_counter) {
53
93.1k
      max_bits_counter >>= 1;
54
93.1k
      ++max_bits;
55
93.1k
    }
56
43.0k
    for (size_t i = 0; i < num_symbols; ++i) {
57
24.4k
      symbols[i] = BrunsliBitReaderRead(br, max_bits) % length;
58
24.4k
    }
59
18.6k
    if (num_symbols == 1) {
60
12.8k
      histogram[symbols[0]] = space;
61
12.8k
    } else {
62
5.80k
      if (symbols[0] == symbols[1]) {  // corrupt data
63
23
        return false;
64
23
      }
65
5.78k
      uint32_t value = BrunsliBitReaderRead(br, precision_bits);
66
5.78k
      histogram[symbols[0]] = value;
67
5.78k
      histogram[symbols[1]] = space - value;
68
5.78k
    }
69
18.6k
  } else {
70
4.04k
    size_t real_length = ReadShortHuffmanCode(br, kLengthTree);
71
4.04k
    uint32_t total_count = 0;
72
4.04k
    uint32_t log_counts[BRUNSLI_ANS_MAX_SYMBOLS];
73
4.04k
    size_t omit_pos = 0;
74
4.04k
    BRUNSLI_DCHECK(real_length > 2);
75
50.1k
    for (size_t i = 0; i < real_length; ++i) {
76
46.0k
      log_counts[i] =
77
46.0k
          static_cast<uint32_t>(ReadShortHuffmanCode(br, kLogCountTree));
78
46.0k
      if (log_counts[i] > log_counts[omit_pos]) omit_pos = i;
79
46.0k
    }
80
4.04k
    BRUNSLI_DCHECK(omit_pos >= 0);
81
50.1k
    for (size_t i = 0; i < real_length; ++i) {
82
46.0k
      uint32_t code = log_counts[i];
83
46.0k
      if (i == omit_pos) {
84
4.04k
        continue;
85
42.0k
      } else if (code == 0) {
86
1.60k
        continue;
87
40.4k
      } else if (code == 1) {
88
3.25k
        histogram[i] = 1;
89
37.1k
      } else {
90
37.1k
        uint32_t bit_count = GetPopulationCountPrecision(code - 1);
91
37.1k
        histogram[i] = (1u << (code - 1)) + (BrunsliBitReaderRead(br, bit_count)
92
37.1k
                                             << (code - 1 - bit_count));
93
37.1k
      }
94
40.4k
      total_count += histogram[i];
95
40.4k
    }
96
4.04k
    if (total_count >= space) {
97
      // The histogram we've read sums to more than total_count (including at
98
      // least 1 for the omitted value).
99
34
      return false;
100
34
    }
101
4.01k
    histogram[omit_pos] = space - total_count;
102
4.01k
  }
103
22.6k
  return BrunsliBitReaderIsHealthy(br);
104
22.6k
}
105
106
}  // namespace brunsli