Coverage Report

Created: 2025-10-10 06:44

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
51.2k
size_t ReadShortHuffmanCode(BrunsliBitReader* br, const int8_t* tree) {
28
51.2k
  size_t pos = 0;
29
51.2k
  int8_t delta = 1;
30
200k
  while (delta > 0) {
31
149k
    pos += delta + BrunsliBitReaderRead(br, 1);
32
149k
    delta = tree[pos];
33
149k
  }
34
51.2k
  return static_cast<size_t>(-delta);
35
51.2k
}
36
37
}  // namespace
38
39
bool ReadHistogram(uint32_t precision_bits, std::vector<uint32_t>* counts,
40
23.5k
                   BrunsliBitReader* br) {
41
23.5k
  BRUNSLI_DCHECK(!counts->empty());
42
23.5k
  uint32_t space = 1u << precision_bits;
43
23.5k
  const size_t length = counts->size();
44
23.5k
  std::fill(counts->begin(), counts->end(), 0);
45
23.5k
  uint32_t* histogram = counts->data();
46
23.5k
  int simple_code = BrunsliBitReaderRead(br, 1);
47
23.5k
  if (simple_code == 1) {
48
19.4k
    size_t max_bits_counter = length - 1;
49
19.4k
    uint32_t max_bits = 0;
50
19.4k
    int symbols[2] = {0};
51
19.4k
    const size_t num_symbols = BrunsliBitReaderRead(br, 1) + 1u;
52
116k
    while (max_bits_counter) {
53
97.1k
      max_bits_counter >>= 1;
54
97.1k
      ++max_bits;
55
97.1k
    }
56
45.0k
    for (size_t i = 0; i < num_symbols; ++i) {
57
25.6k
      symbols[i] = BrunsliBitReaderRead(br, max_bits) % length;
58
25.6k
    }
59
19.4k
    if (num_symbols == 1) {
60
13.2k
      histogram[symbols[0]] = space;
61
13.2k
    } else {
62
6.20k
      if (symbols[0] == symbols[1]) {  // corrupt data
63
20
        return false;
64
20
      }
65
6.18k
      uint32_t value = BrunsliBitReaderRead(br, precision_bits);
66
6.18k
      histogram[symbols[0]] = value;
67
6.18k
      histogram[symbols[1]] = space - value;
68
6.18k
    }
69
19.4k
  } else {
70
4.14k
    size_t real_length = ReadShortHuffmanCode(br, kLengthTree);
71
4.14k
    uint32_t total_count = 0;
72
4.14k
    uint32_t log_counts[BRUNSLI_ANS_MAX_SYMBOLS];
73
4.14k
    size_t omit_pos = 0;
74
4.14k
    BRUNSLI_DCHECK(real_length > 2);
75
51.2k
    for (size_t i = 0; i < real_length; ++i) {
76
47.1k
      log_counts[i] =
77
47.1k
          static_cast<uint32_t>(ReadShortHuffmanCode(br, kLogCountTree));
78
47.1k
      if (log_counts[i] > log_counts[omit_pos]) omit_pos = i;
79
47.1k
    }
80
4.14k
    BRUNSLI_DCHECK(omit_pos >= 0);
81
51.2k
    for (size_t i = 0; i < real_length; ++i) {
82
47.1k
      uint32_t code = log_counts[i];
83
47.1k
      if (i == omit_pos) {
84
4.14k
        continue;
85
43.0k
      } else if (code == 0) {
86
1.58k
        continue;
87
41.4k
      } else if (code == 1) {
88
2.96k
        histogram[i] = 1;
89
38.4k
      } else {
90
38.4k
        uint32_t bit_count = GetPopulationCountPrecision(code - 1);
91
38.4k
        histogram[i] = (1u << (code - 1)) + (BrunsliBitReaderRead(br, bit_count)
92
38.4k
                                             << (code - 1 - bit_count));
93
38.4k
      }
94
41.4k
      total_count += histogram[i];
95
41.4k
    }
96
4.14k
    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
25
      return false;
100
25
    }
101
4.12k
    histogram[omit_pos] = space - total_count;
102
4.12k
  }
103
23.5k
  return BrunsliBitReaderIsHealthy(br);
104
23.5k
}
105
106
}  // namespace brunsli