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);