Use constexpr to simplify HPACK parser (#26656)

* Use constexpr to simplify HPACK parser

This is a bit of a trial balloon: in C++11, generate at load time a
table that used to be hard coded. In C++14, generate that same table at
compile time, but eliminate the code generator.

Should this work out, I'd like to expand the technique so that we can
eliminate some of the confusing tables in this file by keeping the code
that generates them *in the same place* as the code that consumes them.

* comments

* c++14 fixes
pull/26682/head
Craig Tiller 3 years ago committed by GitHub
parent 2dc2ef02c3
commit 95dfe09710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 58
      src/core/ext/transport/chttp2/transport/hpack_parser.cc
  2. 19
      tools/codegen/core/gen_hpack_tables.cc

@ -40,6 +40,14 @@
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/http2_errors.h"
#if __cplusplus > 201103L
#define GRPC_HPACK_CONSTEXPR_FN constexpr
#define GRPC_HPACK_CONSTEXPR_VALUE constexpr
#else
#define GRPC_HPACK_CONSTEXPR_FN
#define GRPC_HPACK_CONSTEXPR_VALUE const
#endif
grpc_core::DebugOnlyTraceFlag grpc_trace_chttp2_hpack_parser(
false, "chttp2_hpack_parser");
@ -617,27 +625,31 @@ static const int16_t emit_sub_tbl[249 * 16] = {
13, 22, 22, 22, 22, 256, 256, 256, 256,
};
static const uint8_t inverse_base64[256] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255,
255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
255, 64, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255,
namespace {
// The alphabet used for base64 encoding binary metadata.
static constexpr char kBase64Alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// An inverted table: for each value in kBase64Alphabet, table contains the
// index with which it's stored, so we can quickly invert the encoding without
// any complicated runtime logic.
struct Base64InverseTable {
uint8_t table[256]{};
GRPC_HPACK_CONSTEXPR_FN Base64InverseTable() {
for (int i = 0; i < 256; i++) {
table[i] = 255;
}
for (const char* p = kBase64Alphabet; *p; p++) {
uint8_t idx = *p;
uint8_t ofs = p - kBase64Alphabet;
table[idx] = ofs;
}
}
};
static GRPC_HPACK_CONSTEXPR_VALUE Base64InverseTable kBase64InverseTable;
} // namespace
static void GPR_ATTRIBUTE_NOINLINE on_hdr_log(grpc_mdelem md) {
char* k = grpc_slice_to_c_string(GRPC_MDKEY(md));
char* v = nullptr;
@ -1325,7 +1337,7 @@ static grpc_error_handle append_string(grpc_chttp2_hpack_parser* p,
p->binary = B64_BYTE0;
return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
bits = kBase64InverseTable.table[*cur];
++cur;
if (bits == 255) {
return parse_error(
@ -1342,7 +1354,7 @@ static grpc_error_handle append_string(grpc_chttp2_hpack_parser* p,
p->binary = B64_BYTE1;
return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
bits = kBase64InverseTable.table[*cur];
++cur;
if (bits == 255) {
return parse_error(
@ -1359,7 +1371,7 @@ static grpc_error_handle append_string(grpc_chttp2_hpack_parser* p,
p->binary = B64_BYTE2;
return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
bits = kBase64InverseTable.table[*cur];
++cur;
if (bits == 255) {
return parse_error(
@ -1376,7 +1388,7 @@ static grpc_error_handle append_string(grpc_chttp2_hpack_parser* p,
p->binary = B64_BYTE3;
return GRPC_ERROR_NONE;
}
bits = inverse_base64[*cur];
bits = kBase64InverseTable.table[*cur];
++cur;
if (bits == 255) {
return parse_error(

@ -325,29 +325,10 @@ static void generate_base64_huff_encoder_table(void) {
printf("};\n");
}
static void generate_base64_inverse_table(void) {
static const char alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
unsigned char inverse[256];
unsigned i;
memset(inverse, 255, sizeof(inverse));
for (i = 0; i < strlen(alphabet); i++) {
inverse[(unsigned char)alphabet[i]] = (unsigned char)i;
}
printf("static const gpr_uint8 inverse_base64[256] = {");
for (i = 0; i < 256; i++) {
printf("%d,", inverse[i]);
}
printf("};\n");
}
int main(void) {
generate_huff_tables();
generate_first_byte_lut();
generate_base64_huff_encoder_table();
generate_base64_inverse_table();
return 0;
}

Loading…
Cancel
Save