/rust/registry/src/index.crates.io-1949cf8c6b5b557f/image-webp-0.2.4/src/huffman.rs
Line | Count | Source |
1 | | //! Rudimentary utility for reading Canonical Huffman Codes. |
2 | | //! Based off <https://github.com/webmproject/libwebp/blob/7f8472a610b61ec780ef0a8873cd954ac512a505/src/utils/huffman.c> |
3 | | |
4 | | use std::io::BufRead; |
5 | | |
6 | | use crate::decoder::DecodingError; |
7 | | |
8 | | use super::lossless::BitReader; |
9 | | |
10 | | const MAX_ALLOWED_CODE_LENGTH: usize = 15; |
11 | | const MAX_TABLE_BITS: u8 = 10; |
12 | | |
13 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
14 | | enum HuffmanTreeNode { |
15 | | Branch(usize), //offset in vector to children |
16 | | Leaf(u16), //symbol stored in leaf |
17 | | Empty, |
18 | | } |
19 | | |
20 | | #[derive(Clone, Debug)] |
21 | | enum HuffmanTreeInner { |
22 | | Single(u16), |
23 | | Tree { |
24 | | tree: Vec<HuffmanTreeNode>, |
25 | | table: Vec<u32>, |
26 | | table_mask: u16, |
27 | | }, |
28 | | } |
29 | | |
30 | | /// Huffman tree |
31 | | #[derive(Clone, Debug)] |
32 | | pub(crate) struct HuffmanTree(HuffmanTreeInner); |
33 | | |
34 | | impl Default for HuffmanTree { |
35 | 69.2k | fn default() -> Self { |
36 | 69.2k | Self(HuffmanTreeInner::Single(0)) |
37 | 69.2k | } |
38 | | } |
39 | | |
40 | | impl HuffmanTree { |
41 | | /// Builds a tree implicitly, just from code lengths |
42 | 21.7k | pub(crate) fn build_implicit(code_lengths: Vec<u16>) -> Result<Self, DecodingError> { |
43 | | // Count symbols and build histogram |
44 | 21.7k | let mut num_symbols = 0; |
45 | 21.7k | let mut code_length_hist = [0; MAX_ALLOWED_CODE_LENGTH + 1]; |
46 | 3.04M | for &length in code_lengths.iter().filter(|&&x| x != 0) { |
47 | 1.02M | code_length_hist[usize::from(length)] += 1; |
48 | 1.02M | num_symbols += 1; |
49 | 1.02M | } |
50 | | |
51 | | // Handle special cases |
52 | 21.7k | if num_symbols == 0 { |
53 | 14 | return Err(DecodingError::HuffmanError); |
54 | 21.7k | } else if num_symbols == 1 { |
55 | 3.42k | let root_symbol = code_lengths.iter().position(|&x| x != 0).unwrap() as u16; |
56 | 1.48k | return Ok(Self::build_single_node(root_symbol)); |
57 | 20.2k | }; |
58 | | |
59 | | // Assign codes |
60 | 20.2k | let mut curr_code = 0; |
61 | 20.2k | let mut next_codes = [0; MAX_ALLOWED_CODE_LENGTH + 1]; |
62 | 192k | let max_code_length = code_length_hist.iter().rposition(|&x| x != 0).unwrap() as u16; |
63 | 130k | for code_len in 1..usize::from(max_code_length) + 1 { |
64 | 130k | next_codes[code_len] = curr_code; |
65 | 130k | curr_code = (curr_code + code_length_hist[code_len]) << 1; |
66 | 130k | } |
67 | | |
68 | | // Confirm that the huffman tree is valid |
69 | 20.2k | if curr_code != 2 << max_code_length { |
70 | 155 | return Err(DecodingError::HuffmanError); |
71 | 20.0k | } |
72 | | |
73 | | // Calculate table/tree parameters |
74 | 20.0k | let table_bits = max_code_length.min(u16::from(MAX_TABLE_BITS)); |
75 | 20.0k | let table_size = (1 << table_bits) as usize; |
76 | 20.0k | let table_mask = table_size as u16 - 1; |
77 | 20.0k | let tree_size = code_length_hist[table_bits as usize + 1..=max_code_length as usize] |
78 | 20.0k | .iter() |
79 | 20.0k | .sum::<u16>() as usize; |
80 | | |
81 | | // Populate decoding table |
82 | 20.0k | let mut tree = Vec::with_capacity(2 * tree_size); |
83 | 20.0k | let mut table = vec![0; table_size]; |
84 | 2.99M | for (symbol, &length) in code_lengths.iter().enumerate() { |
85 | 2.99M | if length == 0 { |
86 | 1.97M | continue; |
87 | 1.01M | } |
88 | | |
89 | 1.01M | let code = next_codes[length as usize]; |
90 | 1.01M | next_codes[length as usize] += 1; |
91 | | |
92 | 1.01M | if length <= table_bits { |
93 | 641k | let mut j = (u16::reverse_bits(code) >> (16 - length)) as usize; |
94 | 641k | let entry = (u32::from(length) << 16) | symbol as u32; |
95 | 6.29M | while j < table_size { |
96 | 5.65M | table[j] = entry; |
97 | 5.65M | j += 1 << length as usize; |
98 | 5.65M | } |
99 | | } else { |
100 | 377k | let table_index = |
101 | 377k | ((u16::reverse_bits(code) >> (16 - length)) & table_mask) as usize; |
102 | 377k | let table_value = table[table_index]; |
103 | | |
104 | 377k | debug_assert_eq!(table_value >> 16, 0); |
105 | | |
106 | 377k | let mut node_index = if table_value == 0 { |
107 | 77.0k | let node_index = tree.len(); |
108 | 77.0k | table[table_index] = (node_index + 1) as u32; |
109 | 77.0k | tree.push(HuffmanTreeNode::Empty); |
110 | 77.0k | node_index |
111 | | } else { |
112 | 300k | (table_value - 1) as usize |
113 | | }; |
114 | | |
115 | 377k | let code = usize::from(code); |
116 | 1.07M | for depth in (0..length - table_bits).rev() { |
117 | 1.07M | let node = tree[node_index]; |
118 | | |
119 | 1.07M | let offset = match node { |
120 | | HuffmanTreeNode::Empty => { |
121 | | // Turns a node from empty into a branch and assigns its children |
122 | 300k | let offset = tree.len() - node_index; |
123 | 300k | tree[node_index] = HuffmanTreeNode::Branch(offset); |
124 | 300k | tree.push(HuffmanTreeNode::Empty); |
125 | 300k | tree.push(HuffmanTreeNode::Empty); |
126 | 300k | offset |
127 | | } |
128 | 0 | HuffmanTreeNode::Leaf(_) => return Err(DecodingError::HuffmanError), |
129 | 773k | HuffmanTreeNode::Branch(offset) => offset, |
130 | | }; |
131 | | |
132 | 1.07M | node_index += offset + ((code >> depth) & 1); |
133 | | } |
134 | | |
135 | 377k | match tree[node_index] { |
136 | 377k | HuffmanTreeNode::Empty => { |
137 | 377k | tree[node_index] = HuffmanTreeNode::Leaf(symbol as u16); |
138 | 377k | } |
139 | 0 | HuffmanTreeNode::Leaf(_) => return Err(DecodingError::HuffmanError), |
140 | 0 | HuffmanTreeNode::Branch(_offset) => return Err(DecodingError::HuffmanError), |
141 | | } |
142 | | } |
143 | | } |
144 | | |
145 | 20.0k | Ok(Self(HuffmanTreeInner::Tree { |
146 | 20.0k | tree, |
147 | 20.0k | table, |
148 | 20.0k | table_mask, |
149 | 20.0k | })) |
150 | 21.7k | } |
151 | | |
152 | 52.4k | pub(crate) const fn build_single_node(symbol: u16) -> Self { |
153 | 52.4k | Self(HuffmanTreeInner::Single(symbol)) |
154 | 52.4k | } |
155 | | |
156 | 6.44k | pub(crate) fn build_two_node(zero: u16, one: u16) -> Self { |
157 | 6.44k | Self(HuffmanTreeInner::Tree { |
158 | 6.44k | tree: vec![ |
159 | 6.44k | HuffmanTreeNode::Leaf(zero), |
160 | 6.44k | HuffmanTreeNode::Leaf(one), |
161 | 6.44k | HuffmanTreeNode::Empty, |
162 | 6.44k | ], |
163 | 6.44k | table: vec![(1 << 16) | u32::from(zero), (1 << 16) | u32::from(one)], |
164 | 6.44k | table_mask: 0x1, |
165 | 6.44k | }) |
166 | 6.44k | } |
167 | | |
168 | 1.83M | pub(crate) const fn is_single_node(&self) -> bool { |
169 | 1.83M | matches!(self.0, HuffmanTreeInner::Single(_)) |
170 | 1.83M | } |
171 | | |
172 | | #[inline(never)] |
173 | 1.20M | fn read_symbol_slowpath<R: BufRead>( |
174 | 1.20M | tree: &[HuffmanTreeNode], |
175 | 1.20M | mut v: usize, |
176 | 1.20M | start_index: usize, |
177 | 1.20M | bit_reader: &mut BitReader<R>, |
178 | 1.20M | ) -> Result<u16, DecodingError> { |
179 | 1.20M | let mut depth = MAX_TABLE_BITS; |
180 | 1.20M | let mut index = start_index; |
181 | | loop { |
182 | 3.84M | match &tree[index] { |
183 | 2.64M | HuffmanTreeNode::Branch(children_offset) => { |
184 | 2.64M | index += children_offset + (v & 1); |
185 | 2.64M | depth += 1; |
186 | 2.64M | v >>= 1; |
187 | 2.64M | } |
188 | 1.20M | HuffmanTreeNode::Leaf(symbol) => { |
189 | 1.20M | bit_reader.consume(depth)?; |
190 | 1.20M | return Ok(*symbol); |
191 | | } |
192 | 0 | HuffmanTreeNode::Empty => return Err(DecodingError::HuffmanError), |
193 | | } |
194 | | } |
195 | 1.20M | } <image_webp::huffman::HuffmanTree>::read_symbol_slowpath::<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 173 | 1.19M | fn read_symbol_slowpath<R: BufRead>( | 174 | 1.19M | tree: &[HuffmanTreeNode], | 175 | 1.19M | mut v: usize, | 176 | 1.19M | start_index: usize, | 177 | 1.19M | bit_reader: &mut BitReader<R>, | 178 | 1.19M | ) -> Result<u16, DecodingError> { | 179 | 1.19M | let mut depth = MAX_TABLE_BITS; | 180 | 1.19M | let mut index = start_index; | 181 | | loop { | 182 | 3.82M | match &tree[index] { | 183 | 2.63M | HuffmanTreeNode::Branch(children_offset) => { | 184 | 2.63M | index += children_offset + (v & 1); | 185 | 2.63M | depth += 1; | 186 | 2.63M | v >>= 1; | 187 | 2.63M | } | 188 | 1.19M | HuffmanTreeNode::Leaf(symbol) => { | 189 | 1.19M | bit_reader.consume(depth)?; | 190 | 1.19M | return Ok(*symbol); | 191 | | } | 192 | 0 | HuffmanTreeNode::Empty => return Err(DecodingError::HuffmanError), | 193 | | } | 194 | | } | 195 | 1.19M | } |
<image_webp::huffman::HuffmanTree>::read_symbol_slowpath::<&mut std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 173 | 7.82k | fn read_symbol_slowpath<R: BufRead>( | 174 | 7.82k | tree: &[HuffmanTreeNode], | 175 | 7.82k | mut v: usize, | 176 | 7.82k | start_index: usize, | 177 | 7.82k | bit_reader: &mut BitReader<R>, | 178 | 7.82k | ) -> Result<u16, DecodingError> { | 179 | 7.82k | let mut depth = MAX_TABLE_BITS; | 180 | 7.82k | let mut index = start_index; | 181 | | loop { | 182 | 18.3k | match &tree[index] { | 183 | 10.4k | HuffmanTreeNode::Branch(children_offset) => { | 184 | 10.4k | index += children_offset + (v & 1); | 185 | 10.4k | depth += 1; | 186 | 10.4k | v >>= 1; | 187 | 10.4k | } | 188 | 7.82k | HuffmanTreeNode::Leaf(symbol) => { | 189 | 7.82k | bit_reader.consume(depth)?; | 190 | 7.82k | return Ok(*symbol); | 191 | | } | 192 | 0 | HuffmanTreeNode::Empty => return Err(DecodingError::HuffmanError), | 193 | | } | 194 | | } | 195 | 7.82k | } |
Unexecuted instantiation: <image_webp::huffman::HuffmanTree>::read_symbol_slowpath::<_> |
196 | | |
197 | | /// Reads a symbol using the bit reader. |
198 | | /// |
199 | | /// You must call call `bit_reader.fill()` before calling this function or it may erroroneosly |
200 | | /// detect the end of the stream and return a bitstream error. |
201 | 107M | pub(crate) fn read_symbol<R: BufRead>( |
202 | 107M | &self, |
203 | 107M | bit_reader: &mut BitReader<R>, |
204 | 107M | ) -> Result<u16, DecodingError> { |
205 | 107M | match &self.0 { |
206 | | HuffmanTreeInner::Tree { |
207 | 98.6M | tree, |
208 | 98.6M | table, |
209 | 98.6M | table_mask, |
210 | | } => { |
211 | 98.6M | let v = bit_reader.peek_full() as u16; |
212 | 98.6M | let entry = table[(v & table_mask) as usize]; |
213 | 98.6M | if entry >> 16 != 0 { |
214 | 97.4M | bit_reader.consume((entry >> 16) as u8)?; |
215 | 97.4M | return Ok(entry as u16); |
216 | 1.20M | } |
217 | | |
218 | 1.20M | Self::read_symbol_slowpath( |
219 | 1.20M | tree, |
220 | 1.20M | (v >> MAX_TABLE_BITS) as usize, |
221 | 1.20M | ((entry & 0xffff) - 1) as usize, |
222 | 1.20M | bit_reader, |
223 | | ) |
224 | | } |
225 | 8.85M | HuffmanTreeInner::Single(symbol) => Ok(*symbol), |
226 | | } |
227 | 107M | } <image_webp::huffman::HuffmanTree>::read_symbol::<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 201 | 78.6M | pub(crate) fn read_symbol<R: BufRead>( | 202 | 78.6M | &self, | 203 | 78.6M | bit_reader: &mut BitReader<R>, | 204 | 78.6M | ) -> Result<u16, DecodingError> { | 205 | 78.6M | match &self.0 { | 206 | | HuffmanTreeInner::Tree { | 207 | 76.9M | tree, | 208 | 76.9M | table, | 209 | 76.9M | table_mask, | 210 | | } => { | 211 | 76.9M | let v = bit_reader.peek_full() as u16; | 212 | 76.9M | let entry = table[(v & table_mask) as usize]; | 213 | 76.9M | if entry >> 16 != 0 { | 214 | 75.8M | bit_reader.consume((entry >> 16) as u8)?; | 215 | 75.8M | return Ok(entry as u16); | 216 | 1.19M | } | 217 | | | 218 | 1.19M | Self::read_symbol_slowpath( | 219 | 1.19M | tree, | 220 | 1.19M | (v >> MAX_TABLE_BITS) as usize, | 221 | 1.19M | ((entry & 0xffff) - 1) as usize, | 222 | 1.19M | bit_reader, | 223 | | ) | 224 | | } | 225 | 1.63M | HuffmanTreeInner::Single(symbol) => Ok(*symbol), | 226 | | } | 227 | 78.6M | } |
<image_webp::huffman::HuffmanTree>::read_symbol::<&mut std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 201 | 28.8M | pub(crate) fn read_symbol<R: BufRead>( | 202 | 28.8M | &self, | 203 | 28.8M | bit_reader: &mut BitReader<R>, | 204 | 28.8M | ) -> Result<u16, DecodingError> { | 205 | 28.8M | match &self.0 { | 206 | | HuffmanTreeInner::Tree { | 207 | 21.6M | tree, | 208 | 21.6M | table, | 209 | 21.6M | table_mask, | 210 | | } => { | 211 | 21.6M | let v = bit_reader.peek_full() as u16; | 212 | 21.6M | let entry = table[(v & table_mask) as usize]; | 213 | 21.6M | if entry >> 16 != 0 { | 214 | 21.6M | bit_reader.consume((entry >> 16) as u8)?; | 215 | 21.6M | return Ok(entry as u16); | 216 | 7.82k | } | 217 | | | 218 | 7.82k | Self::read_symbol_slowpath( | 219 | 7.82k | tree, | 220 | 7.82k | (v >> MAX_TABLE_BITS) as usize, | 221 | 7.82k | ((entry & 0xffff) - 1) as usize, | 222 | 7.82k | bit_reader, | 223 | | ) | 224 | | } | 225 | 7.21M | HuffmanTreeInner::Single(symbol) => Ok(*symbol), | 226 | | } | 227 | 28.8M | } |
Unexecuted instantiation: <image_webp::huffman::HuffmanTree>::read_symbol::<_> |
228 | | |
229 | | /// Peek at the next symbol in the bitstream if it can be read with only a primary table lookup. |
230 | | /// |
231 | | /// Returns a tuple of the codelength and symbol value. This function may return wrong |
232 | | /// information if there aren't enough bits in the bit reader to read the next symbol. |
233 | 3.66M | pub(crate) fn peek_symbol<R: BufRead>(&self, bit_reader: &BitReader<R>) -> Option<(u8, u16)> { |
234 | 3.66M | match &self.0 { |
235 | | HuffmanTreeInner::Tree { |
236 | 3.66M | table, table_mask, .. |
237 | | } => { |
238 | 3.66M | let v = bit_reader.peek_full() as u16; |
239 | 3.66M | let entry = table[(v & table_mask) as usize]; |
240 | 3.66M | if entry >> 16 != 0 { |
241 | 3.66M | return Some(((entry >> 16) as u8, entry as u16)); |
242 | 332 | } |
243 | 332 | None |
244 | | } |
245 | 0 | HuffmanTreeInner::Single(symbol) => Some((0, *symbol)), |
246 | | } |
247 | 3.66M | } <image_webp::huffman::HuffmanTree>::peek_symbol::<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 233 | 1.10M | pub(crate) fn peek_symbol<R: BufRead>(&self, bit_reader: &BitReader<R>) -> Option<(u8, u16)> { | 234 | 1.10M | match &self.0 { | 235 | | HuffmanTreeInner::Tree { | 236 | 1.10M | table, table_mask, .. | 237 | | } => { | 238 | 1.10M | let v = bit_reader.peek_full() as u16; | 239 | 1.10M | let entry = table[(v & table_mask) as usize]; | 240 | 1.10M | if entry >> 16 != 0 { | 241 | 1.10M | return Some(((entry >> 16) as u8, entry as u16)); | 242 | 322 | } | 243 | 322 | None | 244 | | } | 245 | 0 | HuffmanTreeInner::Single(symbol) => Some((0, *symbol)), | 246 | | } | 247 | 1.10M | } |
<image_webp::huffman::HuffmanTree>::peek_symbol::<&mut std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 233 | 2.55M | pub(crate) fn peek_symbol<R: BufRead>(&self, bit_reader: &BitReader<R>) -> Option<(u8, u16)> { | 234 | 2.55M | match &self.0 { | 235 | | HuffmanTreeInner::Tree { | 236 | 2.55M | table, table_mask, .. | 237 | | } => { | 238 | 2.55M | let v = bit_reader.peek_full() as u16; | 239 | 2.55M | let entry = table[(v & table_mask) as usize]; | 240 | 2.55M | if entry >> 16 != 0 { | 241 | 2.55M | return Some(((entry >> 16) as u8, entry as u16)); | 242 | 10 | } | 243 | 10 | None | 244 | | } | 245 | 0 | HuffmanTreeInner::Single(symbol) => Some((0, *symbol)), | 246 | | } | 247 | 2.55M | } |
Unexecuted instantiation: <image_webp::huffman::HuffmanTree>::peek_symbol::<_> |
248 | | } |