Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(615)

Side by Side Diff: net/spdy/hpack/hpack_huffman_table.cc

Issue 1535363003: Switch to standard integer types in net/. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: stddef Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/spdy/hpack/hpack_huffman_table.h ('k') | net/spdy/hpack/hpack_input_stream.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/spdy/hpack/hpack_huffman_table.h" 5 #include "net/spdy/hpack/hpack_huffman_table.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/numerics/safe_conversions.h" 11 #include "base/numerics/safe_conversions.h"
12 #include "net/spdy/hpack/hpack_input_stream.h" 12 #include "net/spdy/hpack/hpack_input_stream.h"
13 #include "net/spdy/hpack/hpack_output_stream.h" 13 #include "net/spdy/hpack/hpack_output_stream.h"
14 14
15 namespace net { 15 namespace net {
16 16
17 using base::StringPiece; 17 using base::StringPiece;
18 using std::string; 18 using std::string;
19 19
20 namespace { 20 namespace {
21 21
22 // How many bits to index in the root decode table. 22 // How many bits to index in the root decode table.
23 const uint8 kDecodeTableRootBits = 9; 23 const uint8_t kDecodeTableRootBits = 9;
24 // Maximum number of bits to index in successive decode tables. 24 // Maximum number of bits to index in successive decode tables.
25 const uint8 kDecodeTableBranchBits = 6; 25 const uint8_t kDecodeTableBranchBits = 6;
26 26
27 bool SymbolLengthAndIdCompare(const HpackHuffmanSymbol& a, 27 bool SymbolLengthAndIdCompare(const HpackHuffmanSymbol& a,
28 const HpackHuffmanSymbol& b) { 28 const HpackHuffmanSymbol& b) {
29 if (a.length == b.length) { 29 if (a.length == b.length) {
30 return a.id < b.id; 30 return a.id < b.id;
31 } 31 }
32 return a.length < b.length; 32 return a.length < b.length;
33 } 33 }
34 bool SymbolIdCompare(const HpackHuffmanSymbol& a, const HpackHuffmanSymbol& b) { 34 bool SymbolIdCompare(const HpackHuffmanSymbol& a, const HpackHuffmanSymbol& b) {
35 return a.id < b.id; 35 return a.id < b.id;
36 } 36 }
37 37
38 } // namespace 38 } // namespace
39 39
40 HpackHuffmanTable::DecodeEntry::DecodeEntry() 40 HpackHuffmanTable::DecodeEntry::DecodeEntry()
41 : next_table_index(0), length(0), symbol_id(0) {} 41 : next_table_index(0), length(0), symbol_id(0) {}
42 HpackHuffmanTable::DecodeEntry::DecodeEntry(uint8 next_table_index, 42 HpackHuffmanTable::DecodeEntry::DecodeEntry(uint8_t next_table_index,
43 uint8 length, 43 uint8_t length,
44 uint16 symbol_id) 44 uint16_t symbol_id)
45 : next_table_index(next_table_index), 45 : next_table_index(next_table_index),
46 length(length), 46 length(length),
47 symbol_id(symbol_id) {} 47 symbol_id(symbol_id) {}
48 size_t HpackHuffmanTable::DecodeTable::size() const { 48 size_t HpackHuffmanTable::DecodeTable::size() const {
49 return size_t(1) << indexed_length; 49 return size_t(1) << indexed_length;
50 } 50 }
51 51
52 HpackHuffmanTable::HpackHuffmanTable() {} 52 HpackHuffmanTable::HpackHuffmanTable() {}
53 53
54 HpackHuffmanTable::~HpackHuffmanTable() {} 54 HpackHuffmanTable::~HpackHuffmanTable() {}
55 55
56 bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols, 56 bool HpackHuffmanTable::Initialize(const HpackHuffmanSymbol* input_symbols,
57 size_t symbol_count) { 57 size_t symbol_count) {
58 CHECK(!IsInitialized()); 58 CHECK(!IsInitialized());
59 DCHECK(base::IsValueInRangeForNumericType<uint16>(symbol_count)); 59 DCHECK(base::IsValueInRangeForNumericType<uint16_t>(symbol_count));
60 60
61 std::vector<Symbol> symbols(symbol_count); 61 std::vector<Symbol> symbols(symbol_count);
62 // Validate symbol id sequence, and copy into |symbols|. 62 // Validate symbol id sequence, and copy into |symbols|.
63 for (uint16 i = 0; i < symbol_count; i++) { 63 for (uint16_t i = 0; i < symbol_count; i++) {
64 if (i != input_symbols[i].id) { 64 if (i != input_symbols[i].id) {
65 failed_symbol_id_ = i; 65 failed_symbol_id_ = i;
66 return false; 66 return false;
67 } 67 }
68 symbols[i] = input_symbols[i]; 68 symbols[i] = input_symbols[i];
69 } 69 }
70 // Order on length and ID ascending, to verify symbol codes are canonical. 70 // Order on length and ID ascending, to verify symbol codes are canonical.
71 std::sort(symbols.begin(), symbols.end(), SymbolLengthAndIdCompare); 71 std::sort(symbols.begin(), symbols.end(), SymbolLengthAndIdCompare);
72 if (symbols[0].code != 0) { 72 if (symbols[0].code != 0) {
73 failed_symbol_id_ = 0; 73 failed_symbol_id_ = 0;
74 return false; 74 return false;
75 } 75 }
76 for (size_t i = 1; i != symbols.size(); i++) { 76 for (size_t i = 1; i != symbols.size(); i++) {
77 unsigned code_shift = 32 - symbols[i - 1].length; 77 unsigned code_shift = 32 - symbols[i - 1].length;
78 uint32 code = symbols[i - 1].code + (1 << code_shift); 78 uint32_t code = symbols[i - 1].code + (1 << code_shift);
79 79
80 if (code != symbols[i].code) { 80 if (code != symbols[i].code) {
81 failed_symbol_id_ = symbols[i].id; 81 failed_symbol_id_ = symbols[i].id;
82 return false; 82 return false;
83 } 83 }
84 if (code < symbols[i - 1].code) { 84 if (code < symbols[i - 1].code) {
85 // An integer overflow occurred. This implies the input 85 // An integer overflow occurred. This implies the input
86 // lengths do not represent a valid Huffman code. 86 // lengths do not represent a valid Huffman code.
87 failed_symbol_id_ = symbols[i].id; 87 failed_symbol_id_ = symbols[i].id;
88 return false; 88 return false;
89 } 89 }
90 } 90 }
91 if (symbols.back().length < 8) { 91 if (symbols.back().length < 8) {
92 // At least one code (such as an EOS symbol) must be 8 bits or longer. 92 // At least one code (such as an EOS symbol) must be 8 bits or longer.
93 // Without this, some inputs will not be encodable in a whole number 93 // Without this, some inputs will not be encodable in a whole number
94 // of bytes. 94 // of bytes.
95 return false; 95 return false;
96 } 96 }
97 pad_bits_ = static_cast<uint8>(symbols.back().code >> 24); 97 pad_bits_ = static_cast<uint8_t>(symbols.back().code >> 24);
98 98
99 BuildDecodeTables(symbols); 99 BuildDecodeTables(symbols);
100 // Order on symbol ID ascending. 100 // Order on symbol ID ascending.
101 std::sort(symbols.begin(), symbols.end(), SymbolIdCompare); 101 std::sort(symbols.begin(), symbols.end(), SymbolIdCompare);
102 BuildEncodeTable(symbols); 102 BuildEncodeTable(symbols);
103 return true; 103 return true;
104 } 104 }
105 105
106 void HpackHuffmanTable::BuildEncodeTable(const std::vector<Symbol>& symbols) { 106 void HpackHuffmanTable::BuildEncodeTable(const std::vector<Symbol>& symbols) {
107 for (size_t i = 0; i != symbols.size(); i++) { 107 for (size_t i = 0; i != symbols.size(); i++) {
108 const Symbol& symbol = symbols[i]; 108 const Symbol& symbol = symbols[i];
109 CHECK_EQ(i, symbol.id); 109 CHECK_EQ(i, symbol.id);
110 code_by_id_.push_back(symbol.code); 110 code_by_id_.push_back(symbol.code);
111 length_by_id_.push_back(symbol.length); 111 length_by_id_.push_back(symbol.length);
112 } 112 }
113 } 113 }
114 114
115 void HpackHuffmanTable::BuildDecodeTables(const std::vector<Symbol>& symbols) { 115 void HpackHuffmanTable::BuildDecodeTables(const std::vector<Symbol>& symbols) {
116 AddDecodeTable(0, kDecodeTableRootBits); 116 AddDecodeTable(0, kDecodeTableRootBits);
117 // We wish to maximize the flatness of the DecodeTable hierarchy (subject to 117 // We wish to maximize the flatness of the DecodeTable hierarchy (subject to
118 // the |kDecodeTableBranchBits| constraint), and to minimize the size of 118 // the |kDecodeTableBranchBits| constraint), and to minimize the size of
119 // child tables. To achieve this, we iterate in order of descending code 119 // child tables. To achieve this, we iterate in order of descending code
120 // length. This ensures that child tables are visited with their longest 120 // length. This ensures that child tables are visited with their longest
121 // entry first, and that the child can therefore be minimally sized to hold 121 // entry first, and that the child can therefore be minimally sized to hold
122 // that entry without fear of introducing unneccesary branches later. 122 // that entry without fear of introducing unneccesary branches later.
123 for (std::vector<Symbol>::const_reverse_iterator it = symbols.rbegin(); 123 for (std::vector<Symbol>::const_reverse_iterator it = symbols.rbegin();
124 it != symbols.rend(); ++it) { 124 it != symbols.rend(); ++it) {
125 uint8 table_index = 0; 125 uint8_t table_index = 0;
126 while (true) { 126 while (true) {
127 const DecodeTable table = decode_tables_[table_index]; 127 const DecodeTable table = decode_tables_[table_index];
128 128
129 // Mask and shift the portion of the code being indexed into low bits. 129 // Mask and shift the portion of the code being indexed into low bits.
130 uint32 index = (it->code << table.prefix_length); 130 uint32_t index = (it->code << table.prefix_length);
131 index = index >> (32 - table.indexed_length); 131 index = index >> (32 - table.indexed_length);
132 132
133 CHECK_LT(index, table.size()); 133 CHECK_LT(index, table.size());
134 DecodeEntry entry = Entry(table, index); 134 DecodeEntry entry = Entry(table, index);
135 135
136 uint8 total_indexed = table.prefix_length + table.indexed_length; 136 uint8_t total_indexed = table.prefix_length + table.indexed_length;
137 if (total_indexed >= it->length) { 137 if (total_indexed >= it->length) {
138 // We're writing a terminal entry. 138 // We're writing a terminal entry.
139 entry.length = it->length; 139 entry.length = it->length;
140 entry.symbol_id = it->id; 140 entry.symbol_id = it->id;
141 entry.next_table_index = table_index; 141 entry.next_table_index = table_index;
142 SetEntry(table, index, entry); 142 SetEntry(table, index, entry);
143 break; 143 break;
144 } 144 }
145 145
146 if (entry.length == 0) { 146 if (entry.length == 0) {
147 // First visit to this placeholder. We need to create a new table. 147 // First visit to this placeholder. We need to create a new table.
148 CHECK_EQ(entry.next_table_index, 0); 148 CHECK_EQ(entry.next_table_index, 0);
149 entry.length = it->length; 149 entry.length = it->length;
150 entry.next_table_index = 150 entry.next_table_index =
151 AddDecodeTable(total_indexed, // Becomes the new table prefix. 151 AddDecodeTable(total_indexed, // Becomes the new table prefix.
152 std::min<uint8>(kDecodeTableBranchBits, 152 std::min<uint8_t>(kDecodeTableBranchBits,
153 entry.length - total_indexed)); 153 entry.length - total_indexed));
154 SetEntry(table, index, entry); 154 SetEntry(table, index, entry);
155 } 155 }
156 CHECK_NE(entry.next_table_index, table_index); 156 CHECK_NE(entry.next_table_index, table_index);
157 table_index = entry.next_table_index; 157 table_index = entry.next_table_index;
158 } 158 }
159 } 159 }
160 // Fill shorter table entries into the additional entry spots they map to. 160 // Fill shorter table entries into the additional entry spots they map to.
161 for (size_t i = 0; i != decode_tables_.size(); i++) { 161 for (size_t i = 0; i != decode_tables_.size(); i++) {
162 const DecodeTable& table = decode_tables_[i]; 162 const DecodeTable& table = decode_tables_[i];
163 uint8 total_indexed = table.prefix_length + table.indexed_length; 163 uint8_t total_indexed = table.prefix_length + table.indexed_length;
164 164
165 size_t j = 0; 165 size_t j = 0;
166 while (j != table.size()) { 166 while (j != table.size()) {
167 const DecodeEntry& entry = Entry(table, j); 167 const DecodeEntry& entry = Entry(table, j);
168 if (entry.length != 0 && entry.length < total_indexed) { 168 if (entry.length != 0 && entry.length < total_indexed) {
169 // The difference between entry & table bit counts tells us how 169 // The difference between entry & table bit counts tells us how
170 // many additional entries map to this one. 170 // many additional entries map to this one.
171 size_t fill_count = 1 << (total_indexed - entry.length); 171 size_t fill_count = 1 << (total_indexed - entry.length);
172 CHECK_LE(j + fill_count, table.size()); 172 CHECK_LE(j + fill_count, table.size());
173 173
174 for (size_t k = 1; k != fill_count; k++) { 174 for (size_t k = 1; k != fill_count; k++) {
175 CHECK_EQ(Entry(table, j + k).length, 0); 175 CHECK_EQ(Entry(table, j + k).length, 0);
176 SetEntry(table, j + k, entry); 176 SetEntry(table, j + k, entry);
177 } 177 }
178 j += fill_count; 178 j += fill_count;
179 } else { 179 } else {
180 j++; 180 j++;
181 } 181 }
182 } 182 }
183 } 183 }
184 } 184 }
185 185
186 uint8 HpackHuffmanTable::AddDecodeTable(uint8 prefix, uint8 indexed) { 186 uint8_t HpackHuffmanTable::AddDecodeTable(uint8_t prefix, uint8_t indexed) {
187 CHECK_LT(decode_tables_.size(), 255u); 187 CHECK_LT(decode_tables_.size(), 255u);
188 { 188 {
189 DecodeTable table; 189 DecodeTable table;
190 table.prefix_length = prefix; 190 table.prefix_length = prefix;
191 table.indexed_length = indexed; 191 table.indexed_length = indexed;
192 table.entries_offset = decode_entries_.size(); 192 table.entries_offset = decode_entries_.size();
193 decode_tables_.push_back(table); 193 decode_tables_.push_back(table);
194 } 194 }
195 decode_entries_.resize(decode_entries_.size() + (size_t(1) << indexed)); 195 decode_entries_.resize(decode_entries_.size() + (size_t(1) << indexed));
196 return static_cast<uint8>(decode_tables_.size() - 1); 196 return static_cast<uint8_t>(decode_tables_.size() - 1);
197 } 197 }
198 198
199 const HpackHuffmanTable::DecodeEntry& HpackHuffmanTable::Entry( 199 const HpackHuffmanTable::DecodeEntry& HpackHuffmanTable::Entry(
200 const DecodeTable& table, 200 const DecodeTable& table,
201 uint32 index) const { 201 uint32_t index) const {
202 DCHECK_LT(index, table.size()); 202 DCHECK_LT(index, table.size());
203 DCHECK_LT(table.entries_offset + index, decode_entries_.size()); 203 DCHECK_LT(table.entries_offset + index, decode_entries_.size());
204 return decode_entries_[table.entries_offset + index]; 204 return decode_entries_[table.entries_offset + index];
205 } 205 }
206 206
207 void HpackHuffmanTable::SetEntry(const DecodeTable& table, 207 void HpackHuffmanTable::SetEntry(const DecodeTable& table,
208 uint32 index, 208 uint32_t index,
209 const DecodeEntry& entry) { 209 const DecodeEntry& entry) {
210 CHECK_LT(index, table.size()); 210 CHECK_LT(index, table.size());
211 CHECK_LT(table.entries_offset + index, decode_entries_.size()); 211 CHECK_LT(table.entries_offset + index, decode_entries_.size());
212 decode_entries_[table.entries_offset + index] = entry; 212 decode_entries_[table.entries_offset + index] = entry;
213 } 213 }
214 214
215 bool HpackHuffmanTable::IsInitialized() const { 215 bool HpackHuffmanTable::IsInitialized() const {
216 return !code_by_id_.empty(); 216 return !code_by_id_.empty();
217 } 217 }
218 218
219 void HpackHuffmanTable::EncodeString(StringPiece in, 219 void HpackHuffmanTable::EncodeString(StringPiece in,
220 HpackOutputStream* out) const { 220 HpackOutputStream* out) const {
221 size_t bit_remnant = 0; 221 size_t bit_remnant = 0;
222 for (size_t i = 0; i != in.size(); i++) { 222 for (size_t i = 0; i != in.size(); i++) {
223 uint16 symbol_id = static_cast<uint8>(in[i]); 223 uint16_t symbol_id = static_cast<uint8_t>(in[i]);
224 CHECK_GT(code_by_id_.size(), symbol_id); 224 CHECK_GT(code_by_id_.size(), symbol_id);
225 225
226 // Load, and shift code to low bits. 226 // Load, and shift code to low bits.
227 unsigned length = length_by_id_[symbol_id]; 227 unsigned length = length_by_id_[symbol_id];
228 uint32 code = code_by_id_[symbol_id] >> (32 - length); 228 uint32_t code = code_by_id_[symbol_id] >> (32 - length);
229 229
230 bit_remnant = (bit_remnant + length) % 8; 230 bit_remnant = (bit_remnant + length) % 8;
231 231
232 if (length > 24) { 232 if (length > 24) {
233 out->AppendBits(static_cast<uint8>(code >> 24), length - 24); 233 out->AppendBits(static_cast<uint8_t>(code >> 24), length - 24);
234 length = 24; 234 length = 24;
235 } 235 }
236 if (length > 16) { 236 if (length > 16) {
237 out->AppendBits(static_cast<uint8>(code >> 16), length - 16); 237 out->AppendBits(static_cast<uint8_t>(code >> 16), length - 16);
238 length = 16; 238 length = 16;
239 } 239 }
240 if (length > 8) { 240 if (length > 8) {
241 out->AppendBits(static_cast<uint8>(code >> 8), length - 8); 241 out->AppendBits(static_cast<uint8_t>(code >> 8), length - 8);
242 length = 8; 242 length = 8;
243 } 243 }
244 out->AppendBits(static_cast<uint8>(code), length); 244 out->AppendBits(static_cast<uint8_t>(code), length);
245 } 245 }
246 if (bit_remnant != 0) { 246 if (bit_remnant != 0) {
247 // Pad current byte as required. 247 // Pad current byte as required.
248 out->AppendBits(pad_bits_ >> bit_remnant, 8 - bit_remnant); 248 out->AppendBits(pad_bits_ >> bit_remnant, 8 - bit_remnant);
249 } 249 }
250 } 250 }
251 251
252 size_t HpackHuffmanTable::EncodedSize(StringPiece in) const { 252 size_t HpackHuffmanTable::EncodedSize(StringPiece in) const {
253 size_t bit_count = 0; 253 size_t bit_count = 0;
254 for (size_t i = 0; i != in.size(); i++) { 254 for (size_t i = 0; i != in.size(); i++) {
255 uint16 symbol_id = static_cast<uint8>(in[i]); 255 uint16_t symbol_id = static_cast<uint8_t>(in[i]);
256 CHECK_GT(code_by_id_.size(), symbol_id); 256 CHECK_GT(code_by_id_.size(), symbol_id);
257 257
258 bit_count += length_by_id_[symbol_id]; 258 bit_count += length_by_id_[symbol_id];
259 } 259 }
260 if (bit_count % 8 != 0) { 260 if (bit_count % 8 != 0) {
261 bit_count += 8 - bit_count % 8; 261 bit_count += 8 - bit_count % 8;
262 } 262 }
263 return bit_count / 8; 263 return bit_count / 8;
264 } 264 }
265 265
266 bool HpackHuffmanTable::DecodeString(HpackInputStream* in, 266 bool HpackHuffmanTable::DecodeString(HpackInputStream* in,
267 size_t out_capacity, 267 size_t out_capacity,
268 string* out) const { 268 string* out) const {
269 // Number of decode iterations required for a 32-bit code. 269 // Number of decode iterations required for a 32-bit code.
270 const int kDecodeIterations = static_cast<int>( 270 const int kDecodeIterations = static_cast<int>(
271 std::ceil((32.f - kDecodeTableRootBits) / kDecodeTableBranchBits)); 271 std::ceil((32.f - kDecodeTableRootBits) / kDecodeTableBranchBits));
272 272
273 out->clear(); 273 out->clear();
274 274
275 // Current input, stored in the high |bits_available| bits of |bits|. 275 // Current input, stored in the high |bits_available| bits of |bits|.
276 uint32 bits = 0; 276 uint32_t bits = 0;
277 size_t bits_available = 0; 277 size_t bits_available = 0;
278 bool peeked_success = in->PeekBits(&bits_available, &bits); 278 bool peeked_success = in->PeekBits(&bits_available, &bits);
279 279
280 while (true) { 280 while (true) {
281 const DecodeTable* table = &decode_tables_[0]; 281 const DecodeTable* table = &decode_tables_[0];
282 uint32 index = bits >> (32 - kDecodeTableRootBits); 282 uint32_t index = bits >> (32 - kDecodeTableRootBits);
283 283
284 for (int i = 0; i != kDecodeIterations; i++) { 284 for (int i = 0; i != kDecodeIterations; i++) {
285 DCHECK_LT(index, table->size()); 285 DCHECK_LT(index, table->size());
286 DCHECK_LT(Entry(*table, index).next_table_index, decode_tables_.size()); 286 DCHECK_LT(Entry(*table, index).next_table_index, decode_tables_.size());
287 287
288 table = &decode_tables_[Entry(*table, index).next_table_index]; 288 table = &decode_tables_[Entry(*table, index).next_table_index];
289 // Mask and shift the portion of the code being indexed into low bits. 289 // Mask and shift the portion of the code being indexed into low bits.
290 index = (bits << table->prefix_length) >> (32 - table->indexed_length); 290 index = (bits << table->prefix_length) >> (32 - table->indexed_length);
291 } 291 }
292 const DecodeEntry& entry = Entry(*table, index); 292 const DecodeEntry& entry = Entry(*table, index);
(...skipping 22 matching lines...) Expand all
315 bits = bits << entry.length; 315 bits = bits << entry.length;
316 bits_available -= entry.length; 316 bits_available -= entry.length;
317 } 317 }
318 peeked_success = in->PeekBits(&bits_available, &bits); 318 peeked_success = in->PeekBits(&bits_available, &bits);
319 } 319 }
320 NOTREACHED(); 320 NOTREACHED();
321 return false; 321 return false;
322 } 322 }
323 323
324 } // namespace net 324 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/hpack/hpack_huffman_table.h ('k') | net/spdy/hpack/hpack_input_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698