/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 | 197k | fn default() -> Self { |
36 | 197k | Self(HuffmanTreeInner::Single(0)) |
37 | 197k | } |
38 | | } |
39 | | |
40 | | impl HuffmanTree { |
41 | | /// Builds a tree implicitly, just from code lengths |
42 | 30.0k | pub(crate) fn build_implicit(code_lengths: Vec<u16>) -> Result<Self, DecodingError> { |
43 | | // Count symbols and build histogram |
44 | 30.0k | let mut num_symbols = 0; |
45 | 30.0k | let mut code_length_hist = [0; MAX_ALLOWED_CODE_LENGTH + 1]; |
46 | 4.33M | for &length in code_lengths.iter().filter(|&&x| x != 0) { |
47 | 990k | code_length_hist[usize::from(length)] += 1; |
48 | 990k | num_symbols += 1; |
49 | 990k | } |
50 | | |
51 | | // Handle special cases |
52 | 30.0k | if num_symbols == 0 { |
53 | 53 | return Err(DecodingError::HuffmanError); |
54 | 29.9k | } else if num_symbols == 1 { |
55 | 25.4k | let root_symbol = code_lengths.iter().position(|&x| x != 0).unwrap() as u16; |
56 | 2.09k | return Ok(Self::build_single_node(root_symbol)); |
57 | 27.8k | }; |
58 | | |
59 | | // Assign codes |
60 | 27.8k | let mut curr_code = 0; |
61 | 27.8k | let mut next_codes = [0; MAX_ALLOWED_CODE_LENGTH + 1]; |
62 | 296k | let max_code_length = code_length_hist.iter().rposition(|&x| x != 0).unwrap() as u16; |
63 | 149k | for code_len in 1..usize::from(max_code_length) + 1 { |
64 | 149k | next_codes[code_len] = curr_code; |
65 | 149k | curr_code = (curr_code + code_length_hist[code_len]) << 1; |
66 | 149k | } |
67 | | |
68 | | // Confirm that the huffman tree is valid |
69 | 27.8k | if curr_code != 2 << max_code_length { |
70 | 407 | return Err(DecodingError::HuffmanError); |
71 | 27.4k | } |
72 | | |
73 | | // Calculate table/tree parameters |
74 | 27.4k | let table_bits = max_code_length.min(u16::from(MAX_TABLE_BITS)); |
75 | 27.4k | let table_size = (1 << table_bits) as usize; |
76 | 27.4k | let table_mask = table_size as u16 - 1; |
77 | 27.4k | let tree_size = code_length_hist[table_bits as usize + 1..=max_code_length as usize] |
78 | 27.4k | .iter() |
79 | 27.4k | .sum::<u16>() as usize; |
80 | | |
81 | | // Populate decoding table |
82 | 27.4k | let mut tree = Vec::with_capacity(2 * tree_size); |
83 | 27.4k | let mut table = vec![0; table_size]; |
84 | 4.14M | for (symbol, &length) in code_lengths.iter().enumerate() { |
85 | 4.14M | if length == 0 { |
86 | 3.17M | continue; |
87 | 961k | } |
88 | | |
89 | 961k | let code = next_codes[length as usize]; |
90 | 961k | next_codes[length as usize] += 1; |
91 | | |
92 | 961k | if length <= table_bits { |
93 | 667k | let mut j = (u16::reverse_bits(code) >> (16 - length)) as usize; |
94 | 667k | let entry = (u32::from(length) << 16) | symbol as u32; |
95 | 6.37M | while j < table_size { |
96 | 5.71M | table[j] = entry; |
97 | 5.71M | j += 1 << length as usize; |
98 | 5.71M | } |
99 | | } else { |
100 | 293k | let table_index = |
101 | 293k | ((u16::reverse_bits(code) >> (16 - length)) & table_mask) as usize; |
102 | 293k | let table_value = table[table_index]; |
103 | | |
104 | 293k | debug_assert_eq!(table_value >> 16, 0); |
105 | | |
106 | 293k | let mut node_index = if table_value == 0 { |
107 | 58.3k | let node_index = tree.len(); |
108 | 58.3k | table[table_index] = (node_index + 1) as u32; |
109 | 58.3k | tree.push(HuffmanTreeNode::Empty); |
110 | 58.3k | node_index |
111 | | } else { |
112 | 235k | (table_value - 1) as usize |
113 | | }; |
114 | | |
115 | 293k | let code = usize::from(code); |
116 | 862k | for depth in (0..length - table_bits).rev() { |
117 | 862k | let node = tree[node_index]; |
118 | | |
119 | 862k | let offset = match node { |
120 | | HuffmanTreeNode::Empty => { |
121 | | // Turns a node from empty into a branch and assigns its children |
122 | 235k | let offset = tree.len() - node_index; |
123 | 235k | tree[node_index] = HuffmanTreeNode::Branch(offset); |
124 | 235k | tree.push(HuffmanTreeNode::Empty); |
125 | 235k | tree.push(HuffmanTreeNode::Empty); |
126 | 235k | offset |
127 | | } |
128 | 0 | HuffmanTreeNode::Leaf(_) => return Err(DecodingError::HuffmanError), |
129 | 626k | HuffmanTreeNode::Branch(offset) => offset, |
130 | | }; |
131 | | |
132 | 862k | node_index += offset + ((code >> depth) & 1); |
133 | | } |
134 | | |
135 | 293k | match tree[node_index] { |
136 | 293k | HuffmanTreeNode::Empty => { |
137 | 293k | tree[node_index] = HuffmanTreeNode::Leaf(symbol as u16); |
138 | 293k | } |
139 | 0 | HuffmanTreeNode::Leaf(_) => return Err(DecodingError::HuffmanError), |
140 | 0 | HuffmanTreeNode::Branch(_offset) => return Err(DecodingError::HuffmanError), |
141 | | } |
142 | | } |
143 | | } |
144 | | |
145 | 27.4k | Ok(Self(HuffmanTreeInner::Tree { |
146 | 27.4k | tree, |
147 | 27.4k | table, |
148 | 27.4k | table_mask, |
149 | 27.4k | })) |
150 | 30.0k | } |
151 | | |
152 | 170k | pub(crate) const fn build_single_node(symbol: u16) -> Self { |
153 | 170k | Self(HuffmanTreeInner::Single(symbol)) |
154 | 170k | } |
155 | | |
156 | 10.0k | pub(crate) fn build_two_node(zero: u16, one: u16) -> Self { |
157 | 10.0k | Self(HuffmanTreeInner::Tree { |
158 | 10.0k | tree: vec![ |
159 | 10.0k | HuffmanTreeNode::Leaf(zero), |
160 | 10.0k | HuffmanTreeNode::Leaf(one), |
161 | 10.0k | HuffmanTreeNode::Empty, |
162 | 10.0k | ], |
163 | 10.0k | table: vec![(1 << 16) | u32::from(zero), (1 << 16) | u32::from(one)], |
164 | 10.0k | table_mask: 0x1, |
165 | 10.0k | }) |
166 | 10.0k | } |
167 | | |
168 | 244M | pub(crate) const fn is_single_node(&self) -> bool { |
169 | 244M | matches!(self.0, HuffmanTreeInner::Single(_)) |
170 | 244M | } |
171 | | |
172 | | #[inline(never)] |
173 | 782k | fn read_symbol_slowpath<R: BufRead>( |
174 | 782k | tree: &[HuffmanTreeNode], |
175 | 782k | mut v: usize, |
176 | 782k | start_index: usize, |
177 | 782k | bit_reader: &mut BitReader<R>, |
178 | 782k | ) -> Result<u16, DecodingError> { |
179 | 782k | let mut depth = MAX_TABLE_BITS; |
180 | 782k | let mut index = start_index; |
181 | | loop { |
182 | 2.56M | match &tree[index] { |
183 | 1.78M | HuffmanTreeNode::Branch(children_offset) => { |
184 | 1.78M | index += children_offset + (v & 1); |
185 | 1.78M | depth += 1; |
186 | 1.78M | v >>= 1; |
187 | 1.78M | } |
188 | 782k | HuffmanTreeNode::Leaf(symbol) => { |
189 | 782k | bit_reader.consume(depth)?; |
190 | 782k | return Ok(*symbol); |
191 | | } |
192 | 0 | HuffmanTreeNode::Empty => return Err(DecodingError::HuffmanError), |
193 | | } |
194 | | } |
195 | 782k | } <image_webp::huffman::HuffmanTree>::read_symbol_slowpath::<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 173 | 775k | fn read_symbol_slowpath<R: BufRead>( | 174 | 775k | tree: &[HuffmanTreeNode], | 175 | 775k | mut v: usize, | 176 | 775k | start_index: usize, | 177 | 775k | bit_reader: &mut BitReader<R>, | 178 | 775k | ) -> Result<u16, DecodingError> { | 179 | 775k | let mut depth = MAX_TABLE_BITS; | 180 | 775k | let mut index = start_index; | 181 | | loop { | 182 | 2.54M | match &tree[index] { | 183 | 1.77M | HuffmanTreeNode::Branch(children_offset) => { | 184 | 1.77M | index += children_offset + (v & 1); | 185 | 1.77M | depth += 1; | 186 | 1.77M | v >>= 1; | 187 | 1.77M | } | 188 | 775k | HuffmanTreeNode::Leaf(symbol) => { | 189 | 775k | bit_reader.consume(depth)?; | 190 | 775k | return Ok(*symbol); | 191 | | } | 192 | 0 | HuffmanTreeNode::Empty => return Err(DecodingError::HuffmanError), | 193 | | } | 194 | | } | 195 | 775k | } |
<image_webp::huffman::HuffmanTree>::read_symbol_slowpath::<&mut std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 173 | 7.01k | fn read_symbol_slowpath<R: BufRead>( | 174 | 7.01k | tree: &[HuffmanTreeNode], | 175 | 7.01k | mut v: usize, | 176 | 7.01k | start_index: usize, | 177 | 7.01k | bit_reader: &mut BitReader<R>, | 178 | 7.01k | ) -> Result<u16, DecodingError> { | 179 | 7.01k | let mut depth = MAX_TABLE_BITS; | 180 | 7.01k | let mut index = start_index; | 181 | | loop { | 182 | 15.6k | match &tree[index] { | 183 | 8.59k | HuffmanTreeNode::Branch(children_offset) => { | 184 | 8.59k | index += children_offset + (v & 1); | 185 | 8.59k | depth += 1; | 186 | 8.59k | v >>= 1; | 187 | 8.59k | } | 188 | 7.01k | HuffmanTreeNode::Leaf(symbol) => { | 189 | 7.01k | bit_reader.consume(depth)?; | 190 | 7.00k | return Ok(*symbol); | 191 | | } | 192 | 0 | HuffmanTreeNode::Empty => return Err(DecodingError::HuffmanError), | 193 | | } | 194 | | } | 195 | 7.01k | } |
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 | 401M | pub(crate) fn read_symbol<R: BufRead>( |
202 | 401M | &self, |
203 | 401M | bit_reader: &mut BitReader<R>, |
204 | 401M | ) -> Result<u16, DecodingError> { |
205 | 401M | match &self.0 { |
206 | | HuffmanTreeInner::Tree { |
207 | 71.3M | tree, |
208 | 71.3M | table, |
209 | 71.3M | table_mask, |
210 | | } => { |
211 | 71.3M | let v = bit_reader.peek_full() as u16; |
212 | 71.3M | let entry = table[(v & table_mask) as usize]; |
213 | 71.3M | if entry >> 16 != 0 { |
214 | 70.5M | bit_reader.consume((entry >> 16) as u8)?; |
215 | 70.5M | return Ok(entry as u16); |
216 | 782k | } |
217 | | |
218 | 782k | Self::read_symbol_slowpath( |
219 | 782k | tree, |
220 | 782k | (v >> MAX_TABLE_BITS) as usize, |
221 | 782k | ((entry & 0xffff) - 1) as usize, |
222 | 782k | bit_reader, |
223 | | ) |
224 | | } |
225 | 329M | HuffmanTreeInner::Single(symbol) => Ok(*symbol), |
226 | | } |
227 | 401M | } <image_webp::huffman::HuffmanTree>::read_symbol::<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 201 | 368M | pub(crate) fn read_symbol<R: BufRead>( | 202 | 368M | &self, | 203 | 368M | bit_reader: &mut BitReader<R>, | 204 | 368M | ) -> Result<u16, DecodingError> { | 205 | 368M | match &self.0 { | 206 | | HuffmanTreeInner::Tree { | 207 | 60.7M | tree, | 208 | 60.7M | table, | 209 | 60.7M | table_mask, | 210 | | } => { | 211 | 60.7M | let v = bit_reader.peek_full() as u16; | 212 | 60.7M | let entry = table[(v & table_mask) as usize]; | 213 | 60.7M | if entry >> 16 != 0 { | 214 | 59.9M | bit_reader.consume((entry >> 16) as u8)?; | 215 | 59.9M | return Ok(entry as u16); | 216 | 775k | } | 217 | | | 218 | 775k | Self::read_symbol_slowpath( | 219 | 775k | tree, | 220 | 775k | (v >> MAX_TABLE_BITS) as usize, | 221 | 775k | ((entry & 0xffff) - 1) as usize, | 222 | 775k | bit_reader, | 223 | | ) | 224 | | } | 225 | 308M | HuffmanTreeInner::Single(symbol) => Ok(*symbol), | 226 | | } | 227 | 368M | } |
<image_webp::huffman::HuffmanTree>::read_symbol::<&mut std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 201 | 32.2M | pub(crate) fn read_symbol<R: BufRead>( | 202 | 32.2M | &self, | 203 | 32.2M | bit_reader: &mut BitReader<R>, | 204 | 32.2M | ) -> Result<u16, DecodingError> { | 205 | 32.2M | match &self.0 { | 206 | | HuffmanTreeInner::Tree { | 207 | 10.6M | tree, | 208 | 10.6M | table, | 209 | 10.6M | table_mask, | 210 | | } => { | 211 | 10.6M | let v = bit_reader.peek_full() as u16; | 212 | 10.6M | let entry = table[(v & table_mask) as usize]; | 213 | 10.6M | if entry >> 16 != 0 { | 214 | 10.6M | bit_reader.consume((entry >> 16) as u8)?; | 215 | 10.6M | return Ok(entry as u16); | 216 | 7.01k | } | 217 | | | 218 | 7.01k | Self::read_symbol_slowpath( | 219 | 7.01k | tree, | 220 | 7.01k | (v >> MAX_TABLE_BITS) as usize, | 221 | 7.01k | ((entry & 0xffff) - 1) as usize, | 222 | 7.01k | bit_reader, | 223 | | ) | 224 | | } | 225 | 21.5M | HuffmanTreeInner::Single(symbol) => Ok(*symbol), | 226 | | } | 227 | 32.2M | } |
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 | 81.3M | pub(crate) fn peek_symbol<R: BufRead>(&self, bit_reader: &BitReader<R>) -> Option<(u8, u16)> { |
234 | 81.3M | match &self.0 { |
235 | | HuffmanTreeInner::Tree { |
236 | 1.97M | table, table_mask, .. |
237 | | } => { |
238 | 1.97M | let v = bit_reader.peek_full() as u16; |
239 | 1.97M | let entry = table[(v & table_mask) as usize]; |
240 | 1.97M | if entry >> 16 != 0 { |
241 | 1.97M | return Some(((entry >> 16) as u8, entry as u16)); |
242 | 542 | } |
243 | 542 | None |
244 | | } |
245 | 79.3M | HuffmanTreeInner::Single(symbol) => Some((0, *symbol)), |
246 | | } |
247 | 81.3M | } <image_webp::huffman::HuffmanTree>::peek_symbol::<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 233 | 79.5M | pub(crate) fn peek_symbol<R: BufRead>(&self, bit_reader: &BitReader<R>) -> Option<(u8, u16)> { | 234 | 79.5M | match &self.0 { | 235 | | HuffmanTreeInner::Tree { | 236 | 862k | table, table_mask, .. | 237 | | } => { | 238 | 862k | let v = bit_reader.peek_full() as u16; | 239 | 862k | let entry = table[(v & table_mask) as usize]; | 240 | 862k | if entry >> 16 != 0 { | 241 | 861k | return Some(((entry >> 16) as u8, entry as u16)); | 242 | 511 | } | 243 | 511 | None | 244 | | } | 245 | 78.6M | HuffmanTreeInner::Single(symbol) => Some((0, *symbol)), | 246 | | } | 247 | 79.5M | } |
<image_webp::huffman::HuffmanTree>::peek_symbol::<&mut std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>> Line | Count | Source | 233 | 1.80M | pub(crate) fn peek_symbol<R: BufRead>(&self, bit_reader: &BitReader<R>) -> Option<(u8, u16)> { | 234 | 1.80M | match &self.0 { | 235 | | HuffmanTreeInner::Tree { | 236 | 1.11M | table, table_mask, .. | 237 | | } => { | 238 | 1.11M | let v = bit_reader.peek_full() as u16; | 239 | 1.11M | let entry = table[(v & table_mask) as usize]; | 240 | 1.11M | if entry >> 16 != 0 { | 241 | 1.11M | return Some(((entry >> 16) as u8, entry as u16)); | 242 | 31 | } | 243 | 31 | None | 244 | | } | 245 | 686k | HuffmanTreeInner::Single(symbol) => Some((0, *symbol)), | 246 | | } | 247 | 1.80M | } |
Unexecuted instantiation: <image_webp::huffman::HuffmanTree>::peek_symbol::<_> |
248 | | } |