Uses constexpr to improve header validation code generation. Thank you to ricea@google.com for the suggestion! ``` $ benchy --perflab --reference=srcfs //third_party/http2/adapter:header_validator_benchmark (Generated by http://go/benchy. Settings: --runs 5 --reference "srcfs" --perflab) name old cpu/op new cpu/op delta BM_ValidateSingleHeaderForRequests 527ns ± 3% 408ns ± 1% -22.64% (p=0.016 n=5+4) BM_ValidateSingleHeaderForResponses 818ns ±17% 628ns ± 3% -23.23% (p=0.008 n=5+5) name old time/op new time/op delta BM_ValidateSingleHeaderForRequests 528ns ± 3% 409ns ± 1% -22.65% (p=0.016 n=5+4) BM_ValidateSingleHeaderForResponses 821ns ±17% 630ns ± 3% -23.28% (p=0.008 n=5+5) name old INSTRUCTIONS/op new INSTRUCTIONS/op delta BM_ValidateSingleHeaderForRequests 5.75k ± 0% 4.69k ± 0% -18.50% (p=0.008 n=5+5) BM_ValidateSingleHeaderForResponses 8.21k ± 0% 6.72k ± 0% -18.19% (p=0.008 n=5+5) name old CYCLES/op new CYCLES/op delta BM_ValidateSingleHeaderForRequests 1.73k ± 0% 1.32k ± 1% -23.81% (p=0.008 n=5+5) BM_ValidateSingleHeaderForResponses 2.59k ± 1% 2.01k ± 0% -22.42% (p=0.008 n=5+5) name old allocs/op new allocs/op delta BM_ValidateSingleHeaderForResponses 1.00 ± 0% 1.00 ± 0% ~ (all samples are equal) name old peak-mem(Bytes)/op new peak-mem(Bytes)/op delta BM_ValidateSingleHeaderForResponses 32.0 ± 0% 32.0 ± 0% ~ (all samples are equal) Results uploaded to http://sponge2/818994d8-6ad4-4dce-ad8f-42319ec5f962 ``` PiperOrigin-RevId: 601176797
diff --git a/quiche/http2/adapter/header_validator.cc b/quiche/http2/adapter/header_validator.cc index b7dd1f8..211d264 100644 --- a/quiche/http2/adapter/header_validator.cc +++ b/quiche/http2/adapter/header_validator.cc
@@ -17,47 +17,45 @@ namespace { // From RFC 9110 Section 5.6.2. -const absl::string_view kHttpTokenChars = +constexpr absl::string_view kHttpTokenChars = "!#$%&'*+-.^_`|~0123456789" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; -const absl::string_view kHttp2HeaderNameAllowedChars = +constexpr absl::string_view kHttp2HeaderNameAllowedChars = "!#$%&'*+-.0123456789" "^_`abcdefghijklmnopqrstuvwxyz|~"; -const absl::string_view kHttp2HeaderValueAllowedChars = +constexpr absl::string_view kHttp2HeaderValueAllowedChars = "\t " "!\"#$%&'()*+,-./" "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" "abcdefghijklmnopqrstuvwxyz{|}~"; -const absl::string_view kHttp2StatusValueAllowedChars = "0123456789"; +constexpr absl::string_view kHttp2StatusValueAllowedChars = "0123456789"; -const absl::string_view kValidAuthorityChars = +constexpr absl::string_view kValidAuthorityChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~%!$&'()[" "]*+,;=:"; -const absl::string_view kValidPathChars = +constexpr absl::string_view kValidPathChars = "/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~%!$&'()" "*+,;=:@?"; -const absl::string_view kValidPathCharsWithFragment = +constexpr absl::string_view kValidPathCharsWithFragment = "/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~%!$&'()" "*+,;=:@?#"; using CharMap = std::array<bool, 256>; -CharMap BuildValidCharMap(absl::string_view valid_chars) { - CharMap map; - map.fill(false); +constexpr CharMap BuildValidCharMap(absl::string_view valid_chars) { + CharMap map = {}; for (char c : valid_chars) { - // Cast to uint8_t, guaranteed to have 8 bits. A char may have more, leading - // to possible indices above 256. + // An array index must be a nonnegative integer, hence the cast to uint8_t. map[static_cast<uint8_t>(c)] = true; } return map; } -CharMap AllowObsText(CharMap map) { +constexpr CharMap AllowObsText(CharMap map) { // Characters above 0x80 are allowed in header field values as `obs-text` in // RFC 7230. for (uint8_t c = 0xff; c >= 0x80; --c) { @@ -76,13 +74,13 @@ } bool IsValidStatus(absl::string_view status) { - static const CharMap valid_chars = + static constexpr CharMap valid_chars = BuildValidCharMap(kHttp2StatusValueAllowedChars); return AllCharsInMap(status, valid_chars); } bool IsValidMethod(absl::string_view method) { - static const CharMap valid_chars = BuildValidCharMap(kHttpTokenChars); + static constexpr CharMap valid_chars = BuildValidCharMap(kHttpTokenChars); return AllCharsInMap(method, valid_chars); } @@ -244,16 +242,16 @@ } bool HeaderValidator::IsValidHeaderName(absl::string_view name) { - static const CharMap valid_chars = + static constexpr CharMap valid_chars = BuildValidCharMap(kHttp2HeaderNameAllowedChars); return AllCharsInMap(name, valid_chars); } bool HeaderValidator::IsValidHeaderValue(absl::string_view value, ObsTextOption option) { - static const CharMap valid_chars = + static constexpr CharMap valid_chars = BuildValidCharMap(kHttp2HeaderValueAllowedChars); - static const CharMap valid_chars_with_obs_text = + static constexpr CharMap valid_chars_with_obs_text = AllowObsText(BuildValidCharMap(kHttp2HeaderValueAllowedChars)); return AllCharsInMap(value, option == ObsTextOption::kAllow ? valid_chars_with_obs_text @@ -261,13 +259,14 @@ } bool HeaderValidator::IsValidAuthority(absl::string_view authority) { - static const CharMap valid_chars = BuildValidCharMap(kValidAuthorityChars); + static constexpr CharMap valid_chars = + BuildValidCharMap(kValidAuthorityChars); return AllCharsInMap(authority, valid_chars); } bool HeaderValidator::IsValidPath(absl::string_view path, bool allow_fragment) { - static const CharMap valid_chars = BuildValidCharMap(kValidPathChars); - static const CharMap valid_chars_with_fragment = + static constexpr CharMap valid_chars = BuildValidCharMap(kValidPathChars); + static constexpr CharMap valid_chars_with_fragment = BuildValidCharMap(kValidPathCharsWithFragment); if (allow_fragment) { return AllCharsInMap(path, valid_chars_with_fragment);