/src/brunsli/c/dec/huffman_table.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 "./huffman_table.h" |
8 | | |
9 | | #include <cstring> /* for memcpy */ |
10 | | #include <vector> |
11 | | |
12 | | #include "../common/constants.h" |
13 | | #include <brunsli/types.h> |
14 | | #include "./huffman_decode.h" |
15 | | |
16 | | namespace brunsli { |
17 | | |
18 | | /* Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the |
19 | | bit-wise reversal of the len least significant bits of key. */ |
20 | 10.7k | static inline int GetNextKey(int key, size_t len) { |
21 | 10.7k | int step = 1u << (len - 1); |
22 | 21.0k | while (key & step) { |
23 | 10.3k | step >>= 1; |
24 | 10.3k | } |
25 | 10.7k | return (key & (step - 1)) + step; |
26 | 10.7k | } |
27 | | |
28 | | /* Stores code in table[0], table[step], table[2*step], ..., table[end] */ |
29 | | /* Assumes that end is an integer multiple of step */ |
30 | | static inline void ReplicateValue(HuffmanCode* table, int step, int end, |
31 | 10.7k | HuffmanCode code) { |
32 | 25.6k | do { |
33 | 25.6k | end -= step; |
34 | 25.6k | table[end] = code; |
35 | 25.6k | } while (end > 0); |
36 | 10.7k | } |
37 | | |
38 | | /* Returns the table width of the next 2nd level table. count is the histogram |
39 | | of bit lengths for the remaining symbols, len is the code length of the next |
40 | | processed symbol */ |
41 | | static inline size_t NextTableBitSize(const uint16_t* const count, size_t len, |
42 | 965 | size_t root_bits) { |
43 | 965 | size_t left = size_t(1) << (len - root_bits); |
44 | 1.07k | while (len < kMaxHuffmanBits) { |
45 | 1.06k | if (left <= count[len]) break; |
46 | 109 | left -= count[len]; |
47 | 109 | ++len; |
48 | 109 | left <<= 1; |
49 | 109 | } |
50 | 965 | return len - root_bits; |
51 | 965 | } |
52 | | |
53 | | uint32_t BuildHuffmanTable(HuffmanCode* root_table, size_t root_bits, |
54 | | const uint8_t* const code_lengths, |
55 | 409 | size_t code_lengths_size, uint16_t* count) { |
56 | 409 | HuffmanCode code; /* current table entry */ |
57 | 409 | HuffmanCode* table; /* next available space in table */ |
58 | 409 | size_t len; /* current code length */ |
59 | 409 | size_t symbol; /* symbol index in original or sorted table */ |
60 | 409 | int key; /* reversed prefix code */ |
61 | 409 | int step; /* step size to replicate values in current table */ |
62 | 409 | int low; /* low bits for current root entry */ |
63 | 409 | int mask; /* mask for low bits */ |
64 | 409 | size_t table_bits; /* key length of current table */ |
65 | 409 | int table_size; /* size of current table */ |
66 | 409 | int total_size; /* sum of root table size and 2nd level table sizes */ |
67 | | /* offsets in sorted table for each length */ |
68 | 409 | uint16_t offset[kMaxHuffmanBits + 1]; |
69 | 409 | size_t max_length = 1; |
70 | | |
71 | 409 | if (code_lengths_size > 1u << kMaxHuffmanBits) return 0; |
72 | | |
73 | | /* symbols sorted by code length */ |
74 | 409 | std::vector<uint16_t> sorted_storage(code_lengths_size); |
75 | 409 | uint16_t* sorted = sorted_storage.data(); |
76 | | |
77 | | /* generate offsets into sorted symbol table by code length */ |
78 | 409 | { |
79 | 409 | uint16_t sum = 0; |
80 | 6.54k | for (len = 1; len <= kMaxHuffmanBits; len++) { |
81 | 6.13k | offset[len] = sum; |
82 | 6.13k | if (count[len]) { |
83 | 1.14k | sum = static_cast<uint16_t>(sum + count[len]); |
84 | 1.14k | max_length = len; |
85 | 1.14k | } |
86 | 6.13k | } |
87 | 409 | } |
88 | | |
89 | | /* sort symbols by length, by symbol order within each length */ |
90 | 24.1k | for (symbol = 0; symbol < code_lengths_size; symbol++) { |
91 | 23.7k | if (code_lengths[symbol] != 0) { |
92 | 10.7k | sorted[offset[code_lengths[symbol]]++] = static_cast<uint16_t>(symbol); |
93 | 10.7k | } |
94 | 23.7k | } |
95 | | |
96 | 409 | table = root_table; |
97 | 409 | table_bits = root_bits; |
98 | 409 | table_size = 1u << table_bits; |
99 | 409 | total_size = table_size; |
100 | | |
101 | | /* special case code with only one value */ |
102 | 409 | if (offset[kMaxHuffmanBits] == 1) { |
103 | 38 | code.bits = 0; |
104 | 38 | code.value = static_cast<uint16_t>(sorted[0]); |
105 | 1.25k | for (key = 0; key < total_size; ++key) { |
106 | 1.21k | table[key] = code; |
107 | 1.21k | } |
108 | 38 | return total_size; |
109 | 38 | } |
110 | | |
111 | | /* fill in root table */ |
112 | | /* let's reduce the table size to a smaller size if possible, and */ |
113 | | /* create the repetitions by memcpy if possible in the coming loop */ |
114 | 371 | if (table_bits > max_length) { |
115 | 263 | table_bits = max_length; |
116 | 263 | table_size = 1u << table_bits; |
117 | 263 | } |
118 | 371 | key = 0; |
119 | 371 | symbol = 0; |
120 | 371 | code.bits = 1; |
121 | 371 | step = 2; |
122 | 1.60k | do { |
123 | 9.29k | for (; count[code.bits] != 0; --count[code.bits]) { |
124 | 7.69k | code.value = static_cast<uint16_t>(sorted[symbol++]); |
125 | 7.69k | ReplicateValue(&table[key], step, table_size, code); |
126 | 7.69k | key = GetNextKey(key, code.bits); |
127 | 7.69k | } |
128 | 1.60k | step <<= 1; |
129 | 1.60k | } while (++code.bits <= table_bits); |
130 | | |
131 | | /* if root_bits != table_bits we only created one fraction of the */ |
132 | | /* table, and we need to replicate it now. */ |
133 | 1.07k | while (total_size != table_size) { |
134 | 707 | memcpy(&table[table_size], &table[0], table_size * sizeof(table[0])); |
135 | 707 | table_size <<= 1; |
136 | 707 | } |
137 | | |
138 | | /* fill in 2nd level tables and add pointers to root table */ |
139 | 371 | mask = total_size - 1; |
140 | 371 | low = -1; |
141 | 559 | for (len = root_bits + 1, step = 2; len <= max_length; ++len, step <<= 1) { |
142 | 3.21k | for (; count[len] != 0; --count[len]) { |
143 | 3.02k | if ((key & mask) != low) { |
144 | 965 | table += table_size; |
145 | 965 | table_bits = NextTableBitSize(count, len, root_bits); |
146 | 965 | table_size = 1u << table_bits; |
147 | 965 | total_size += table_size; |
148 | 965 | low = key & mask; |
149 | 965 | root_table[low].bits = static_cast<uint8_t>(table_bits + root_bits); |
150 | 965 | root_table[low].value = |
151 | 965 | static_cast<uint16_t>((table - root_table) - low); |
152 | 965 | } |
153 | 3.02k | code.bits = static_cast<uint8_t>(len - root_bits); |
154 | 3.02k | code.value = static_cast<uint16_t>(sorted[symbol++]); |
155 | 3.02k | ReplicateValue(&table[key >> root_bits], step, table_size, code); |
156 | 3.02k | key = GetNextKey(key, len); |
157 | 3.02k | } |
158 | 188 | } |
159 | | |
160 | 371 | return total_size; |
161 | 409 | } |
162 | | |
163 | | } // namespace brunsli |