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