Protobuf C++: Optimize printing ranges of strings which do not need escaping. This path is especially hot because field names are printed as camelcased string keys and use this path, and those are generally all [a-zA-Z0-9]+ and very rarely have any escaping. PiperOrigin-RevId: 911535727
diff --git a/src/google/protobuf/json/BUILD b/src/google/protobuf/json/BUILD index e2c9109..6784216 100644 --- a/src/google/protobuf/json/BUILD +++ b/src/google/protobuf/json/BUILD
@@ -89,6 +89,7 @@ "@abseil-cpp//absl/algorithm:container", "@abseil-cpp//absl/log:absl_check", "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:charset", "@abseil-cpp//absl/strings:str_format", ], )
diff --git a/src/google/protobuf/json/internal/writer.cc b/src/google/protobuf/json/internal/writer.cc index cded1c5..f265a35 100644 --- a/src/google/protobuf/json/internal/writer.cc +++ b/src/google/protobuf/json/internal/writer.cc
@@ -7,13 +7,15 @@ #include "google/protobuf/json/internal/writer.h" +#include <cstddef> #include <cstdint> -#include <initializer_list> #include <limits> #include <utility> #include "absl/algorithm/container.h" #include "absl/log/absl_check.h" +#include "absl/strings/charset.h" +#include "absl/strings/string_view.h" // Must be included last. #include "google/protobuf/port_def.inc" @@ -266,8 +268,33 @@ } } +namespace { + +std::pair<absl::string_view, absl::string_view> SplitAtFirst( + absl::string_view str, absl::CharSet charset) { + size_t i = 0; + while (i < str.size() && !charset.contains(str[i])) { + i++; + } + return {str.substr(0, i), str.substr(i)}; +} + +} // namespace + void JsonWriter::WriteEscapedUtf8(absl::string_view str) { while (!str.empty()) { + static constexpr absl::CharSet kUnsafeChars = + ~absl::CharSet::AsciiPrintable() | absl::CharSet("\"\\<>"); + + auto [safe_prefix, rest] = SplitAtFirst(str, kUnsafeChars); + if (!safe_prefix.empty()) { + Write(safe_prefix); + str = rest; + if (str.empty()) { + break; + } + } + auto scalar = ConsumeUtf8Scalar(str); absl::string_view custom_escape;