diff options
author | nechda <[email protected]> | 2024-08-29 23:50:27 +0300 |
---|---|---|
committer | nechda <[email protected]> | 2024-08-30 00:05:25 +0300 |
commit | e10d6638f07a82edae3ea8197b9f5c0affcc07ea (patch) | |
tree | 571c38cec05813766a1ad290c9d51ce7ace52919 /contrib/libs/protoc/src/google/protobuf/compiler/cpp | |
parent | e79b38f2bbbf78d295d1901d2a79f898022d5224 (diff) |
Update cpp-protobuf to 22.5
Привет!\
Этот PR переключат cpp & python библиотеки protobuf на версию 22.5
Если у вас возникли проблемы после влития этого PR:
1. Если начали падать канон тесты, то проведите их переканонизацию
2. Прочитайте <https://wiki.yandex-team.ru/users/nechda/obnovlenie-cpp-protobuf-22.5/> страничку с основными изменениями
3. Если страничка в вики не помогла, то пишите в [DEVTOOLSSUPPORT](https://st.yandex-team.ru/DEVTOOLSSUPPORT)
7fecade616c20a841b9e9af7b7998bdfc8d2807d
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/cpp')
39 files changed, 7397 insertions, 7563 deletions
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.cc index 91d0b9442b7..917cc761288 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.cc @@ -32,26 +32,49 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/enum.h> +#include "google/protobuf/compiler/cpp/enum.h" +#include <algorithm> #include <cstdint> #include <limits> -#include <map> - -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/cpp/names.h> +#include <string> +#include <utility> +#include <vector> + +#include "google/protobuf/descriptor.h" +#include "y_absl/container/btree_map.h" +#include "y_absl/container/btree_set.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/names.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - namespace { -// The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value -// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the -// generation of the GOOGLE_ARRAYSIZE constant. +using Sub = ::google::protobuf::io::Printer::Sub; + +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> EnumVars( + const EnumDescriptor* enum_, const Options& options, + const EnumValueDescriptor* min, const EnumValueDescriptor* max) { + auto classname = ClassName(enum_, false); + return { + {"Enum", enum_->name()}, + {"Enum_", ResolveKeyword(enum_->name())}, + {"Msg_Enum", classname}, + {"::Msg_Enum", QualifiedClassName(enum_, options)}, + {"Msg_Enum_", + enum_->containing_type() == nullptr ? "" : y_absl::StrCat(classname, "_")}, + {"kMin", y_absl::StrCat(min->number())}, + {"kMax", y_absl::StrCat(max->number())}, + }; +} + +// The ARRAYSIZE constant is the max enum value plus 1. If the max enum value +// is kint32max, ARRAYSIZE will overflow. In such cases we should omit the +// generation of the ARRAYSIZE constant. bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) { arc_i32 max_value = descriptor->value(0)->number(); for (int i = 0; i < descriptor->value_count(); i++) { @@ -61,251 +84,323 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) { } return max_value != std::numeric_limits<arc_i32>::max(); } - -// Returns the number of unique numeric enum values. This is less than -// descriptor->value_count() when there are aliased values. -int CountUniqueValues(const EnumDescriptor* descriptor) { - std::set<int> values; - for (int i = 0; i < descriptor->value_count(); ++i) { - values.insert(descriptor->value(i)->number()); +} // namespace +EnumGenerator::ValueLimits EnumGenerator::ValueLimits::FromEnum( + const EnumDescriptor* descriptor) { + const EnumValueDescriptor* min_desc = descriptor->value(0); + const EnumValueDescriptor* max_desc = descriptor->value(0); + + for (int i = 1; i < descriptor->value_count(); ++i) { + if (descriptor->value(i)->number() < min_desc->number()) { + min_desc = descriptor->value(i); + } + if (descriptor->value(i)->number() > max_desc->number()) { + max_desc = descriptor->value(i); + } } - return values.size(); -} -} // namespace + return EnumGenerator::ValueLimits{min_desc, max_desc}; +} EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, - const std::map<TProtoStringType, TProtoStringType>& vars, const Options& options) - : descriptor_(descriptor), - classname_(ClassName(descriptor, false)), + : enum_(descriptor), options_(options), generate_array_size_(ShouldGenerateArraySize(descriptor)), - variables_(vars) { - variables_["classname"] = classname_; - variables_["classtype"] = QualifiedClassName(descriptor_, options); - variables_["short_name"] = descriptor_->name(); - variables_["nested_name"] = descriptor_->name(); - variables_["resolved_name"] = ResolveKeyword(descriptor_->name()); - variables_["prefix"] = - (descriptor_->containing_type() == nullptr) ? "" : classname_ + "_"; + has_reflection_(HasDescriptorMethods(enum_->file(), options_)), + limits_(ValueLimits::FromEnum(enum_)) { + // The conditions here for what is "sparse" are not rigorously + // chosen. + size_t values_range = static_cast<size_t>(limits_.max->number()) - + static_cast<size_t>(limits_.min->number()); + size_t total_values = static_cast<size_t>(enum_->value_count()); + should_cache_ = has_reflection_ && + (values_range < 16u || values_range < total_values * 2u); } -EnumGenerator::~EnumGenerator() {} - -void EnumGenerator::GenerateDefinition(io::Printer* printer) { - Formatter format(printer, variables_); - format("enum ${1$$classname$$}$ : int {\n", descriptor_); - format.Indent(); - - const EnumValueDescriptor* min_value = descriptor_->value(0); - const EnumValueDescriptor* max_value = descriptor_->value(0); - - for (int i = 0; i < descriptor_->value_count(); i++) { - auto format_value = format; - format_value.Set("name", EnumValueName(descriptor_->value(i))); - // In C++, an value of -2147483648 gets interpreted as the negative of - // 2147483648, and since 2147483648 can't fit in an integer, this produces a - // compiler warning. This works around that issue. - format_value.Set("number", Int32ToString(descriptor_->value(i)->number())); - format_value.Set("deprecation", - DeprecatedAttribute(options_, descriptor_->value(i))); - - if (i > 0) format_value(",\n"); - format_value("${1$$prefix$$name$$}$ $deprecation$= $number$", - descriptor_->value(i)); - - if (descriptor_->value(i)->number() < min_value->number()) { - min_value = descriptor_->value(i); - } - if (descriptor_->value(i)->number() > max_value->number()) { - max_value = descriptor_->value(i); - } - } - - if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { - // For new enum semantics: generate min and max sentinel values equal to - // INT32_MIN and INT32_MAX - if (descriptor_->value_count() > 0) format(",\n"); - format( - "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = " - "std::numeric_limits<$int32$>::min(),\n" - "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = " - "std::numeric_limits<$int32$>::max()"); - } - - format.Outdent(); - format("\n};\n"); - - format( - "$dllexport_decl $bool $classname$_IsValid(int value);\n" - "constexpr $classname$ ${1$$prefix$$short_name$_MIN$}$ = " - "$prefix$$2$;\n" - "constexpr $classname$ ${1$$prefix$$short_name$_MAX$}$ = " - "$prefix$$3$;\n", - descriptor_, EnumValueName(min_value), EnumValueName(max_value)); +void EnumGenerator::GenerateDefinition(io::Printer* p) { + auto v1 = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max)); + + auto v2 = p->WithVars({ + Sub("Msg_Enum_Enum_MIN", + y_absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_MIN")) + .AnnotatedAs(enum_), + Sub("Msg_Enum_Enum_MAX", + y_absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_MAX")) + .AnnotatedAs(enum_), + }); + p->Emit( + { + {"values", + [&] { + for (int i = 0; i < enum_->value_count(); ++i) { + const auto* value = enum_->value(i); + p->Emit( + { + Sub("Msg_Enum_VALUE", + y_absl::StrCat(p->LookupVar("Msg_Enum_"), + EnumValueName(value))) + .AnnotatedAs(value), + {"kNumber", Int32ToString(value->number())}, + {"DEPRECATED", value->options().deprecated() + ? "PROTOBUF_DEPRECATED_ENUM" + : ""}, + }, + R"cc( + $Msg_Enum_VALUE$$ DEPRECATED$ = $kNumber$, + )cc"); + } + }}, + // Only emit annotations for the $Msg_Enum$ used in the `enum` + // definition. + Sub("Msg_Enum_annotated", p->LookupVar("Msg_Enum")) + .AnnotatedAs(enum_), + {"open_enum_sentinels", + [&] { + if (enum_->is_closed()) { + return; + } + + // For open enum semantics: generate min and max sentinel values + // equal to INT32_MIN and INT32_MAX + p->Emit({{"Msg_Enum_Msg_Enum_", + y_absl::StrCat(p->LookupVar("Msg_Enum"), "_", + p->LookupVar("Msg_Enum_"))}}, + R"cc( + $Msg_Enum_Msg_Enum_$INT_MIN_SENTINEL_DO_NOT_USE_ = + std::numeric_limits<::arc_i32>::min(), + $Msg_Enum_Msg_Enum_$INT_MAX_SENTINEL_DO_NOT_USE_ = + std::numeric_limits<::arc_i32>::max(), + )cc"); + }}, + }, + R"cc( + enum $Msg_Enum_annotated$ : int { + $values$, + $open_enum_sentinels$, + }; + + $dllexport_decl $bool $Msg_Enum$_IsValid(int value); + constexpr $Msg_Enum$ $Msg_Enum_Enum_MIN$ = static_cast<$Msg_Enum$>($kMin$); + constexpr $Msg_Enum$ $Msg_Enum_Enum_MAX$ = static_cast<$Msg_Enum$>($kMax$); + )cc"); if (generate_array_size_) { - format( - "constexpr int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = " - "$prefix$$short_name$_MAX + 1;\n\n", - descriptor_); + p->Emit({Sub("Msg_Enum_Enum_ARRAYSIZE", + y_absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), + "_ARRAYSIZE")) + .AnnotatedAs(enum_)}, + R"cc( + constexpr int $Msg_Enum_Enum_ARRAYSIZE$ = $kMax$ + 1; + )cc"); } - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "$dllexport_decl $const ::$proto_ns$::EnumDescriptor* " - "$classname$_descriptor();\n"); + if (has_reflection_) { + p->Emit(R"cc( + $dllexport_decl $const ::$proto_ns$::EnumDescriptor* + $Msg_Enum$_descriptor(); + )cc"); + } else { + p->Emit(R"cc( + const TProtoStringType& $Msg_Enum$_Name($Msg_Enum$ value); + )cc"); } - // The _Name and _Parse functions. The lite implementation is table-based, so - // we make sure to keep the tables hidden in the .cc file. - if (!HasDescriptorMethods(descriptor_->file(), options_)) { - format("const TProtoStringType& $classname$_Name($classname$ value);\n"); - } - // The _Name() function accepts the enum type itself but also any integral - // type. - format( - "template<typename T>\n" - "inline const TProtoStringType& $classname$_Name(T enum_t_value) {\n" - " static_assert(::std::is_same<T, $classname$>::value ||\n" - " ::std::is_integral<T>::value,\n" - " \"Incorrect type passed to function $classname$_Name.\");\n"); - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - " return ::$proto_ns$::internal::NameOfEnum(\n" - " $classname$_descriptor(), enum_t_value);\n"); + // There are three possible implementations of $Enum$_Name() and + // $Msg_Enum$_Parse(), depending on whether we are using a dense enum name + // cache or not, and whether or not we have reflection. Very little code is + // shared between the three, so it is split into three Emit() calls. + + // Can't use WithVars here, since callbacks can only be passed to Emit() + // directly. Because this includes $Enum$, it must be a callback. + auto write_assert = [&] { + p->Emit(R"cc( + static_assert(std::is_same<T, $Msg_Enum$>::value || + std::is_integral<T>::value, + "Incorrect type passed to $Enum$_Name()."); + )cc"); + }; + + if (should_cache_ || !has_reflection_) { + p->Emit({{"static_assert", write_assert}}, R"cc( + template <typename T> + const TProtoStringType& $Msg_Enum$_Name(T value) { + $static_assert$; + return $Msg_Enum$_Name(static_cast<$Msg_Enum$>(value)); + } + )cc"); + if (should_cache_) { + // Using the NameOfEnum routine can be slow, so we create a small + // cache of pointers to the TProtoStringType objects that reflection + // stores internally. This cache is a simple contiguous array of + // pointers, so if the enum values are sparse, it's not worth it. + p->Emit(R"cc( + template <> + inline const TProtoStringType& $Msg_Enum$_Name($Msg_Enum$ value) { + return ::$proto_ns$::internal::NameOfDenseEnum<$Msg_Enum$_descriptor, + $kMin$, $kMax$>( + static_cast<int>(value)); + } + )cc"); + } else { + p->Emit(R"cc( + const TProtoStringType& $Msg_Enum$_Name($Msg_Enum$ value); + )cc"); + } } else { - format( - " return $classname$_Name(static_cast<$classname$>(enum_t_value));\n"); + p->Emit({{"static_assert", write_assert}}, R"cc( + template <typename T> + const TProtoStringType& $Msg_Enum$_Name(T value) { + $static_assert$; + return ::$proto_ns$::internal::NameOfEnum($Msg_Enum$_descriptor(), value); + } + )cc"); } - format("}\n"); - - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "inline bool $classname$_Parse(\n" - " ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* " - "value) " - "{\n" - " return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n" - " $classname$_descriptor(), name, value);\n" - "}\n"); + + if (has_reflection_) { + p->Emit(R"cc( + inline bool $Msg_Enum$_Parse(y_absl::string_view name, $Msg_Enum$* value) { + return ::$proto_ns$::internal::ParseNamedEnum<$Msg_Enum$>( + $Msg_Enum$_descriptor(), name, value); + } + )cc"); } else { - format( - "bool $classname$_Parse(\n" - " ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* " - "value);\n"); + p->Emit(R"cc( + bool $Msg_Enum$_Parse(y_absl::string_view name, $Msg_Enum$* value); + )cc"); } } -void EnumGenerator::GenerateGetEnumDescriptorSpecializations( - io::Printer* printer) { - Formatter format(printer, variables_); - format( - "template <> struct is_proto_enum< $classtype$> : ::std::true_type " - "{};\n"); - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "template <>\n" - "inline const EnumDescriptor* GetEnumDescriptor< $classtype$>() {\n" - " return $classtype$_descriptor();\n" - "}\n"); +void EnumGenerator::GenerateGetEnumDescriptorSpecializations(io::Printer* p) { + auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max)); + + p->Emit(R"cc( + template <> + struct is_proto_enum<$::Msg_Enum$> : std::true_type {}; + )cc"); + if (!has_reflection_) { + return; } + p->Emit(R"cc( + template <> + inline const EnumDescriptor* GetEnumDescriptor<$::Msg_Enum$>() { + return $::Msg_Enum$_descriptor(); + } + )cc"); } -void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const { - Formatter format(printer, variables_); - format("typedef $classname$ $resolved_name$;\n"); - - for (int j = 0; j < descriptor_->value_count(); j++) { - TProtoStringType deprecated_attr = - DeprecatedAttribute(options_, descriptor_->value(j)); - format( - "$1$static constexpr $resolved_name$ ${2$$3$$}$ =\n" - " $classname$_$3$;\n", - deprecated_attr, descriptor_->value(j), - EnumValueName(descriptor_->value(j))); +void EnumGenerator::GenerateSymbolImports(io::Printer* p) const { + auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max)); + + p->Emit({Sub("Enum_", p->LookupVar("Enum_")).AnnotatedAs(enum_)}, R"cc( + using $Enum_$ = $Msg_Enum$; + )cc"); + + for (int j = 0; j < enum_->value_count(); ++j) { + const auto* value = enum_->value(j); + p->Emit( + { + Sub("VALUE", EnumValueName(enum_->value(j))).AnnotatedAs(value), + {"DEPRECATED", + value->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM" : ""}, + }, + R"cc( + $DEPRECATED $static constexpr $Enum_$ $VALUE$ = $Msg_Enum$_$VALUE$; + )cc"); } - format( - "static inline bool $nested_name$_IsValid(int value) {\n" - " return $classname$_IsValid(value);\n" - "}\n" - "static constexpr $resolved_name$ ${1$$nested_name$_MIN$}$ =\n" - " $classname$_$nested_name$_MIN;\n" - "static constexpr $resolved_name$ ${1$$nested_name$_MAX$}$ =\n" - " $classname$_$nested_name$_MAX;\n", - descriptor_); + p->Emit( + { + Sub("Enum_MIN", y_absl::StrCat(enum_->name(), "_MIN")) + .AnnotatedAs(enum_), + Sub("Enum_MAX", y_absl::StrCat(enum_->name(), "_MAX")) + .AnnotatedAs(enum_), + }, + R"cc( + static inline bool $Enum$_IsValid(int value) { + return $Msg_Enum$_IsValid(value); + } + static constexpr $Enum_$ $Enum_MIN$ = $Msg_Enum$_$Enum$_MIN; + static constexpr $Enum_$ $Enum_MAX$ = $Msg_Enum$_$Enum$_MAX; + )cc"); + if (generate_array_size_) { - format( - "static constexpr int ${1$$nested_name$_ARRAYSIZE$}$ =\n" - " $classname$_$nested_name$_ARRAYSIZE;\n", - descriptor_); + p->Emit( + { + Sub("Enum_ARRAYSIZE", y_absl::StrCat(enum_->name(), "_ARRAYSIZE")) + .AnnotatedAs(enum_), + }, + R"cc( + static constexpr int $Enum_ARRAYSIZE$ = $Msg_Enum$_$Enum$_ARRAYSIZE; + )cc"); } - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "static inline const ::$proto_ns$::EnumDescriptor*\n" - "$nested_name$_descriptor() {\n" - " return $classname$_descriptor();\n" - "}\n"); + if (has_reflection_) { + p->Emit(R"cc( + static inline const ::$proto_ns$::EnumDescriptor* $Enum$_descriptor() { + return $Msg_Enum$_descriptor(); + } + )cc"); } - format( - "template<typename T>\n" - "static inline const TProtoStringType& $nested_name$_Name(T enum_t_value) {\n" - " static_assert(::std::is_same<T, $resolved_name$>::value ||\n" - " ::std::is_integral<T>::value,\n" - " \"Incorrect type passed to function $nested_name$_Name.\");\n" - " return $classname$_Name(enum_t_value);\n" - "}\n"); - format( - "static inline bool " - "$nested_name$_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,\n" - " $resolved_name$* value) {\n" - " return $classname$_Parse(name, value);\n" - "}\n"); + p->Emit(R"cc( + template <typename T> + static inline const TProtoStringType& $Enum$_Name(T value) { + return $Msg_Enum$_Name(value); + } + static inline bool $Enum$_Parse(y_absl::string_view name, $Enum_$* value) { + return $Msg_Enum$_Parse(name, value); + } + )cc"); } -void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { - Formatter format(printer, variables_); - if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "const ::$proto_ns$::EnumDescriptor* $classname$_descriptor() {\n" - " ::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n" - " return $file_level_enum_descriptors$[$1$];\n" - "}\n", - idx); - } - - format( - "bool $classname$_IsValid(int value) {\n" - " switch (value) {\n"); - - // Multiple values may have the same number. Make sure we only cover - // each number once by first constructing a set containing all valid - // numbers, then printing a case statement for each element. - - std::set<int> numbers; - for (int j = 0; j < descriptor_->value_count(); j++) { - const EnumValueDescriptor* value = descriptor_->value(j); - numbers.insert(value->number()); - } +void EnumGenerator::GenerateMethods(int idx, io::Printer* p) { + auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max)); - for (std::set<int>::iterator iter = numbers.begin(); iter != numbers.end(); - ++iter) { - format(" case $1$:\n", Int32ToString(*iter)); + if (has_reflection_) { + p->Emit({{"idx", idx}}, R"cc( + const ::$proto_ns$::EnumDescriptor* $Msg_Enum$_descriptor() { + ::$proto_ns$::internal::AssignDescriptors(&$desc_table$); + return $file_level_enum_descriptors$[$idx$]; + } + )cc"); } - format( - " return true;\n" - " default:\n" - " return false;\n" - " }\n" - "}\n" - "\n"); - - if (!HasDescriptorMethods(descriptor_->file(), options_)) { + p->Emit({{"cases", + [&] { + // Multiple values may have the same number. Make sure we only + // cover each number once by first constructing a set containing + // all valid numbers, then printing a case statement for each + // element. + + std::vector<int> numbers; + numbers.reserve(enum_->value_count()); + for (int i = 0; i < enum_->value_count(); ++i) { + numbers.push_back(enum_->value(i)->number()); + } + // Sort and deduplicate `numbers`. + y_absl::c_sort(numbers); + numbers.erase(std::unique(numbers.begin(), numbers.end()), + numbers.end()); + + for (int n : numbers) { + p->Emit({{"n", n}}, R"cc( + case $n$: + )cc"); + } + }}}, + R"( + bool $Msg_Enum$_IsValid(int value) { + switch (value) { + $cases$; + return true; + default: + return false; + } + } + )"); + + if (!has_reflection_) { // In lite mode (where descriptors are unavailable), we generate separate // tables for mapping between enum names and numbers. The _entries table // contains the bulk of the data and is sorted by name, while @@ -319,119 +414,168 @@ void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { // numerical value. In cases where there are multiple names for the same // number, we treat the first name appearing in the .proto file as the // canonical one. - std::map<TProtoStringType, int> name_to_number; - std::map<int, TProtoStringType> number_to_canonical_name; - for (int i = 0; i < descriptor_->value_count(); i++) { - const EnumValueDescriptor* value = descriptor_->value(i); + + y_absl::btree_map<TProtoStringType, int> name_to_number; + y_absl::flat_hash_map<int, TProtoStringType> number_to_canonical_name; + for (int i = 0; i < enum_->value_count(); ++i) { + const auto* value = enum_->value(i); name_to_number.emplace(value->name(), value->number()); + // The same number may appear with multiple names, so we use emplace() to // let the first name win. number_to_canonical_name.emplace(value->number(), value->name()); } - format( - "static ::$proto_ns$::internal::ExplicitlyConstructed<TProtoStringType> " - "$classname$_strings[$1$] = {};\n\n", - CountUniqueValues(descriptor_)); - - // We concatenate all the names for a given enum into one big string - // literal. If instead we store an array of string literals, the linker - // seems to put all enum strings for a given .proto file in the same - // section, which hinders its ability to strip out unused strings. - format("static const char $classname$_names[] ="); - for (const auto& p : name_to_number) { - format("\n \"$1$\"", p.first); + // Build the offset table for the strings table. + struct Offset { + int number; + size_t index, byte_offset, len; + }; + std::vector<Offset> offsets; + size_t index = 0; + size_t offset = 0; + for (const auto& e : name_to_number) { + offsets.push_back(Offset{e.second, index, offset, e.first.size()}); + ++index; + offset += e.first.size(); } - format(";\n\n"); - - format( - "static const ::$proto_ns$::internal::EnumEntry $classname$_entries[] " - "= {\n"); - int i = 0; - std::map<int, int> number_to_index; - int data_index = 0; - for (const auto& p : name_to_number) { - format(" { {$classname$_names + $1$, $2$}, $3$ },\n", data_index, - p.first.size(), p.second); - if (number_to_canonical_name[p.second] == p.first) { - number_to_index.emplace(p.second, i); - } - ++i; - data_index += p.first.size(); - } - - format( - "};\n" - "\n" - "static const int $classname$_entries_by_number[] = {\n"); - for (const auto& p : number_to_index) { - format(" $1$, // $2$ -> $3$\n", p.second, p.first, - number_to_canonical_name[p.first]); - } - format( - "};\n" - "\n"); - - format( - "const TProtoStringType& $classname$_Name(\n" - " $classname$ value) {\n" - " static const bool dummy =\n" - " ::$proto_ns$::internal::InitializeEnumStrings(\n" - " $classname$_entries,\n" - " $classname$_entries_by_number,\n" - " $1$, $classname$_strings);\n" - " (void) dummy;\n" - " int idx = ::$proto_ns$::internal::LookUpEnumName(\n" - " $classname$_entries,\n" - " $classname$_entries_by_number,\n" - " $1$, value);\n" - " return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() :\n" - " $classname$_strings[idx].get();\n" - "}\n", - CountUniqueValues(descriptor_)); - format( - "bool $classname$_Parse(\n" - " ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* " - "value) " - "{\n" - " int int_value;\n" - " bool success = ::$proto_ns$::internal::LookUpEnumValue(\n" - " $classname$_entries, $1$, name, &int_value);\n" - " if (success) {\n" - " *value = static_cast<$classname$>(int_value);\n" - " }\n" - " return success;\n" - "}\n", - descriptor_->value_count()); + y_absl::c_sort(offsets, [](const auto& a, const auto& b) { + return a.byte_offset < b.byte_offset; + }); + + std::vector<Offset> offsets_by_number = offsets; + y_absl::c_sort(offsets_by_number, [](const auto& a, const auto& b) { + return a.number < b.number; + }); + + offsets_by_number.erase( + std::unique( + offsets_by_number.begin(), offsets_by_number.end(), + [](const auto& a, const auto& b) { return a.number == b.number; }), + offsets_by_number.end()); + + p->Emit( + { + {"num_unique", number_to_canonical_name.size()}, + {"num_declared", enum_->value_count()}, + {"names", + // We concatenate all the names for a given enum into one big + // string literal. If instead we store an array of string + // literals, the linker seems to put all enum strings for a given + // .proto file in the same section, which hinders its ability to + // strip out unused strings. + [&] { + for (const auto& e : name_to_number) { + p->Emit({{"name", e.first}}, R"cc( + "$name$" + )cc"); + } + }}, + {"entries", + [&] { + for (const auto& offset : offsets) { + p->Emit({{"number", offset.number}, + {"offset", offset.byte_offset}, + {"len", offset.len}}, + R"cc( + {{&$Msg_Enum$_names[$offset$], $len$}, $number$}, + )cc"); + } + }}, + {"entries_by_number", + [&] { + for (const auto& offset : offsets_by_number) { + p->Emit({{"number", offset.number}, + {"index", offset.index}, + {"name", number_to_canonical_name[offset.number]}}, + R"cc( + $index$, // $number$ -> $name$ + )cc"); + } + }}, + }, + R"cc( + static ::$proto_ns$::internal::ExplicitlyConstructed<TProtoStringType> + $Msg_Enum$_strings[$num_unique$] = {}; + + static const char $Msg_Enum$_names[] = { + $names$, + }; + + static const ::$proto_ns$::internal::EnumEntry $Msg_Enum$_entries[] = + { + $entries$, + }; + + static const int $Msg_Enum$_entries_by_number[] = { + $entries_by_number$, + }; + + const TProtoStringType& $Msg_Enum$_Name($Msg_Enum$ value) { + static const bool kDummy = + ::$proto_ns$::internal::InitializeEnumStrings( + $Msg_Enum$_entries, $Msg_Enum$_entries_by_number, + $num_unique$, $Msg_Enum$_strings); + (void)kDummy; + + int idx = ::$proto_ns$::internal::LookUpEnumName( + $Msg_Enum$_entries, $Msg_Enum$_entries_by_number, $num_unique$, + value); + return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() + : $Msg_Enum$_strings[idx].get(); + } + + bool $Msg_Enum$_Parse(y_absl::string_view name, $Msg_Enum$* value) { + int int_value; + bool success = ::$proto_ns$::internal::LookUpEnumValue( + $Msg_Enum$_entries, $num_declared$, name, &int_value); + if (success) { + *value = static_cast<$Msg_Enum$>(int_value); + } + return success; + } + )cc"); } - if (descriptor_->containing_type() != nullptr) { - TProtoStringType parent = ClassName(descriptor_->containing_type(), false); + if (enum_->containing_type() != nullptr) { // Before C++17, we must define the static constants which were // declared in the header, to give the linker a place to put them. // But MSVC++ pre-2015 and post-2017 (version 15.5+) insists that we not. - format( - "#if (__cplusplus < 201703) && " - "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n"); - - for (int i = 0; i < descriptor_->value_count(); i++) { - format("constexpr $classname$ $1$::$2$;\n", parent, - EnumValueName(descriptor_->value(i))); - } - format( - "constexpr $classname$ $1$::$nested_name$_MIN;\n" - "constexpr $classname$ $1$::$nested_name$_MAX;\n", - parent); - if (generate_array_size_) { - format("constexpr int $1$::$nested_name$_ARRAYSIZE;\n", parent); - } - - format( - "#endif // (__cplusplus < 201703) && " - "(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n"); + p->Emit( + { + {"Msg_", ClassName(enum_->containing_type(), false)}, + {"constexpr_storage", + [&] { + for (int i = 0; i < enum_->value_count(); i++) { + p->Emit({{"VALUE", EnumValueName(enum_->value(i))}}, + R"cc( + constexpr $Msg_Enum$ $Msg_$::$VALUE$; + )cc"); + } + }}, + {"array_size", + [&] { + if (generate_array_size_) { + p->Emit(R"cc( + constexpr int $Msg_$::$Enum$_ARRAYSIZE; + )cc"); + } + }}, + }, + R"( + #if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + + $constexpr_storage$; + constexpr $Msg_Enum$ $Msg_$::$Enum$_MIN; + constexpr $Msg_Enum$ $Msg_$::$Enum$_MAX; + $array_size$; + + #endif // (__cplusplus < 201703) && + // (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) + )"); } } - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.h index 550f43b1ed4..58a62f5533a 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.h @@ -35,67 +35,64 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ -#include <map> -#include <set> #include <string> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/options.h> - -namespace google { -namespace protobuf { -namespace io { -class Printer; // printer.h -} -} // namespace protobuf -} // namespace google +#include "google/protobuf/descriptor.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - class EnumGenerator { public: - // See generator.cc for the meaning of dllexport_decl. - EnumGenerator(const EnumDescriptor* descriptor, - const std::map<TProtoStringType, TProtoStringType>& vars, - const Options& options); - ~EnumGenerator(); + EnumGenerator(const EnumDescriptor* descriptor, const Options& options); + + EnumGenerator(const EnumGenerator&) = delete; + EnumGenerator& operator=(const EnumGenerator&) = delete; + + ~EnumGenerator() = default; // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for // nested enums. - void GenerateDefinition(io::Printer* printer); + void GenerateDefinition(io::Printer* p); // Generate specialization of GetEnumDescriptor<MyEnum>(). // Precondition: in ::google::protobuf namespace. - void GenerateGetEnumDescriptorSpecializations(io::Printer* printer); + void GenerateGetEnumDescriptorSpecializations(io::Printer* p); // For enums nested within a message, generate code to import all the enum's // symbols (e.g. the enum type name, all its values, etc.) into the class's // namespace. This should be placed inside the class definition in the // header. - void GenerateSymbolImports(io::Printer* printer) const; + void GenerateSymbolImports(io::Printer* p) const; // Source file stuff. // Generate non-inline methods related to the enum, such as IsValidValue(). // Goes in the .cc file. EnumDescriptors are stored in an array, idx is // the index in this array that corresponds with this enum. - void GenerateMethods(int idx, io::Printer* printer); + void GenerateMethods(int idx, io::Printer* p); private: - const EnumDescriptor* descriptor_; - const TProtoStringType classname_; - const Options& options_; - // whether to generate the *_ARRAYSIZE constant. - const bool generate_array_size_; + friend class FileGenerator; - std::map<TProtoStringType, TProtoStringType> variables_; + struct ValueLimits { + const EnumValueDescriptor* min; + const EnumValueDescriptor* max; - friend class FileGenerator; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); + static ValueLimits FromEnum(const EnumDescriptor* descriptor); + }; + + const EnumDescriptor* enum_; + Options options_; + + bool generate_array_size_; + bool should_cache_; + bool has_reflection_; + ValueLimits limits_; }; } // namespace cpp diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.cc deleted file mode 100644 index dc8dc524815..00000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.cc +++ /dev/null @@ -1,451 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: [email protected] (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <google/protobuf/compiler/cpp/enum_field.h> - -#include <google/protobuf/io/printer.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/field.h> -#include <google/protobuf/compiler/cpp/helpers.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -namespace { - -void SetEnumVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables, - const Options& options) { - SetCommonFieldVariables(descriptor, variables, options); - const EnumValueDescriptor* default_value = descriptor->default_value_enum(); - (*variables)["type"] = QualifiedClassName(descriptor->enum_type(), options); - (*variables)["default"] = Int32ToString(default_value->number()); - (*variables)["full_name"] = descriptor->full_name(); - (*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor); - bool cold = ShouldSplit(descriptor, options); - (*variables)["cached_byte_size_field"] = - MakeVarintCachedSizeFieldName(descriptor, cold); -} - -} // namespace - -// =================================================================== - -EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : FieldGenerator(descriptor, options) { - SetEnumVariables(descriptor, &variables_, options); -} - -EnumFieldGenerator::~EnumFieldGenerator() {} - -void EnumFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { - Formatter format(printer, variables_); - format("int $name$_;\n"); -} - -void EnumFieldGenerator::GenerateAccessorDeclarations( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "$deprecated_attr$$type$ ${1$$name$$}$() const;\n" - "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n" - "private:\n" - "$type$ ${1$_internal_$name$$}$() const;\n" - "void ${1$_internal_set_$name$$}$($type$ value);\n" - "public:\n", - descriptor_); -} - -void EnumFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline $type$ $classname$::_internal_$name$() const {\n" - " return static_cast< $type$ >($field$);\n" - "}\n" - "inline $type$ $classname$::$name$() const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return _internal_$name$();\n" - "}\n" - "inline void $classname$::_internal_set_$name$($type$ value) {\n"); - if (!HasPreservingUnknownEnumSemantics(descriptor_)) { - format(" assert($type$_IsValid(value));\n"); - } - format( - " $set_hasbit$\n" - " $field$ = value;\n" - "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" - "$maybe_prepare_split_message$" - " _internal_set_$name$(value);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); -} - -void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$ = $default$;\n"); -} - -void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - format("_this->_internal_set_$name$(from._internal_$name$());\n"); -} - -void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - format("swap($field$, other->$field$);\n"); -} - -void EnumFieldGenerator::GenerateCopyConstructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("_this->$field$ = from.$field$;\n"); -} - -void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "target = stream->EnsureSpace(target);\n" - "target = ::_pbi::WireFormatLite::WriteEnumToArray(\n" - " $number$, this->_internal_$name$(), target);\n"); -} - -void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "total_size += $tag_size$ +\n" - " ::_pbi::WireFormatLite::EnumSize(this->_internal_$name$());\n"); -} - -void EnumFieldGenerator::GenerateConstexprAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("/*decltype($field$)*/$default$"); -} - -void EnumFieldGenerator::GenerateAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (ShouldSplit(descriptor_, options_)) { - format("decltype(Impl_::Split::$name$_){$default$}"); - return; - } - format("decltype($field$){$default$}"); -} - -void EnumFieldGenerator::GenerateCopyAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("decltype($field$){}"); -} - -// =================================================================== - -EnumOneofFieldGenerator::EnumOneofFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) - : EnumFieldGenerator(descriptor, options) { - SetCommonOneofFieldVariables(descriptor, &variables_); -} - -EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {} - -void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline $type$ $classname$::_internal_$name$() const {\n" - " if (_internal_has_$name$()) {\n" - " return static_cast< $type$ >($field$);\n" - " }\n" - " return static_cast< $type$ >($default$);\n" - "}\n" - "inline $type$ $classname$::$name$() const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return _internal_$name$();\n" - "}\n" - "inline void $classname$::_internal_set_$name$($type$ value) {\n"); - if (!HasPreservingUnknownEnumSemantics(descriptor_)) { - format(" assert($type$_IsValid(value));\n"); - } - format( - " if (!_internal_has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " }\n" - " $field$ = value;\n" - "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" - " _internal_set_$name$(value);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); -} - -void EnumOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$ = $default$;\n"); -} - -void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { - // Don't print any swapping code. Swapping the union will swap this field. -} - -void EnumOneofFieldGenerator::GenerateConstructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n"); -} - -// =================================================================== - -RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(descriptor, options) { - SetEnumVariables(descriptor, &variables_, options); -} - -RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} - -void RepeatedEnumFieldGenerator::GeneratePrivateMembers( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("::$proto_ns$::RepeatedField<int> $name$_;\n"); - if (descriptor_->is_packed() && - HasGeneratedMethods(descriptor_->file(), options_)) { - format("mutable std::atomic<int> $cached_byte_size_name$;\n"); - } -} - -void RepeatedEnumFieldGenerator::GenerateAccessorDeclarations( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "private:\n" - "$type$ ${1$_internal_$name$$}$(int index) const;\n" - "void ${1$_internal_add_$name$$}$($type$ value);\n" - "::$proto_ns$::RepeatedField<int>* " - "${1$_internal_mutable_$name$$}$();\n" - "public:\n" - "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n" - "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n" - "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n" - "$deprecated_attr$const ::$proto_ns$::RepeatedField<int>& " - "${1$$name$$}$() const;\n" - "$deprecated_attr$::$proto_ns$::RepeatedField<int>* " - "${1$mutable_$name$$}$();\n", - descriptor_); -} - -void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline $type$ $classname$::_internal_$name$(int index) const {\n" - " return static_cast< $type$ >($field$.Get(index));\n" - "}\n" - "inline $type$ $classname$::$name$(int index) const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return _internal_$name$(index);\n" - "}\n" - "inline void $classname$::set_$name$(int index, $type$ value) {\n"); - if (!HasPreservingUnknownEnumSemantics(descriptor_)) { - format(" assert($type$_IsValid(value));\n"); - } - format( - " $field$.Set(index, value);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline void $classname$::_internal_add_$name$($type$ value) {\n"); - if (!HasPreservingUnknownEnumSemantics(descriptor_)) { - format(" assert($type$_IsValid(value));\n"); - } - format( - " $field$.Add(value);\n" - "}\n" - "inline void $classname$::add_$name$($type$ value) {\n" - " _internal_add_$name$(value);\n" - "$annotate_add$" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n" - "inline const ::$proto_ns$::RepeatedField<int>&\n" - "$classname$::$name$() const {\n" - "$annotate_list$" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $field$;\n" - "}\n" - "inline ::$proto_ns$::RepeatedField<int>*\n" - "$classname$::_internal_mutable_$name$() {\n" - " return &$field$;\n" - "}\n" - "inline ::$proto_ns$::RepeatedField<int>*\n" - "$classname$::mutable_$name$() {\n" - "$annotate_mutable_list$" - " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return _internal_mutable_$name$();\n" - "}\n"); -} - -void RepeatedEnumFieldGenerator::GenerateClearingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.Clear();\n"); -} - -void RepeatedEnumFieldGenerator::GenerateMergingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("_this->$field$.MergeFrom(from.$field$);\n"); -} - -void RepeatedEnumFieldGenerator::GenerateSwappingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.InternalSwap(&other->$field$);\n"); -} - -void RepeatedEnumFieldGenerator::GenerateConstructorCode( - io::Printer* printer) const { - // Not needed for repeated fields. -} - -void RepeatedEnumFieldGenerator::GenerateDestructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.~RepeatedField();\n"); -} - -void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (descriptor_->is_packed()) { - // Write the tag and the size. - format( - "{\n" - " int byte_size = " - "$cached_byte_size_field$.load(std::memory_order_relaxed);\n" - " if (byte_size > 0) {\n" - " target = stream->WriteEnumPacked(\n" - " $number$, $field$, byte_size, target);\n" - " }\n" - "}\n"); - } else { - format( - "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n" - " target = stream->EnsureSpace(target);\n" - " target = ::_pbi::WireFormatLite::WriteEnumToArray(\n" - " $number$, this->_internal_$name$(i), target);\n" - "}\n"); - } -} - -void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "{\n" - " size_t data_size = 0;\n" - " unsigned int count = static_cast<unsigned " - "int>(this->_internal_$name$_size());"); - format.Indent(); - format( - "for (unsigned int i = 0; i < count; i++) {\n" - " data_size += ::_pbi::WireFormatLite::EnumSize(\n" - " this->_internal_$name$(static_cast<int>(i)));\n" - "}\n"); - - if (descriptor_->is_packed()) { - format( - "if (data_size > 0) {\n" - " total_size += $tag_size$ +\n" - " " - "::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n" - "}\n" - "int cached_size = ::_pbi::ToCachedSize(data_size);\n" - "$cached_byte_size_field$.store(cached_size,\n" - " std::memory_order_relaxed);\n" - "total_size += data_size;\n"); - } else { - format("total_size += ($tag_size$UL * count) + data_size;\n"); - } - format.Outdent(); - format("}\n"); -} - -void RepeatedEnumFieldGenerator::GenerateConstexprAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("/*decltype($field$)*/{}"); - if (descriptor_->is_packed() && - HasGeneratedMethods(descriptor_->file(), options_)) { - format("\n, /*decltype($cached_byte_size_field$)*/{0}"); - } -} - -void RepeatedEnumFieldGenerator::GenerateAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("decltype($field$){arena}"); - if (descriptor_->is_packed() && - HasGeneratedMethods(descriptor_->file(), options_)) { - // std::atomic has no copy constructor, which prevents explicit aggregate - // initialization pre-C++17. - format("\n, /*decltype($cached_byte_size_field$)*/{0}"); - } -} - -void RepeatedEnumFieldGenerator::GenerateCopyAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("decltype($field$){from.$field$}"); - if (descriptor_->is_packed() && - HasGeneratedMethods(descriptor_->file(), options_)) { - // std::atomic has no copy constructor. - format("\n, /*decltype($cached_byte_size_field$)*/{0}"); - } -} - -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.h deleted file mode 100644 index 61bae855cd6..00000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.h +++ /dev/null @@ -1,125 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: [email protected] (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ - -#include <map> -#include <string> - -#include <google/protobuf/compiler/cpp/field.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -class EnumFieldGenerator : public FieldGenerator { - public: - EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~EnumFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override {} - void GenerateCopyConstructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstexprAggregateInitializer( - io::Printer* printer) const override; - void GenerateAggregateInitializer(io::Printer* printer) const override; - void GenerateCopyAggregateInitializer(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); -}; - -class EnumOneofFieldGenerator : public EnumFieldGenerator { - public: - EnumOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); - ~EnumOneofFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator); -}; - -class RepeatedEnumFieldGenerator : public FieldGenerator { - public: - RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); - ~RepeatedEnumFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override { - GOOGLE_CHECK(!ShouldSplit(descriptor_, options_)); - } - void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstexprAggregateInitializer( - io::Printer* printer) const override; - void GenerateAggregateInitializer(io::Printer* printer) const override; - void GenerateCopyAggregateInitializer(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); -}; - -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.cc index ed85f75960a..60ef25c1356 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.cc @@ -32,14 +32,13 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/extension.h> +#include "google/protobuf/compiler/cpp/extension.h" -#include <map> - -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/descriptor.pb.h> +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/str_replace.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { @@ -77,7 +76,6 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, type_traits_.append(" >"); break; } - SetCommonVars(options, &variables_); SetCommonMessageDataVariables(descriptor_->containing_type(), &variables_); variables_["extendee"] = QualifiedClassName(descriptor_->containing_type(), options_); @@ -86,14 +84,18 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, variables_["name"] = ResolveKeyword(name); variables_["constant_name"] = FieldConstantName(descriptor_); variables_["field_type"] = - StrCat(static_cast<int>(descriptor_->type())); + y_absl::StrCat(static_cast<int>(descriptor_->type())); variables_["packed"] = descriptor_->is_packed() ? "true" : "false"; - TProtoStringType scope = - IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : ""; + TProtoStringType scope; + if (IsScoped()) { + scope = + y_absl::StrCat(ClassName(descriptor_->extension_scope(), false), "::"); + } + variables_["scope"] = scope; variables_["scoped_name"] = ExtensionName(descriptor_); - variables_["number"] = StrCat(descriptor_->number()); + variables_["number"] = y_absl::StrCat(descriptor_->number()); bool add_verify_fn = // Only verify msgs. @@ -104,7 +106,7 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, variables_["verify_fn"] = add_verify_fn - ? StrCat("&", FieldMessageTypeName(descriptor_, options_), + ? y_absl::StrCat("&", FieldMessageTypeName(descriptor_, options_), "::InternalVerify") : "nullptr"; } @@ -125,7 +127,7 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) const { if (!IsScoped()) { qualifier = "extern"; if (!options_.dllexport_decl.empty()) { - qualifier = options_.dllexport_decl + " " + qualifier; + qualifier = y_absl::StrCat(options_.dllexport_decl, " ", qualifier); } } else { qualifier = "static"; @@ -159,14 +161,15 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { // it in the header which would be annoying for other reasons. So we // replace :: with _ in the name and declare it as a global. default_str = - StringReplace(variables_["scoped_name"], "::", "_", true) + "_default"; + y_absl::StrReplaceAll(variables_["scoped_name"], {{"::", "_"}}) + + "_default"; format("const TProtoStringType $1$($2$);\n", default_str, DefaultValue(options_, descriptor_)); } else if (descriptor_->message_type()) { // We have to initialize the default instance for extensions at registration // time. - default_str = - FieldMessageTypeName(descriptor_, options_) + "::default_instance()"; + default_str = y_absl::StrCat(FieldMessageTypeName(descriptor_, options_), + "::default_instance()"); } else { default_str = DefaultValue(options_, descriptor_); } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.h index b94b178868a..e93473dbab1 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.h @@ -35,11 +35,11 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ -#include <map> #include <string> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/cpp/options.h> +#include "y_absl/container/flat_hash_map.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/port.h" namespace google { namespace protobuf { @@ -66,6 +66,8 @@ class ExtensionGenerator { explicit ExtensionGenerator(const FieldDescriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer); + ExtensionGenerator(const ExtensionGenerator&) = delete; + ExtensionGenerator& operator=(const ExtensionGenerator&) = delete; ~ExtensionGenerator(); // Header stuff. @@ -82,9 +84,7 @@ class ExtensionGenerator { Options options_; MessageSCCAnalyzer* scc_analyzer_; - std::map<TProtoStringType, TProtoStringType> variables_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> variables_; }; } // namespace cpp diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.cc index d5359b6d247..361c039cc52 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.cc @@ -32,276 +32,89 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/field.h> +#include "google/protobuf/compiler/cpp/field.h" #include <cstdint> #include <memory> #include <string> - -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/substitute.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/cpp/primitive_field.h> -#include <google/protobuf/compiler/cpp/string_field.h> -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/compiler/cpp/enum_field.h> -#include <google/protobuf/compiler/cpp/map_field.h> -#include <google/protobuf/compiler/cpp/message_field.h> -#include <google/protobuf/descriptor.pb.h> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/strings/str_format.h" +#include "y_absl/strings/string_view.h" +#include "y_absl/types/optional.h" +#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/compiler/cpp/tracker.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/wire_format.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - -using internal::WireFormat; - -namespace { - -void MaySetAnnotationVariable(const Options& options, - StringPiece annotation_name, - StringPiece substitute_template_prefix, - StringPiece prepared_template, - int field_index, StringPiece access_type, - std::map<TProtoStringType, TProtoStringType>* variables) { - if (options.field_listener_options.forbidden_field_listener_events.count( - TProtoStringType(annotation_name))) - return; - (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute( - StrCat(substitute_template_prefix, prepared_template, ");\n"), - field_index, access_type); -} - -TProtoStringType GenerateTemplateForOneofString(const FieldDescriptor* descriptor, - StringPiece proto_ns, - StringPiece field_member) { - TProtoStringType field_name = google::protobuf::compiler::cpp::FieldName(descriptor); - TProtoStringType field_pointer = - descriptor->options().ctype() == google::protobuf::FieldOptions::STRING - ? "$0.UnsafeGetPointer()" - : "$0"; - - if (descriptor->default_value_string().empty()) { - return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ", - field_pointer, ": nullptr"), - field_member); - } - - if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING_PIECE) { - return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ", - field_pointer, ": nullptr"), - field_member); - } - - TProtoStringType default_value_pointer = - descriptor->options().ctype() == google::protobuf::FieldOptions::STRING - ? "&$1.get()" - : "&$1"; - return strings::Substitute( - StrCat("_internal_has_", field_name, "() ? ", field_pointer, " : ", - default_value_pointer), - field_member, MakeDefaultFieldName(descriptor)); -} - -TProtoStringType GenerateTemplateForSingleString(const FieldDescriptor* descriptor, - StringPiece field_member) { - if (descriptor->default_value_string().empty()) { - return StrCat("&", field_member); - } - - if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) { - return strings::Substitute( - "$0.IsDefault() ? &$1.get() : $0.UnsafeGetPointer()", field_member, - MakeDefaultFieldName(descriptor)); - } - - return StrCat("&", field_member); -} - -} // namespace - -void AddAccessorAnnotations(const FieldDescriptor* descriptor, - const Options& options, - std::map<TProtoStringType, TProtoStringType>* variables) { - // Can be expanded to include more specific calls, for example, for arena or - // clear calls. - static constexpr const char* kAccessorsAnnotations[] = { - "annotate_add", "annotate_get", "annotate_has", - "annotate_list", "annotate_mutable", "annotate_mutable_list", - "annotate_release", "annotate_set", "annotate_size", - "annotate_clear", "annotate_add_mutable", +using ::google::protobuf::internal::WireFormat; +using Sub = ::google::protobuf::io::Printer::Sub; + +std::vector<Sub> FieldVars(const FieldDescriptor* field, const Options& opts) { + bool split = ShouldSplit(field, opts); + std::vector<Sub> vars = { + // This will eventually be renamed to "field", once the existing "field" + // variable is replaced with "field_" everywhere. + {"name", FieldName(field)}, + + {"index", field->index()}, + {"number", field->number()}, + {"pkg.Msg.field", field->full_name()}, + + {"field_", FieldMemberName(field, split)}, + {"DeclaredType", DeclaredTypeMethodName(field->type())}, + {"kTagBytes", WireFormat::TagSize(field->number(), field->type())}, + Sub("PrepareSplitMessageForWrite", + split ? "PrepareSplitMessageForWrite();" : "") + .WithSuffix(";"), + Sub("DEPRECATED", DeprecatedAttribute(opts, field)).WithSuffix(" "), + + // These variables are placeholders to pick out the beginning and ends of + // identifiers for annotations (when doing so with existing variables + // would be ambiguous or impossible). They should never be set to anything + // but the empty string. + {"{", ""}, + {"}", ""}, + + // Old-style names. + {"field", FieldMemberName(field, split)}, + {"maybe_prepare_split_message", + split ? "PrepareSplitMessageForWrite();" : ""}, + {"declared_type", DeclaredTypeMethodName(field->type())}, + {"classname", ClassName(FieldScope(field), false)}, + {"ns", Namespace(field, opts)}, + {"tag_size", WireFormat::TagSize(field->number(), field->type())}, + {"deprecated_attr", DeprecatedAttribute(opts, field)}, }; - for (size_t i = 0; i < GOOGLE_ARRAYSIZE(kAccessorsAnnotations); ++i) { - (*variables)[kAccessorsAnnotations[i]] = ""; - } - if (options.annotate_accessor) { - for (size_t i = 0; i < GOOGLE_ARRAYSIZE(kAccessorsAnnotations); ++i) { - (*variables)[kAccessorsAnnotations[i]] = StrCat( - " ", FieldName(descriptor), "_AccessedNoStrip = true;\n"); - } - } - if (!options.field_listener_options.inject_field_listener_events) { - return; - } - if (descriptor->file()->options().optimize_for() == - google::protobuf::FileOptions::LITE_RUNTIME) { - return; - } - TProtoStringType field_member = (*variables)["field"]; - const google::protobuf::OneofDescriptor* oneof_member = - descriptor->real_containing_oneof(); - const TProtoStringType proto_ns = (*variables)["proto_ns"]; - const TProtoStringType substitute_template_prefix = - StrCat(" ", (*variables)["tracker"], ".$1<$0>(this, "); - TProtoStringType prepared_template; - - // Flat template is needed if the prepared one is introspecting the values - // inside the returned values, for example, for repeated fields and maps. - TProtoStringType prepared_flat_template; - TProtoStringType prepared_add_template; - // TODO(b/190614678): Support fields with type Message or Map. - if (descriptor->is_repeated() && !descriptor->is_map()) { - if (descriptor->type() != FieldDescriptor::TYPE_MESSAGE && - descriptor->type() != FieldDescriptor::TYPE_GROUP) { - prepared_template = strings::Substitute("&$0.Get(index)", field_member); - prepared_add_template = - strings::Substitute("&$0.Get($0.size() - 1)", field_member); - } else { - prepared_template = "nullptr"; - prepared_add_template = "nullptr"; - } - } else if (descriptor->is_map()) { - prepared_template = "nullptr"; - } else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE && - !IsExplicitLazy(descriptor)) { - prepared_template = "nullptr"; - } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { - if (oneof_member) { - prepared_template = GenerateTemplateForOneofString( - descriptor, (*variables)["proto_ns"], field_member); - } else { - prepared_template = - GenerateTemplateForSingleString(descriptor, field_member); - } - } else { - prepared_template = StrCat("&", field_member); - } - if (descriptor->is_repeated() && !descriptor->is_map() && - descriptor->type() != FieldDescriptor::TYPE_MESSAGE && - descriptor->type() != FieldDescriptor::TYPE_GROUP) { - prepared_flat_template = StrCat("&", field_member); - } else { - prepared_flat_template = prepared_template; - } - MaySetAnnotationVariable(options, "get", substitute_template_prefix, - prepared_template, descriptor->index(), "OnGet", - variables); - MaySetAnnotationVariable(options, "set", substitute_template_prefix, - prepared_template, descriptor->index(), "OnSet", - variables); - MaySetAnnotationVariable(options, "has", substitute_template_prefix, - prepared_template, descriptor->index(), "OnHas", - variables); - MaySetAnnotationVariable(options, "mutable", substitute_template_prefix, - prepared_template, descriptor->index(), "OnMutable", - variables); - MaySetAnnotationVariable(options, "release", substitute_template_prefix, - prepared_template, descriptor->index(), "OnRelease", - variables); - MaySetAnnotationVariable(options, "clear", substitute_template_prefix, - prepared_flat_template, descriptor->index(), - "OnClear", variables); - MaySetAnnotationVariable(options, "size", substitute_template_prefix, - prepared_flat_template, descriptor->index(), - "OnSize", variables); - MaySetAnnotationVariable(options, "list", substitute_template_prefix, - prepared_flat_template, descriptor->index(), - "OnList", variables); - MaySetAnnotationVariable(options, "mutable_list", substitute_template_prefix, - prepared_flat_template, descriptor->index(), - "OnMutableList", variables); - MaySetAnnotationVariable(options, "add", substitute_template_prefix, - prepared_add_template, descriptor->index(), "OnAdd", - variables); - MaySetAnnotationVariable(options, "add_mutable", substitute_template_prefix, - prepared_add_template, descriptor->index(), - "OnAddMutable", variables); -} - -void SetCommonFieldVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables, - const Options& options) { - SetCommonVars(options, variables); - SetCommonMessageDataVariables(descriptor->containing_type(), variables); - - (*variables)["ns"] = Namespace(descriptor, options); - (*variables)["name"] = FieldName(descriptor); - (*variables)["index"] = StrCat(descriptor->index()); - (*variables)["number"] = StrCat(descriptor->number()); - (*variables)["classname"] = ClassName(FieldScope(descriptor), false); - (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); - bool split = ShouldSplit(descriptor, options); - (*variables)["field"] = FieldMemberName(descriptor, split); - - (*variables)["tag_size"] = StrCat( - WireFormat::TagSize(descriptor->number(), descriptor->type())); - (*variables)["deprecated_attr"] = DeprecatedAttribute(options, descriptor); - - (*variables)["set_hasbit"] = ""; - (*variables)["clear_hasbit"] = ""; - (*variables)["maybe_prepare_split_message"] = - split ? " PrepareSplitMessageForWrite();\n" : ""; - - AddAccessorAnnotations(descriptor, options, variables); - - // These variables are placeholders to pick out the beginning and ends of - // identifiers for annotations (when doing so with existing variables would - // be ambiguous or impossible). They should never be set to anything but the - // empty string. - (*variables)["{"] = ""; - (*variables)["}"] = ""; -} - -void FieldGenerator::SetHasBitIndex(arc_i32 has_bit_index) { - if (!HasHasbit(descriptor_)) { - GOOGLE_CHECK_EQ(has_bit_index, -1); - return; + if (const auto* oneof = field->containing_oneof()) { + auto field_name = UnderscoresToCamelCase(field->name(), true); + + vars.push_back({"oneof_name", oneof->name()}); + vars.push_back({"field_name", field_name}); + vars.push_back({"oneof_index", oneof->index()}); + vars.push_back({"has_field", y_absl::StrFormat("%s_case() == k%s", + oneof->name(), field_name)}); + vars.push_back( + {"not_has_field", + y_absl::StrFormat("%s_case() != k%s", oneof->name(), field_name)}); } - variables_["set_hasbit"] = StrCat( - variables_["has_bits"], "[", has_bit_index / 32, "] |= 0x", - strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); - variables_["clear_hasbit"] = StrCat( - variables_["has_bits"], "[", has_bit_index / 32, "] &= ~0x", - strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); -} -void FieldGenerator::SetInlinedStringIndex(arc_i32 inlined_string_index) { - if (!IsStringInlined(descriptor_, options_)) { - GOOGLE_CHECK_EQ(inlined_string_index, -1); - return; - } - // The first bit is the tracking bit for on demand registering ArenaDtor. - GOOGLE_CHECK_GT(inlined_string_index, 0) - << "_inlined_string_donated_'s bit 0 is reserved for arena dtor tracking"; - variables_["inlined_string_donated"] = StrCat( - "(", variables_["inlined_string_donated_array"], "[", - inlined_string_index / 32, "] & 0x", - strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8), - "u) != 0;"); - variables_["donating_states_word"] = - StrCat(variables_["inlined_string_donated_array"], "[", - inlined_string_index / 32, "]"); - variables_["mask_for_undonate"] = StrCat( - "~0x", strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8), - "u"); + return vars; } -void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const { - Formatter format(printer, variables_); +void FieldGeneratorBase::GenerateAggregateInitializer(io::Printer* p) const { + Formatter format(p, variables_); if (ShouldSplit(descriptor_, options_)) { format("decltype(Impl_::Split::$name$_){arena}"); return; @@ -309,110 +122,159 @@ void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const { format("decltype($field$){arena}"); } -void FieldGenerator::GenerateConstexprAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); +void FieldGeneratorBase::GenerateConstexprAggregateInitializer( + io::Printer* p) const { + Formatter format(p, variables_); format("/*decltype($field$)*/{}"); } -void FieldGenerator::GenerateCopyAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); +void FieldGeneratorBase::GenerateCopyAggregateInitializer( + io::Printer* p) const { + Formatter format(p, variables_); format("decltype($field$){from.$field$}"); } -void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const { +void FieldGeneratorBase::GenerateCopyConstructorCode(io::Printer* p) const { if (ShouldSplit(descriptor_, options_)) { // There is no copy constructor for the `Split` struct, so we need to copy // the value here. - Formatter format(printer, variables_); + Formatter format(p, variables_); format("$field$ = from.$field$;\n"); } } -void SetCommonOneofFieldVariables( - const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables) { - const TProtoStringType prefix = descriptor->containing_oneof()->name() + "_."; - (*variables)["oneof_name"] = descriptor->containing_oneof()->name(); -} - -FieldGenerator::~FieldGenerator() {} +void FieldGeneratorBase::GenerateIfHasField(io::Printer* p) const { + Y_ABSL_CHECK(internal::cpp::HasHasbit(descriptor_)); -FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, - const Options& options, - MessageSCCAnalyzer* scc_analyzer) - : descriptor_(descriptor), field_generators_(descriptor->field_count()) { - // Construct all the FieldGenerators. - for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset( - MakeGenerator(descriptor->field(i), options, scc_analyzer)); - } + Formatter format(p); + format("if (($has_hasbit$) != 0) {\n"); } -FieldGenerator* FieldGeneratorMap::MakeGoogleInternalGenerator( - const FieldDescriptor* field, const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - - return nullptr; -} +namespace { +std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc) { -FieldGenerator* FieldGeneratorMap::MakeGenerator( - const FieldDescriptor* field, const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - FieldGenerator* generator = - MakeGoogleInternalGenerator(field, options, scc_analyzer); - if (generator) { - return generator; + if (field->is_map()) { + return MakeMapGenerator(field, options, scc); } - if (field->is_repeated()) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - if (field->is_map()) { - return new MapFieldGenerator(field, options, scc_analyzer); - } else { - return new RepeatedMessageFieldGenerator(field, options, - scc_analyzer); - } - case FieldDescriptor::CPPTYPE_STRING: - return new RepeatedStringFieldGenerator(field, options); - case FieldDescriptor::CPPTYPE_ENUM: - return new RepeatedEnumFieldGenerator(field, options); - default: - return new RepeatedPrimitiveFieldGenerator(field, options); - } - } else if (field->real_containing_oneof()) { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageOneofFieldGenerator(field, options, scc_analyzer); - case FieldDescriptor::CPPTYPE_STRING: - return new StringOneofFieldGenerator(field, options); - case FieldDescriptor::CPPTYPE_ENUM: - return new EnumOneofFieldGenerator(field, options); - default: - return new PrimitiveOneofFieldGenerator(field, options); - } - } else { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageFieldGenerator(field, options, scc_analyzer); + return MakeRepeatedMessageGenerator(field, options, scc); case FieldDescriptor::CPPTYPE_STRING: - return new StringFieldGenerator(field, options); + return MakeRepeatedStringGenerator(field, options, scc); case FieldDescriptor::CPPTYPE_ENUM: - return new EnumFieldGenerator(field, options); + return MakeRepeatedEnumGenerator(field, options, scc); default: - return new PrimitiveFieldGenerator(field, options); + return MakeRepeatedPrimitiveGenerator(field, options, scc); } } + + if (field->real_containing_oneof() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + return MakeOneofMessageGenerator(field, options, scc); + } + + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_MESSAGE: + return MakeSinguarMessageGenerator(field, options, scc); + case FieldDescriptor::CPPTYPE_STRING: + return MakeSinguarStringGenerator(field, options, scc); + case FieldDescriptor::CPPTYPE_ENUM: + return MakeSinguarEnumGenerator(field, options, scc); + default: + return MakeSinguarPrimitiveGenerator(field, options, scc); + } } -FieldGeneratorMap::~FieldGeneratorMap() {} +void HasBitVars(const FieldDescriptor* field, const Options& opts, + y_absl::optional<arc_ui32> idx, std::vector<Sub>& vars) { + if (!idx.has_value()) { + vars.emplace_back("set_hasbit", ""); + vars.emplace_back("clear_hasbit", ""); + return; + } + + Y_ABSL_CHECK(internal::cpp::HasHasbit(field)); + + arc_i32 index = *idx / 32; + TProtoStringType mask = y_absl::StrFormat("0x%08xu", 1u << (*idx % 32)); -const FieldGenerator& FieldGeneratorMap::get( - const FieldDescriptor* field) const { - GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); - return *field_generators_[field->index()]; + y_absl::string_view has_bits = IsMapEntryMessage(field->containing_type()) + ? "_has_bits_" + : "_impl_._has_bits_"; + + auto has = y_absl::StrFormat("%s[%d] & %s", has_bits, index, mask); + auto set = y_absl::StrFormat("%s[%d] |= %s;", has_bits, index, mask); + auto clr = y_absl::StrFormat("%s[%d] &= ~%s;", has_bits, index, mask); + + vars.emplace_back("has_hasbit", has); + vars.emplace_back(Sub("set_hasbit", set).WithSuffix(";")); + vars.emplace_back(Sub("clear_hasbit", clr).WithSuffix(";")); +} + +void InlinedStringVars(const FieldDescriptor* field, const Options& opts, + y_absl::optional<arc_ui32> idx, std::vector<Sub>& vars) { + if (!IsStringInlined(field, opts)) { + Y_ABSL_CHECK(!idx.has_value()); + return; + } + + // The first bit is the tracking bit for on demand registering ArenaDtor. + Y_ABSL_CHECK_GT(*idx, 0) + << "_inlined_string_donated_'s bit 0 is reserved for arena dtor tracking"; + + arc_i32 index = *idx / 32; + TProtoStringType mask = y_absl::StrFormat("0x%08xu", 1u << (*idx % 32)); + + y_absl::string_view array = IsMapEntryMessage(field->containing_type()) + ? "_inlined_string_donated_" + : "_impl_._inlined_string_donated_"; + + vars.emplace_back("inlined_string_donated", + y_absl::StrFormat("(%s[%d] & %s) != 0;", array, index, mask)); + vars.emplace_back("donating_states_word", + y_absl::StrFormat("%s[%d]", array, index)); + vars.emplace_back("mask_for_undonate", y_absl::StrFormat("~%s", mask)); +} +} // namespace + +FieldGenerator::FieldGenerator(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer, + y_absl::optional<arc_ui32> hasbit_index, + y_absl::optional<arc_ui32> inlined_string_index) + : impl_(MakeGenerator(field, options, scc_analyzer)), + field_vars_(FieldVars(field, options)), + tracker_vars_(MakeTrackerCalls(field, options)), + per_generator_vars_(impl_->MakeVars()) { + HasBitVars(field, options, hasbit_index, field_vars_); + InlinedStringVars(field, options, inlined_string_index, field_vars_); +} + +void FieldGeneratorTable::Build( + const Options& options, MessageSCCAnalyzer* scc, + y_absl::Span<const arc_i32> has_bit_indices, + y_absl::Span<const arc_i32> inlined_string_indices) { + // Construct all the FieldGenerators. + fields_.reserve(descriptor_->field_count()); + for (const auto* field : internal::FieldRange(descriptor_)) { + y_absl::optional<arc_ui32> has_bit_index; + if (!has_bit_indices.empty() && has_bit_indices[field->index()] >= 0) { + has_bit_index = static_cast<arc_ui32>(has_bit_indices[field->index()]); + } + + y_absl::optional<arc_ui32> inlined_string_index; + if (!inlined_string_indices.empty() && + inlined_string_indices[field->index()] >= 0) { + inlined_string_index = + static_cast<arc_ui32>(inlined_string_indices[field->index()]); + } + + fields_.push_back(FieldGenerator(field, options, scc, has_bit_index, + inlined_string_index)); + } } } // namespace cpp diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.h index 95eb96f499d..0d00011ff74 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.h @@ -36,232 +36,384 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ #include <cstdint> -#include <map> #include <memory> #include <string> +#include <tuple> +#include <vector> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/cpp/options.h> - -namespace google { -namespace protobuf { -namespace io { -class Printer; // printer.h -} -} // namespace protobuf -} // namespace google +#include "google/protobuf/descriptor.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { -// Helper function: set variables in the map that are the same for all -// field code generators. -// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size', -// 'deprecation']. -void SetCommonFieldVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables, - const Options& options); +// Customization points for each field codegen type. See FieldGenerator to +// see how each of these functions is used. +// +// TODO(b/245791219): Make every function except the dtor in this generator +// non-pure-virtual. A generator with no implementation should be able to +// automatically not contribute any code to the message it is part of, as a +// matter of clean composability. +class FieldGeneratorBase { + public: + FieldGeneratorBase(const FieldDescriptor* descriptor, const Options& options) + : descriptor_(descriptor), options_(options) {} + + FieldGeneratorBase(const FieldGeneratorBase&) = delete; + FieldGeneratorBase& operator=(const FieldGeneratorBase&) = delete; + + virtual ~FieldGeneratorBase() = 0; + + virtual std::vector<io::Printer::Sub> MakeVars() const { return {}; } + + virtual void GeneratePrivateMembers(io::Printer* p) const = 0; + + virtual void GenerateStaticMembers(io::Printer* p) const {} + + virtual void GenerateAccessorDeclarations(io::Printer* p) const = 0; + + virtual void GenerateInlineAccessorDefinitions(io::Printer* p) const = 0; + + virtual void GenerateNonInlineAccessorDefinitions(io::Printer* p) const {} + + virtual void GenerateInternalAccessorDefinitions(io::Printer* p) const {} + + virtual void GenerateInternalAccessorDeclarations(io::Printer* p) const {} + + virtual void GenerateClearingCode(io::Printer* p) const = 0; + + virtual void GenerateMessageClearingCode(io::Printer* p) const { + GenerateClearingCode(p); + } + + virtual void GenerateMergingCode(io::Printer* p) const = 0; + + virtual void GenerateCopyConstructorCode(io::Printer* p) const; + + virtual void GenerateSwappingCode(io::Printer* p) const = 0; + + virtual void GenerateConstructorCode(io::Printer* p) const = 0; + + virtual void GenerateDestructorCode(io::Printer* p) const {} + + virtual void GenerateArenaDestructorCode(io::Printer* p) const { + Y_ABSL_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone) + << descriptor_->cpp_type_name(); + } + + virtual void GenerateAggregateInitializer(io::Printer* p) const; + + virtual void GenerateConstexprAggregateInitializer(io::Printer* p) const; + + virtual void GenerateCopyAggregateInitializer(io::Printer* p) const; + + virtual void GenerateSerializeWithCachedSizesToArray( + io::Printer* p) const = 0; + + virtual void GenerateByteSize(io::Printer* p) const = 0; -void SetCommonOneofFieldVariables( - const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables); + virtual void GenerateIsInitialized(io::Printer* p) const {} + + virtual void GenerateIfHasField(io::Printer* p) const; + + virtual bool IsInlined() const { return false; } + + virtual ArenaDtorNeeds NeedsArenaDestructor() const { + return ArenaDtorNeeds::kNone; + } + + protected: + // TODO(b/245791219): Remove these members and make this a pure interface. + const FieldDescriptor* descriptor_; + const Options& options_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> variables_; +}; + +inline FieldGeneratorBase::~FieldGeneratorBase() = default; class FieldGenerator { + private: + // This function must be defined here so that the inline definitions below + // can see it, which is required because it has deduced return type. + auto PushVarsForCall(io::Printer* p) const { + // NOTE: we use a struct here because: + // * We want to ensure that order of evaluation below is well-defined, + // which {...} guarantees but (...) does not. + // * We do not require C++17 as of writing and therefore cannot use + // std::tuple with CTAD. + // * std::make_tuple uses (...), not {...}. + struct Vars { + decltype(p->WithVars(field_vars_)) cleanup1; + decltype(p->WithVars(tracker_vars_)) cleanup2; + decltype(p->WithVars(per_generator_vars_)) cleanup3; + }; + + return Vars{p->WithVars(field_vars_), p->WithVars(tracker_vars_), + p->WithVars(per_generator_vars_)}; + } + public: - explicit FieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor), options_(options) {} - virtual ~FieldGenerator(); - virtual void GenerateSerializeWithCachedSizes( - io::Printer* printer) const final{}; - // Generate lines of code declaring members fields of the message class - // needed to represent this field. These are placed inside the message - // class. - virtual void GeneratePrivateMembers(io::Printer* printer) const = 0; - - // Generate static default variable for this field. These are placed inside - // the message class. Most field types don't need this, so the default - // implementation is empty. - virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {} - - // Generate prototypes for all of the accessor functions related to this - // field. These are placed inside the class definition. - virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0; - - // Generate inline definitions of accessor functions for this field. - // These are placed inside the header after all class definitions. - virtual void GenerateInlineAccessorDefinitions( - io::Printer* printer) const = 0; - - // Generate definitions of accessors that aren't inlined. These are - // placed somewhere in the .cc file. - // Most field types don't need this, so the default implementation is empty. - virtual void GenerateNonInlineAccessorDefinitions( - io::Printer* /*printer*/) const {} - - // Generate declarations of accessors that are for internal purposes only. - // Most field types don't need this, so the default implementation is empty. - virtual void GenerateInternalAccessorDefinitions( - io::Printer* /*printer*/) const {} - - // Generate definitions of accessors that are for internal purposes only. - // Most field types don't need this, so the default implementation is empty. - virtual void GenerateInternalAccessorDeclarations( - io::Printer* /*printer*/) const {} - - // Generate lines of code (statements, not declarations) which clear the - // field. This is used to define the clear_$name$() method - virtual void GenerateClearingCode(io::Printer* printer) const = 0; - - // Generate lines of code (statements, not declarations) which clear the - // field as part of the Clear() method for the whole message. For message - // types which have field presence bits, MessageGenerator::GenerateClear - // will have already checked the presence bits. + FieldGenerator(const FieldGenerator&) = delete; + FieldGenerator& operator=(const FieldGenerator&) = delete; + FieldGenerator(FieldGenerator&&) = default; + FieldGenerator& operator=(FieldGenerator&&) = default; + + // Prints private members needed to represent this field. // - // Since most field types can re-use GenerateClearingCode, this method is - // not pure virtual. - virtual void GenerateMessageClearingCode(io::Printer* printer) const { - GenerateClearingCode(printer); + // These are placed inside the class definition. + void GeneratePrivateMembers(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GeneratePrivateMembers(p); } - // Generate lines of code (statements, not declarations) which merges the - // contents of the field from the current message to the target message, - // which is stored in the generated code variable "from". + // Prints static members needed to represent this field. + // + // These are placed inside the class definition. + void GenerateStaticMembers(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateStaticMembers(p); + } + + // Generates declarations for all of the accessor functions related to this + // field. + // + // These are placed inside the class definition. + void GenerateAccessorDeclarations(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateAccessorDeclarations(p); + } + + // Generates inline definitions of accessor functions for this field. + // + // These are placed in namespace scope in the header after all class + // definitions. + void GenerateInlineAccessorDefinitions(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateInlineAccessorDefinitions(p); + } + + // Generates definitions of accessors that aren't inlined. + // + // These are placed in namespace scope in the .cc file. + void GenerateNonInlineAccessorDefinitions(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateNonInlineAccessorDefinitions(p); + } + + // Generates declarations of accessors that are for internal purposes only. + void GenerateInternalAccessorDefinitions(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateInternalAccessorDefinitions(p); + } + + // Generates definitions of accessors that are for internal purposes only. + void GenerateInternalAccessorDeclarations(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateInternalAccessorDeclarations(p); + } + + // Generates statements which clear the field. + // + // This is used to define the clear_$name$() method. + void GenerateClearingCode(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateClearingCode(p); + } + + // Generates statements which clear the field as part of the Clear() method + // for the whole message. + // + // For message types which have field presence bits, + // MessageGenerator::GenerateClear will have already checked the presence + // bits. + void GenerateMessageClearingCode(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateMessageClearingCode(p); + } + + // Generates statements which merge the contents of the field from the current + // message to the target message, which is stored in the generated code + // variable `from`. + // // This is used to fill in the MergeFrom method for the whole message. + // // Details of this usage can be found in message.cc under the // GenerateMergeFrom method. - virtual void GenerateMergingCode(io::Printer* printer) const = 0; + void GenerateMergingCode(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateMergingCode(p); + } // Generates a copy constructor - virtual void GenerateCopyConstructorCode(io::Printer* printer) const; + // + // TODO(b/245791219): Document this properly. + void GenerateCopyConstructorCode(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateCopyConstructorCode(p); + } - // Generate lines of code (statements, not declarations) which swaps - // this field and the corresponding field of another message, which - // is stored in the generated code variable "other". This is used to - // define the Swap method. Details of usage can be found in + // Generates statements which swap this field and the corresponding field of + // another message, which is stored in the generated code variable `other`. + // + // This is used to define the Swap method. Details of usage can be found in // message.cc under the GenerateSwap method. - virtual void GenerateSwappingCode(io::Printer* printer) const = 0; - - // Generate initialization code for private members declared by - // GeneratePrivateMembers(). These go into the message class's SharedCtor() - // method, invoked by each of the generated constructors. - virtual void GenerateConstructorCode(io::Printer* printer) const = 0; + void GenerateSwappingCode(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateSwappingCode(p); + } - // Generate initialization code for private members in the cold struct. - virtual void GenerateCreateSplitMessageCode(io::Printer* printer) const {} + // Generates initialization code for private members declared by + // GeneratePrivateMembers(). + // + // These go into the message class's SharedCtor() method, invoked by each of + // the generated constructors. + void GenerateConstructorCode(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateConstructorCode(p); + } - // Generate any code that needs to go in the class's SharedDtor() method, + // Generates any code that needs to go in the class's SharedDtor() method, // invoked by the destructor. - // Most field types don't need this, so the default implementation is empty. - virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {} - - // Generate a manual destructor invocation for use when the message is on an - // arena. The code that this method generates will be executed inside a - // shared-for-the-whole-message-class method registered with - // OwnDestructor(). - virtual void GenerateArenaDestructorCode(io::Printer* printer) const { - GOOGLE_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone) - << descriptor_->cpp_type_name(); + void GenerateDestructorCode(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateDestructorCode(p); } - // Generate initialization code for private members declared by - // GeneratePrivateMembers(). These go into the SharedCtor's - // aggregate initialization of the _impl_ struct and must follow the syntax - // (e.g. `decltype($field$){$default$}`). Does not include `:` or `,` - // separators. Default values should be specified here when possible. + // Generates a manual destructor invocation for use when the message is on an + // arena. // - // Note: We use `decltype($field$)` for both explicit construction and the - // fact that it's self-documenting. Pre-C++17, copy elision isn't guaranteed + // The code that this method generates will be executed inside a + // shared-for-the-whole-message-class method registered with OwnDestructor(). + void GenerateArenaDestructorCode(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateArenaDestructorCode(p); + } + + // Generates initialization code for private members declared by + // GeneratePrivateMembers(). + // + // These go into the SharedCtor's aggregate initialization of the _impl_ + // struct and must follow the syntax `decltype($field$){$default$}`. + // Does not include `:` or `,` separators. Default values should be specified + // here when possible. + // + // NOTE: We use `decltype($field$)` for both explicit construction and the + // fact that it's self-documenting. Pre-C++17, copy elision isn't guaranteed // in aggregate initialization so a valid copy/move constructor must exist - // (even though it's not used). Because of this, we need to comment out the + // (even though it's not used). Because of this, we need to comment out the // decltype and fallback to implicit construction. - virtual void GenerateAggregateInitializer(io::Printer* printer) const; - - // Generate constinit initialization code for private members declared by - // GeneratePrivateMembers(). These go into the constexpr constructor's - // aggregate initialization of the _impl_ struct and must follow the syntax - // (e.g. `/*decltype($field$)*/{}`, see above). Does not - // include `:` or `,` separators. - virtual void GenerateConstexprAggregateInitializer( - io::Printer* printer) const; - - // Generate copy initialization code for private members declared by - // GeneratePrivateMembers(). These go into the copy constructor's - // aggregate initialization of the _impl_ struct and must follow the syntax - // (e.g. `decltype($field$){from.$field$}`, see above). Does not - // include `:` or `,` separators. - virtual void GenerateCopyAggregateInitializer(io::Printer* printer) const; - - // Generate lines to serialize this field directly to the array "target", - // which are placed within the message's SerializeWithCachedSizesToArray() - // method. This must also advance "target" past the written bytes. - virtual void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const = 0; + void GenerateAggregateInitializer(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateAggregateInitializer(p); + } + + // Generates constinit initialization code for private members declared by + // GeneratePrivateMembers(). + // + // These go into the constexpr constructor's aggregate initialization of the + // _impl_ struct and must follow the syntax `/*decltype($field$)*/{}` (see + // above). Does not include `:` or `,` separators. + void GenerateConstexprAggregateInitializer(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateConstexprAggregateInitializer(p); + } + + // Generates copy initialization code for private members declared by + // GeneratePrivateMembers(). + // + // These go into the copy constructor's aggregate initialization of the _impl_ + // struct and must follow the syntax `decltype($field$){from.$field$}` (see + // above). Does not include `:` or `,` separators. + void GenerateCopyAggregateInitializer(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateCopyAggregateInitializer(p); + } + + // Generates statements to serialize this field directly to the array + // `target`, which are placed within the message's + // SerializeWithCachedSizesToArray() method. + // + // This must also advance `target` past the written bytes. + void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateSerializeWithCachedSizesToArray(p); + } - // Generate lines to compute the serialized size of this field, which + // Generates statements to compute the serialized size of this field, which // are placed in the message's ByteSize() method. - virtual void GenerateByteSize(io::Printer* printer) const = 0; + void GenerateByteSize(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateByteSize(p); + } // Generates lines to call IsInitialized() for eligible message fields. Non // message fields won't need to override this function. - virtual void GenerateIsInitialized(io::Printer* printer) const {} - - virtual bool IsInlined() const { return false; } + void GenerateIsInitialized(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateIsInitialized(p); + } - virtual ArenaDtorNeeds NeedsArenaDestructor() const { - return ArenaDtorNeeds::kNone; + // TODO(b/245791219): Document this properly. + void GenerateIfHasField(io::Printer* p) const { + auto vars = PushVarsForCall(p); + impl_->GenerateIfHasField(p); } - void SetHasBitIndex(arc_i32 has_bit_index); - void SetInlinedStringIndex(arc_i32 inlined_string_index); + // TODO(b/245791219): Document this properly. + bool IsInlined() const { return impl_->IsInlined(); } - protected: - const FieldDescriptor* descriptor_; - const Options& options_; - std::map<TProtoStringType, TProtoStringType> variables_; + // TODO(b/245791219): Document this properly. + ArenaDtorNeeds NeedsArenaDestructor() const { + return impl_->NeedsArenaDestructor(); + } private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); + friend class FieldGeneratorTable; + FieldGenerator(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer, + y_absl::optional<arc_ui32> hasbit_index, + y_absl::optional<arc_ui32> inlined_string_index); + + std::unique_ptr<FieldGeneratorBase> impl_; + std::vector<io::Printer::Sub> field_vars_; + std::vector<io::Printer::Sub> tracker_vars_; + std::vector<io::Printer::Sub> per_generator_vars_; }; -// Convenience class which constructs FieldGenerators for a Descriptor. -class FieldGeneratorMap { +// Convenience class which constructs FieldGeneratorBases for a Descriptor. +class FieldGeneratorTable { public: - FieldGeneratorMap(const Descriptor* descriptor, const Options& options, - MessageSCCAnalyzer* scc_analyzer); - ~FieldGeneratorMap(); + explicit FieldGeneratorTable(const Descriptor* descriptor) + : descriptor_(descriptor) {} - const FieldGenerator& get(const FieldDescriptor* field) const; + FieldGeneratorTable(const FieldGeneratorTable&) = delete; + FieldGeneratorTable& operator=(const FieldGeneratorTable&) = delete; - void SetHasBitIndices(const std::vector<int>& has_bit_indices_) { - for (int i = 0; i < descriptor_->field_count(); ++i) { - field_generators_[i]->SetHasBitIndex(has_bit_indices_[i]); - } - } + void Build(const Options& options, MessageSCCAnalyzer* scc_analyzer, + y_absl::Span<const arc_i32> has_bit_indices, + y_absl::Span<const arc_i32> inlined_string_indices); - void SetInlinedStringIndices(const std::vector<int>& inlined_string_indices) { - for (int i = 0; i < descriptor_->field_count(); ++i) { - field_generators_[i]->SetInlinedStringIndex(inlined_string_indices[i]); - } + const FieldGenerator& get(const FieldDescriptor* field) const { + Y_ABSL_CHECK_EQ(field->containing_type(), descriptor_); + return fields_[field->index()]; } private: const Descriptor* descriptor_; - std::vector<std::unique_ptr<FieldGenerator>> field_generators_; - - static FieldGenerator* MakeGoogleInternalGenerator( - const FieldDescriptor* field, const Options& options, - MessageSCCAnalyzer* scc_analyzer); - static FieldGenerator* MakeGenerator(const FieldDescriptor* field, - const Options& options, - MessageSCCAnalyzer* scc_analyzer); - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); + std::vector<FieldGenerator> fields_; }; +// Returns variables common to all fields. +// +// TODO(b/245791219): Make this function .cc-private. +std::vector<io::Printer::Sub> FieldVars(const FieldDescriptor* field, + const Options& opts); } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc new file mode 100644 index 00000000000..0ee76cb710e --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc @@ -0,0 +1,471 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: [email protected] (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <memory> +#include <string> +#include <tuple> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/memory/memory.h" +#include "y_absl/strings/substitute.h" +#include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/descriptor.pb.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { +namespace { +using Sub = ::google::protobuf::io::Printer::Sub; + +std::vector<Sub> Vars(const FieldDescriptor* field, const Options& opts) { + const EnumValueDescriptor* default_value = field->default_value_enum(); + bool split = ShouldSplit(field, opts); + bool is_open = internal::cpp::HasPreservingUnknownEnumSemantics(field); + auto enum_name = QualifiedClassName(field->enum_type(), opts); + return { + {"Enum", enum_name}, + {"kDefault", Int32ToString(default_value->number())}, + Sub("assert_valid", + is_open ? "" + : y_absl::Substitute("assert($0_IsValid(value));", enum_name)) + .WithSuffix(";"), + + {"cached_size_name", MakeVarintCachedSizeName(field)}, + {"cached_size_", MakeVarintCachedSizeFieldName(field, split)}, + }; +} + +class SingularEnum : public FieldGeneratorBase { + public: + SingularEnum(const FieldDescriptor* field, const Options& opts) + : FieldGeneratorBase(field, opts), + field_(field), + opts_(&opts), + is_oneof_(field->real_containing_oneof() != nullptr) {} + ~SingularEnum() override = default; + + std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); } + + void GeneratePrivateMembers(io::Printer* p) const override { + p->Emit(R"cc( + int $name$_; + )cc"); + } + + void GenerateClearingCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$ = $kDefault$; + )cc"); + } + + void GenerateMergingCode(io::Printer* p) const override { + p->Emit(R"cc( + _this->_internal_set_$name$(from._internal_$name$()); + )cc"); + } + + void GenerateSwappingCode(io::Printer* p) const override { + if (is_oneof_) return; + + p->Emit(R"cc( + swap($field_$, other->$field_$); + )cc"); + } + + void GenerateConstructorCode(io::Printer* p) const override { + if (!is_oneof_) return; + p->Emit(R"cc( + $ns$::_$Msg$_default_instance_.$field_$ = $kDefault$; + )cc"); + } + + void GenerateCopyConstructorCode(io::Printer* p) const override { + p->Emit(R"cc( + _this->$field_$ = from.$field_$; + )cc"); + } + + void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override { + p->Emit(R"cc( + target = stream->EnsureSpace(target); + target = ::_pbi::WireFormatLite::WriteEnumToArray( + $number$, this->_internal_$name$(), target); + )cc"); + } + + void GenerateByteSize(io::Printer* p) const override { + p->Emit(R"cc( + total_size += $kTagBytes$ + + ::_pbi::WireFormatLite::EnumSize(this->_internal_$name$()); + )cc"); + } + + void GenerateConstexprAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + /*decltype($field_$)*/ $kDefault$ + )cc"); + } + + void GenerateAggregateInitializer(io::Printer* p) const override { + if (ShouldSplit(descriptor_, options_)) { + p->Emit(R"cc( + decltype(Impl_::Split::$name$_) { $kDefault$ } + )cc"); + return; + } + + p->Emit(R"cc( + decltype($field_$) { $kDefault$ } + )cc"); + } + + void GenerateCopyAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + decltype($field_$) {} + )cc"); + } + + void GenerateAccessorDeclarations(io::Printer* p) const override; + void GenerateInlineAccessorDefinitions(io::Printer* p) const override; + + private: + const FieldDescriptor* field_; + const Options* opts_; + bool is_oneof_; +}; + +void SingularEnum::GenerateAccessorDeclarations(io::Printer* p) const { + auto v = p->WithVars( + AnnotatedAccessors(field_, {"", "set_", "_internal_", "_internal_set_"})); + p->Emit(R"cc( + $DEPRECATED$ $Enum$ $name$() const; + $DEPRECATED$ void $set_name$($Enum$ value); + + private: + $Enum$ $_internal_name$() const; + void $_internal_set_name$($Enum$ value); + + public: + )cc"); +} + +void SingularEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const { + p->Emit(R"cc( + inline $Enum$ $Msg$::$name$() const { + $annotate_get$; + // @@protoc_insertion_point(field_get:$pkg.Msg.field$) + return _internal_$name$(); + } + inline void $Msg$::set_$name$($Enum$ value) { + $maybe_prepare_split_message$ _internal_set_$name$(value); + $annotate_set$; + // @@protoc_insertion_point(field_set:$pkg.Msg.field$) + } + )cc"); + + if (is_oneof_) { + p->Emit(R"cc( + inline $Enum$ $Msg$::_internal_$name$() const { + if ($has_field$) { + return static_cast<$Enum$>($field_$); + } + return static_cast<$Enum$>($kDefault$); + } + inline void $Msg$::_internal_set_$name$($Enum$ value) { + $assert_valid$; + if ($not_has_field$) { + clear_$oneof_name$(); + set_has_$name$(); + } + $field_$ = value; + } + )cc"); + } else { + p->Emit(R"cc( + inline $Enum$ $Msg$::_internal_$name$() const { + return static_cast<$Enum$>($field_$); + } + inline void $Msg$::_internal_set_$name$($Enum$ value) { + $assert_valid$; + $set_hasbit$; + $field_$ = value; + } + )cc"); + } +} + +class RepeatedEnum : public FieldGeneratorBase { + public: + RepeatedEnum(const FieldDescriptor* field, const Options& opts) + : FieldGeneratorBase(field, opts), + field_(field), + opts_(&opts), + has_cached_size_(field_->is_packed() && + HasGeneratedMethods(field_->file(), opts)) {} + ~RepeatedEnum() override = default; + + std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); } + + void GeneratePrivateMembers(io::Printer* p) const override { + p->Emit(R"cc( + $pb$::RepeatedField<int> $name$_; + )cc"); + + if (has_cached_size_) { + p->Emit(R"cc( + mutable $pbi$::CachedSize $cached_size_name$; + )cc"); + } + } + + void GenerateClearingCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.Clear(); + )cc"); + } + + void GenerateMergingCode(io::Printer* p) const override { + p->Emit(R"cc( + _this->$field_$.MergeFrom(from.$field_$); + )cc"); + } + + void GenerateSwappingCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.InternalSwap(&other->$field_$); + )cc"); + } + + void GenerateDestructorCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.~RepeatedField(); + )cc"); + } + + void GenerateConstexprAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + /*decltype($field_$)*/ {} + )cc"); + if (has_cached_size_) { + p->Emit(R"cc( + , /*decltype($cached_size_$)*/ { 0 } + )cc"); + } + } + + void GenerateAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + decltype($field_$) { arena } + )cc"); + if (has_cached_size_) { + // std::atomic has no copy constructor, which prevents explicit aggregate + // initialization pre-C++17. + p->Emit(R"cc( + , /*decltype($cached_size_$)*/ { 0 } + )cc"); + } + } + + void GenerateCopyAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + decltype($field_$) { from.$field_$ })cc"); + if (has_cached_size_) { + // std::atomic has no copy constructor. + p->Emit(R"cc( + , /*decltype($cached_size_$)*/ { 0 } + )cc"); + } + } + + void GenerateCopyConstructorCode(io::Printer* p) const override { + Y_ABSL_CHECK(!ShouldSplit(field_, *opts_)); + } + + void GenerateConstructorCode(io::Printer* p) const override {} + + void GenerateAccessorDeclarations(io::Printer* p) const override; + void GenerateInlineAccessorDefinitions(io::Printer* p) const override; + void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override; + void GenerateByteSize(io::Printer* p) const override; + + private: + const FieldDescriptor* field_; + const Options* opts_; + bool has_cached_size_; +}; + +void RepeatedEnum::GenerateAccessorDeclarations(io::Printer* p) const { + auto v = p->WithVars( + AnnotatedAccessors(field_, {"", "set_", "add_", "mutable_", "_internal_", + "_internal_add_", "_internal_mutable_"})); + + p->Emit(R"cc( + public: + $DEPRECATED$ $Enum$ $name$(int index) const; + $DEPRECATED$ void $set_name$(int index, $Enum$ value); + $DEPRECATED$ void $add_name$($Enum$ value); + $DEPRECATED$ const $pb$::RepeatedField<int>& $name$() const; + $DEPRECATED$ $pb$::RepeatedField<int>* $mutable_name$(); + + private: + $Enum$ $_internal_name$(int index) const; + void $_internal_add_name$($Enum$ value); + $pb$::RepeatedField<int>* $_internal_mutable_name$(); + + public: + )cc"); +} + +void RepeatedEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const { + p->Emit(R"cc( + inline $Enum$ $Msg$::$name$(int index) const { + $annotate_get$; + // @@protoc_insertion_point(field_get:$pkg.Msg.field$) + return _internal_$name$(index); + } + inline void $Msg$::set_$name$(int index, $Enum$ value) { + $assert_valid$; + $field_$.Set(index, value); + $annotate_set$ + // @@protoc_insertion_point(field_set:$pkg.Msg.field$) + } + inline void $Msg$::add_$name$($Enum$ value) { + _internal_add_$name$(value); + $annotate_add$ + // @@protoc_insertion_point(field_add:$pkg.Msg.field$) + } + inline const $pb$::RepeatedField<int>& $Msg$::$name$() const { + $annotate_list$; + // @@protoc_insertion_point(field_list:$pkg.Msg.field$) + return $field_$; + } + inline $pb$::RepeatedField<int>* $Msg$::mutable_$name$() { + $annotate_mutable_list$; + // @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$) + return _internal_mutable_$name$(); + } + inline $Enum$ $Msg$::_internal_$name$(int index) const { + return static_cast<$Enum$>($field_$.Get(index)); + } + inline void $Msg$::_internal_add_$name$($Enum$ value) { + $assert_valid$; + $field_$.Add(value); + } + inline $pb$::RepeatedField<int>* $Msg$::_internal_mutable_$name$() { + return &$field_$; + } + )cc"); +} + +void RepeatedEnum::GenerateSerializeWithCachedSizesToArray( + io::Printer* p) const { + if (field_->is_packed()) { + p->Emit(R"cc( + { + int byte_size = $cached_size_$.Get(); + if (byte_size > 0) { + target = stream->WriteEnumPacked($number$, $field_$, byte_size, target); + } + } + )cc"); + return; + } + p->Emit(R"cc( + for (int i = 0, n = this->_internal_$name$_size(); i < n; ++i) { + target = stream->EnsureSpace(target); + target = ::_pbi::WireFormatLite::WriteEnumToArray( + $number$, this->_internal_$name$(i), target); + } + )cc"); +} + +void RepeatedEnum::GenerateByteSize(io::Printer* p) const { + p->Emit( + { + {"add_to_size", + [&] { + if (!field_->is_packed()) { + p->Emit(R"cc( + total_size += std::size_t{$kTagBytes$} * count; + )cc"); + return; + } + + p->Emit(R"cc( + if (data_size > 0) { + total_size += $kTagBytes$; + total_size += ::_pbi::WireFormatLite::Int32Size( + static_cast<arc_i32>(data_size)); + } + $cached_size_$.Set(::_pbi::ToCachedSize(data_size)); + )cc"); + }}, + }, + R"cc( + { + std::size_t data_size = 0; + auto count = static_cast<std::size_t>(this->_internal_$name$_size()); + + for (std::size_t i = 0; i < count; ++i) { + data_size += ::_pbi::WireFormatLite::EnumSize( + this->_internal_$name$(static_cast<int>(i))); + } + total_size += data_size; + $add_to_size$; + } + )cc"); +} +} // namespace + +std::unique_ptr<FieldGeneratorBase> MakeSinguarEnumGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<SingularEnum>(desc, options); +} + +std::unique_ptr<FieldGeneratorBase> MakeRepeatedEnumGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<RepeatedEnum>(desc, options); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/generators.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/generators.h new file mode 100644 index 00000000000..c9accc56e71 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/generators.h @@ -0,0 +1,98 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_GENERATORS_GENERATORS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_GENERATORS_GENERATORS_H__ + +#include <memory> + +#include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/helpers.h" + +// The functions in this file construct FieldGeneratorBase objects for +// generating different "codegen types" of fields. The logic for selecting the +// correct choice of generator lives in compiler/cpp/field.cc; this is merely +// the API that file uses for constructing generators. +// +// Functions are of the form `Make<card><kind>Generator()`, where <card> is +// `Singular`, `Repeated`, or `Oneof`, and <kind> is the field type, plus +// `MakeMapGenerator()`, since map fields are always repeated message fields. +// +// The returned pointers are never null. + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { +std::unique_ptr<FieldGeneratorBase> MakeSinguarPrimitiveGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeRepeatedPrimitiveGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeSinguarEnumGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeRepeatedEnumGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeSinguarStringGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeRepeatedStringGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeSinguarMessageGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeRepeatedMessageGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeOneofMessageGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); + +std::unique_ptr<FieldGeneratorBase> MakeMapGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc); +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_GENERATORS_GENERATORS_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/map_field.cc index ba363f5267b..2fe5484ab4b 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/map_field.cc @@ -28,28 +28,26 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <google/protobuf/compiler/cpp/map_field.h> - -#include <google/protobuf/io/printer.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/helpers.h> +#include <memory> +#include <string> +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/wire_format.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - -bool IsProto3Field(const FieldDescriptor* field_descriptor) { - const FileDescriptor* file_descriptor = field_descriptor->file(); - return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3; -} - -void SetMessageVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables, - const Options& options) { - SetCommonFieldVariables(descriptor, variables, options); +namespace { +void SetMessageVariables( + const FieldDescriptor* descriptor, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables, + const Options& options) { (*variables)["type"] = ClassName(descriptor->message_type(), false); (*variables)["full_name"] = descriptor->full_name(); @@ -66,13 +64,13 @@ void SetMessageVariables(const FieldDescriptor* descriptor, default: (*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type()); } - (*variables)["key_wire_type"] = - "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type())); - (*variables)["val_wire_type"] = - "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type())); + (*variables)["key_wire_type"] = y_absl::StrCat( + "TYPE_", y_absl::AsciiStrToUpper(DeclaredTypeMethodName(key->type()))); + (*variables)["val_wire_type"] = y_absl::StrCat( + "TYPE_", y_absl::AsciiStrToUpper(DeclaredTypeMethodName(val->type()))); (*variables)["map_classname"] = ClassName(descriptor->message_type(), false); - (*variables)["number"] = StrCat(descriptor->number()); - (*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor)); + (*variables)["number"] = y_absl::StrCat(descriptor->number()); + (*variables)["tag"] = y_absl::StrCat(internal::WireFormat::MakeTag(descriptor)); if (HasDescriptorMethods(descriptor->file(), options)) { (*variables)["lite"] = ""; @@ -81,17 +79,46 @@ void SetMessageVariables(const FieldDescriptor* descriptor, } } +class MapFieldGenerator : public FieldGeneratorBase { + public: + MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~MapFieldGenerator() override = default; + + // implements FieldGeneratorBase --------------------------------------- + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override {} + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateArenaDestructorCode(io::Printer* printer) const override; + ArenaDtorNeeds NeedsArenaDestructor() const override; + + private: + bool has_required_fields_; +}; + MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer) - : FieldGenerator(descriptor, options), + : FieldGeneratorBase(descriptor, options), has_required_fields_( scc_analyzer->HasRequiredFields(descriptor->message_type())) { SetMessageVariables(descriptor, &variables_, options); } -MapFieldGenerator::~MapFieldGenerator() {} - void MapFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { Formatter format(printer, variables_); format( @@ -303,8 +330,6 @@ void MapFieldGenerator::GenerateAggregateInitializer( } void MapFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); if (ShouldSplit(descriptor_, options_)) { format("$cached_split_ptr$->$name$_.Destruct();\n"); @@ -331,6 +356,13 @@ ArenaDtorNeeds MapFieldGenerator::NeedsArenaDestructor() const { ? ArenaDtorNeeds::kRequired : ArenaDtorNeeds::kNone; } +} // namespace + +std::unique_ptr<FieldGeneratorBase> MakeMapGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return std::make_unique<MapFieldGenerator>(desc, options, scc); +} } // namespace cpp } // namespace compiler diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/message_field.cc index 9a91fd91720..49e86d936bf 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/message_field.cc @@ -32,52 +32,63 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/message_field.h> - -#include <google/protobuf/io/printer.h> -#include <google/protobuf/compiler/cpp/field.h> -#include <google/protobuf/compiler/cpp/helpers.h> - -#include <google/protobuf/stubs/strutil.h> +#include <memory> +#include <string> +#include <tuple> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/memory/memory.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - namespace { -TProtoStringType ReinterpretCast(const TProtoStringType& type, - const TProtoStringType& expression, +TProtoStringType ReinterpretCast(y_absl::string_view type, + y_absl::string_view expression, bool implicit_weak_field) { if (implicit_weak_field) { - return "reinterpret_cast< " + type + " >(" + expression + ")"; + return y_absl::StrCat("reinterpret_cast< ", type, " >(", expression, ")"); } else { - return expression; + return TProtoStringType(expression); } } -void SetMessageVariables(const FieldDescriptor* descriptor, - const Options& options, bool implicit_weak, - std::map<TProtoStringType, TProtoStringType>* variables) { - SetCommonFieldVariables(descriptor, variables, options); +void SetMessageVariables( + const FieldDescriptor* descriptor, const Options& options, + bool implicit_weak, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables) { + bool split = ShouldSplit(descriptor, options); + TProtoStringType field_name = FieldMemberName(descriptor, split); + (*variables)["type"] = FieldMessageTypeName(descriptor, options); - (*variables)["casted_member"] = ReinterpretCast( - (*variables)["type"] + "*", (*variables)["field"], implicit_weak); - (*variables)["casted_member_const"] = - ReinterpretCast("const " + (*variables)["type"] + "&", - "*" + (*variables)["field"], implicit_weak); + variables->insert( + {"casted_member", ReinterpretCast(y_absl::StrCat((*variables)["type"], "*"), + field_name, implicit_weak)}); + variables->insert( + {"casted_member_const", + ReinterpretCast(y_absl::StrCat("const ", (*variables)["type"], "&"), + y_absl::StrCat("*", field_name), implicit_weak)}); (*variables)["type_default_instance"] = QualifiedDefaultInstanceName(descriptor->message_type(), options); (*variables)["type_default_instance_ptr"] = ReinterpretCast( "const ::PROTOBUF_NAMESPACE_ID::MessageLite*", QualifiedDefaultInstancePtr(descriptor->message_type(), options), implicit_weak); - (*variables)["type_reference_function"] = - implicit_weak ? (" ::" + (*variables)["proto_ns"] + - "::internal::StrongReference(reinterpret_cast<const " + - (*variables)["type"] + "&>(\n" + - (*variables)["type_default_instance"] + "));\n") - : ""; + variables->insert( + {"type_reference_function", + implicit_weak + ? y_absl::StrCat(" ::", ProtobufNamespace(options), + "::internal::StrongReference(reinterpret_cast<const ", + (*variables)["type"], "&>(\n", + (*variables)["type_default_instance"], "));\n") + : ""}); // NOTE: Escaped here to unblock proto1->proto2 migration. // TODO(liujisi): Extend this to apply for other conflicting methods. (*variables)["release_name"] = @@ -85,14 +96,92 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["full_name"] = descriptor->full_name(); } -} // namespace +class MessageFieldGenerator : public FieldGeneratorBase { + public: + MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~MessageFieldGenerator() override = default; + + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const override; + void GenerateInternalAccessorDeclarations( + io::Printer* printer) const override; + void GenerateInternalAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override {} + void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; + + protected: + bool implicit_weak_field_; + bool has_required_fields_; +}; + +class MessageOneofFieldGenerator : public MessageFieldGenerator { + public: + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~MessageOneofFieldGenerator() override = default; + + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; +}; + +class RepeatedMessageFieldGenerator : public FieldGeneratorBase { + public: + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~RepeatedMessageFieldGenerator() override = default; + + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateCopyConstructorCode(io::Printer* printer) const override {} + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; + + private: + bool implicit_weak_field_; + bool has_required_fields_; +}; // =================================================================== MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer) - : FieldGenerator(descriptor, options), + : FieldGeneratorBase(descriptor, options), implicit_weak_field_( IsImplicitWeakField(descriptor, options, scc_analyzer)), has_required_fields_( @@ -100,8 +189,6 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); } -MessageFieldGenerator::~MessageFieldGenerator() {} - void MessageFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { Formatter format(printer, variables_); if (implicit_weak_field_) { @@ -114,41 +201,21 @@ void MessageFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { void MessageFieldGenerator::GenerateAccessorDeclarations( io::Printer* printer) const { Formatter format(printer, variables_); - if (IsFieldStripped(descriptor_, options_)) { - format( - "$deprecated_attr$const $type$& ${1$$name$$}$() const { " - "__builtin_trap(); }\n" - "PROTOBUF_NODISCARD $deprecated_attr$$type$* " - "${1$$release_name$$}$() { " - "__builtin_trap(); }\n" - "$deprecated_attr$$type$* ${1$mutable_$name$$}$() { " - "__builtin_trap(); }\n" - "$deprecated_attr$void ${1$set_allocated_$name$$}$" - "($type$* $name$) { __builtin_trap(); }\n" - "$deprecated_attr$void " - "${1$unsafe_arena_set_allocated_$name$$}$(\n" - " $type$* $name$) { __builtin_trap(); }\n" - "$deprecated_attr$$type$* ${1$unsafe_arena_release_$name$$}$() { " - "__builtin_trap(); }\n", - descriptor_); - return; - } format( "$deprecated_attr$const $type$& ${1$$name$$}$() const;\n" "PROTOBUF_NODISCARD $deprecated_attr$$type$* " - "${1$$release_name$$}$();\n" - "$deprecated_attr$$type$* ${1$mutable_$name$$}$();\n" + "${1$$release_name$$}$();\n", + descriptor_); + format("$deprecated_attr$$type$* ${1$mutable_$name$$}$();\n", + std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::ALIAS)); + format( "$deprecated_attr$void ${1$set_allocated_$name$$}$" - "($type$* $name$);\n", + "($type$* $name$);\n" + "private:\n" + "const $type$& ${1$_internal_$name$$}$() const;\n" + "$type$* ${1$_internal_mutable_$name$$}$();\n" + "public:\n", descriptor_); - if (!IsFieldStripped(descriptor_, options_)) { - format( - "private:\n" - "const $type$& ${1$_internal_$name$$}$() const;\n" - "$type$* ${1$_internal_mutable_$name$$}$();\n" - "public:\n", - descriptor_); - } format( "$deprecated_attr$void " "${1$unsafe_arena_set_allocated_$name$$}$(\n" @@ -191,12 +258,15 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( } else { format(" $field$ = $name$;\n"); } + if (internal::cpp::HasHasbit(descriptor_)) { + format( + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n"); + } format( - " if ($name$) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n" "$annotate_set$" " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" ":$full_name$)\n" @@ -343,14 +413,14 @@ void MessageFieldGenerator::GenerateInternalAccessorDefinitions( format( "::$proto_ns$::MessageLite*\n" "$classname$::_Internal::mutable_$name$($classname$* msg) {\n"); - if (HasHasbit(descriptor_)) { + if (internal::cpp::HasHasbit(descriptor_)) { format(" msg->$set_hasbit$\n"); } if (descriptor_->real_containing_oneof() == nullptr) { format(" if (msg->$field$ == nullptr) {\n"); } else { format( - " if (!msg->_internal_has_$name$()) {\n" + " if (msg->$not_has_field$) {\n" " msg->clear_$oneof_name$();\n" " msg->set_has_$name$();\n"); } @@ -373,10 +443,8 @@ void MessageFieldGenerator::GenerateInternalAccessorDefinitions( } void MessageFieldGenerator::GenerateClearingCode(io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); - if (!HasHasbit(descriptor_)) { + if (!internal::cpp::HasHasbit(descriptor_)) { // If we don't have has-bits, message presence is indicated only by ptr != // nullptr. Thus on clear, we need to delete the object. format( @@ -391,10 +459,8 @@ void MessageFieldGenerator::GenerateClearingCode(io::Printer* printer) const { void MessageFieldGenerator::GenerateMessageClearingCode( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); - if (!HasHasbit(descriptor_)) { + if (!internal::cpp::HasHasbit(descriptor_)) { // If we don't have has-bits, message presence is indicated only by ptr != // nullptr. Thus on clear, we need to delete the object. format( @@ -410,8 +476,6 @@ void MessageFieldGenerator::GenerateMessageClearingCode( } void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); if (implicit_weak_field_) { format( @@ -425,15 +489,11 @@ void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) const { } void MessageFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); format("swap($field$, other->$field$);\n"); } void MessageFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); if (options_.opensource_runtime) { // TODO(gerbens) Remove this when we don't need to destruct default @@ -450,21 +510,26 @@ void MessageFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { format("delete $field$;\n"); } +using internal::cpp::HasHasbit; + void MessageFieldGenerator::GenerateCopyConstructorCode( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); - format( - "if (from._internal_has_$name$()) {\n" - " _this->$field$ = new $type$(*from.$field$);\n" - "}\n"); + if (HasHasbit(descriptor_)) { + format( + "if ((from.$has_hasbit$) != 0) {\n" + " _this->$field$ = new $type$(*from.$field$);\n" + "}\n"); + } else { + format( + "if (from._internal_has_$name$()) {\n" + " _this->$field$ = new $type$(*from.$field$);\n" + "}\n"); + } } void MessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { format( @@ -481,8 +546,6 @@ void MessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( } void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); format( "total_size += $tag_size$ +\n" @@ -491,15 +554,20 @@ void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const { } void MessageFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - if (!has_required_fields_) return; Formatter format(printer, variables_); - format( - "if (_internal_has_$name$()) {\n" - " if (!$field$->IsInitialized()) return false;\n" - "}\n"); + if (HasHasbit(descriptor_)) { + format( + "if (($has_hasbit$) != 0) {\n" + " if (!$field$->IsInitialized()) return false;\n" + "}\n"); + } else { + format( + "if (_internal_has_$name$()) {\n" + " if (!$field$->IsInitialized()) return false;\n" + "}\n"); + } } void MessageFieldGenerator::GenerateConstexprAggregateInitializer( @@ -530,11 +598,8 @@ MessageOneofFieldGenerator::MessageOneofFieldGenerator( const FieldDescriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer) : MessageFieldGenerator(descriptor, options, scc_analyzer) { - SetCommonOneofFieldVariables(descriptor, &variables_); } -MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} - void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions( io::Printer* printer) const { Formatter format(printer, variables_); @@ -577,7 +642,7 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( "$annotate_release$" " // @@protoc_insertion_point(field_release:$full_name$)\n" "$type_reference_function$" - " if (_internal_has_$name$()) {\n" + " if ($has_field$) {\n" " clear_has_$oneof_name$();\n" " $type$* temp = $casted_member$;\n" " if (GetArenaForAllocation() != nullptr) {\n" @@ -593,7 +658,7 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline const $type$& $classname$::_internal_$name$() const {\n" "$type_reference_function$" - " return _internal_has_$name$()\n" + " return $has_field$\n" " ? $casted_member_const$\n" " : reinterpret_cast< $type$&>($type_default_instance$);\n" "}\n" @@ -607,7 +672,7 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( " // @@protoc_insertion_point(field_unsafe_arena_release" ":$full_name$)\n" "$type_reference_function$" - " if (_internal_has_$name$()) {\n" + " if ($has_field$) {\n" " clear_has_$oneof_name$();\n" " $type$* temp = $casted_member$;\n" " $field$ = nullptr;\n" @@ -639,7 +704,7 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( "}\n" "inline $type$* $classname$::_internal_mutable_$name$() {\n" "$type_reference_function$" - " if (!_internal_has_$name$()) {\n" + " if ($not_has_field$) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n"); if (implicit_weak_field_) { @@ -666,8 +731,6 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( void MessageOneofFieldGenerator::GenerateClearingCode( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); format( "if (GetArenaForAllocation() == nullptr) {\n" @@ -703,7 +766,7 @@ void MessageOneofFieldGenerator::GenerateIsInitialized( Formatter format(printer, variables_); format( - "if (_internal_has_$name$()) {\n" + "if ($has_field$) {\n" " if (!$field$->IsInitialized()) return false;\n" "}\n"); } @@ -713,7 +776,7 @@ void MessageOneofFieldGenerator::GenerateIsInitialized( RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( const FieldDescriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer) - : FieldGenerator(descriptor, options), + : FieldGeneratorBase(descriptor, options), implicit_weak_field_( IsImplicitWeakField(descriptor, options, scc_analyzer)), has_required_fields_( @@ -721,8 +784,6 @@ RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); } -RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} - void RepeatedMessageFieldGenerator::GeneratePrivateMembers( io::Printer* printer) const { Formatter format(printer, variables_); @@ -736,34 +797,18 @@ void RepeatedMessageFieldGenerator::GeneratePrivateMembers( void RepeatedMessageFieldGenerator::GenerateAccessorDeclarations( io::Printer* printer) const { Formatter format(printer, variables_); - if (IsFieldStripped(descriptor_, options_)) { - format( - "$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index) { " - "__builtin_trap(); }\n" - "$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n" - " ${1$mutable_$name$$}$() { __builtin_trap(); }\n" - "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const { " - "__builtin_trap(); }\n" - "$deprecated_attr$$type$* ${1$add_$name$$}$() { " - "__builtin_trap(); }\n" - "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n" - " ${1$$name$$}$() const { __builtin_trap(); }\n", - descriptor_); - return; - } + format("$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index);\n", + std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::ALIAS)); format( - "$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index);\n" "$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n" " ${1$mutable_$name$$}$();\n", + std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::ALIAS)); + format( + "private:\n" + "const $type$& ${1$_internal_$name$$}$(int index) const;\n" + "$type$* ${1$_internal_add_$name$$}$();\n" + "public:\n", descriptor_); - if (!IsFieldStripped(descriptor_, options_)) { - format( - "private:\n" - "const $type$& ${1$_internal_$name$$}$(int index) const;\n" - "$type$* ${1$_internal_add_$name$$}$();\n" - "public:\n", - descriptor_); - } format( "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n" "$deprecated_attr$$type$* ${1$add_$name$$}$();\n" @@ -837,24 +882,18 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions( void RepeatedMessageFieldGenerator::GenerateClearingCode( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); format("$field$.Clear();\n"); } void RepeatedMessageFieldGenerator::GenerateMergingCode( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); format("_this->$field$.MergeFrom(from.$field$);\n"); } void RepeatedMessageFieldGenerator::GenerateSwappingCode( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); format("$field$.InternalSwap(&other->$field$);\n"); } @@ -866,8 +905,6 @@ void RepeatedMessageFieldGenerator::GenerateConstructorCode( void RepeatedMessageFieldGenerator::GenerateDestructorCode( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); if (implicit_weak_field_) { format("$field$.~WeakRepeatedPtrField();\n"); @@ -878,8 +915,6 @@ void RepeatedMessageFieldGenerator::GenerateDestructorCode( void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); if (implicit_weak_field_) { format( @@ -923,8 +958,6 @@ void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( void RepeatedMessageFieldGenerator::GenerateByteSize( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - Formatter format(printer, variables_); format( "total_size += $tag_size$UL * this->_internal_$name$_size();\n" @@ -936,8 +969,6 @@ void RepeatedMessageFieldGenerator::GenerateByteSize( void RepeatedMessageFieldGenerator::GenerateIsInitialized( io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - if (!has_required_fields_) return; Formatter format(printer, variables_); @@ -951,6 +982,25 @@ void RepeatedMessageFieldGenerator::GenerateIsInitialized( " return false;\n"); } } +} // namespace + +std::unique_ptr<FieldGeneratorBase> MakeSinguarMessageGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<MessageFieldGenerator>(desc, options, scc); +} + +std::unique_ptr<FieldGeneratorBase> MakeRepeatedMessageGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<RepeatedMessageFieldGenerator>(desc, options, scc); +} + +std::unique_ptr<FieldGeneratorBase> MakeOneofMessageGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<MessageOneofFieldGenerator>(desc, options, scc); +} } // namespace cpp } // namespace compiler diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc new file mode 100644 index 00000000000..9b5659fc023 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc @@ -0,0 +1,582 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: [email protected] (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <memory> +#include <string> +#include <tuple> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_log.h" +#include "y_absl/memory/memory.h" +#include "y_absl/types/optional.h" +#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/wire_format.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { +namespace { +using ::google::protobuf::internal::WireFormat; +using ::google::protobuf::internal::WireFormatLite; +using Sub = ::google::protobuf::io::Printer::Sub; +using Annotation = ::google::protobuf::GeneratedCodeInfo::Annotation; + +// For encodings with fixed sizes, returns that size in bytes. +y_absl::optional<size_t> FixedSize(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + return y_absl::nullopt; + + case FieldDescriptor::TYPE_FIXED32: + return WireFormatLite::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64: + return WireFormatLite::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: + return WireFormatLite::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: + return WireFormatLite::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT: + return WireFormatLite::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE: + return WireFormatLite::kDoubleSize; + case FieldDescriptor::TYPE_BOOL: + return WireFormatLite::kBoolSize; + + // No default because we want the compiler to complain if any new + // types are added. + } + + Y_ABSL_LOG(FATAL) << "Can't get here."; + return y_absl::nullopt; +} + +std::vector<Sub> Vars(const FieldDescriptor* field, const Options& options) { + bool cold = ShouldSplit(field, options); + return { + {"Type", PrimitiveTypeName(options, field->cpp_type())}, + {"kDefault", DefaultValue(options, field)}, + {"_field_cached_byte_size_", MakeVarintCachedSizeFieldName(field, cold)}, + }; +} + +class SingularPrimitive final : public FieldGeneratorBase { + public: + SingularPrimitive(const FieldDescriptor* field, const Options& opts) + : FieldGeneratorBase(field, opts), + field_(field), + opts_(&opts), + is_oneof_(field_->real_containing_oneof() != nullptr) {} + ~SingularPrimitive() override = default; + + std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); } + + void GeneratePrivateMembers(io::Printer* p) const override { + p->Emit(R"cc( + $Type$ $name$_; + )cc"); + } + + void GenerateClearingCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$ = $kDefault$; + )cc"); + } + + void GenerateMergingCode(io::Printer* p) const override { + p->Emit(R"cc( + _this->_internal_set_$name$(from._internal_$name$()); + )cc"); + } + + void GenerateSwappingCode(io::Printer* p) const override { + if (is_oneof_) { + // Don't print any swapping code. Swapping the union will swap this field. + return; + } + + p->Emit(R"cc( + //~ A `using std::swap;` is already present in this function. + swap($field_$, other->$field_$); + )cc"); + } + + void GenerateConstructorCode(io::Printer* p) const override { + if (!is_oneof_) { + return; + } + + p->Emit(R"cc( + $pkg$::_$Msg$_default_instance_.$field_$ = $kDefault$; + )cc"); + } + + void GenerateCopyConstructorCode(io::Printer* p) const override { + p->Emit(R"cc( + _this->$field_$ = from.$field_$; + )cc"); + } + + void GenerateConstexprAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + /*decltype($field_$)*/ $kDefault$ + )cc"); + } + + void GenerateAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + decltype($field_$) { $kDefault$ } + )cc"); + } + + void GenerateCopyAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + decltype($field_$) {} + )cc"); + } + + void GenerateAccessorDeclarations(io::Printer* p) const override; + void GenerateInlineAccessorDefinitions(io::Printer* p) const override; + void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override; + void GenerateByteSize(io::Printer* p) const override; + + private: + const FieldDescriptor* field_; + const Options* opts_; + bool is_oneof_; +}; + +void SingularPrimitive::GenerateAccessorDeclarations(io::Printer* p) const { + p->Emit( + { + Sub("name", p->LookupVar("name")).AnnotatedAs(field_), + Sub("set_name", y_absl::StrCat("set_", p->LookupVar("name"))) + .AnnotatedAs(field_), + Sub("_internal_name", + y_absl::StrCat("_internal_", p->LookupVar("name"))) + .AnnotatedAs(field_), + Sub("_internal_set_name", + y_absl::StrCat("_internal_set_", p->LookupVar("name"))) + .AnnotatedAs(field_), + }, + R"cc( + $DEPRECATED$ $Type$ $name$() const; + $DEPRECATED$ void $set_name$($Type$ value); + + private: + $Type$ $_internal_name$() const; + void $_internal_set_name$($Type$ value); + + public: + )cc"); +} + +void SingularPrimitive::GenerateInlineAccessorDefinitions( + io::Printer* p) const { + p->Emit(R"cc( + inline $Type$ $Msg$::$name$() const { + $annotate_get$; + // @@protoc_insertion_point(field_get:$pkg.Msg.field$) + return _internal_$name$(); + } + inline void $Msg$::set_$name$($Type$ value) { + $PrepareSplitMessageForWrite$; + _internal_set_$name$(value); + $annotate_set$; + // @@protoc_insertion_point(field_set:$pkg.Msg.field$) + } + )cc"); + + if (is_oneof_) { + p->Emit(R"cc( + inline $Type$ $Msg$::_internal_$name$() const { + if ($has_field$) { + return $field_$; + } + return $kDefault$; + } + inline void $Msg$::_internal_set_$name$($Type$ value) { + if ($not_has_field$) { + clear_$oneof_name$(); + set_has_$name$(); + } + $field_$ = value; + } + )cc"); + } else { + p->Emit(R"cc( + inline $Type$ $Msg$::_internal_$name$() const { + return $field_$; + } + inline void $Msg$::_internal_set_$name$($Type$ value) { + $set_hasbit$; + $field_$ = value; + } + )cc"); + } +} + +void SingularPrimitive::GenerateSerializeWithCachedSizesToArray( + io::Printer* p) const { + p->Emit(R"cc( + target = stream->EnsureSpace(target); + target = ::_pbi::WireFormatLite::Write$DeclaredType$ToArray( + $number$, this->_internal_$name$(), target); + )cc"); +} + +void SingularPrimitive::GenerateByteSize(io::Printer* p) const { + size_t tag_size = WireFormat::TagSize(field_->number(), field_->type()); + + auto fixed_size = FixedSize(field_->type()); + if (fixed_size.has_value()) { + p->Emit({{"kFixedBytes", tag_size + *fixed_size}}, R"cc( + total_size += $kFixedBytes$; + )cc"); + return; + } + + // Adding one is very common and it turns out it can be done for + // free inside of WireFormatLite, so we can save an instruction here. + if (tag_size == 1) { + p->Emit(R"cc( + total_size += ::_pbi::WireFormatLite::$DeclaredType$SizePlusOne( + this->_internal_$name$()); + )cc"); + return; + } + + p->Emit(R"cc( + total_size += $kTagBytes$ + ::_pbi::WireFormatLite::$DeclaredType$Size( + this->_internal_$name$()); + )cc"); +} + +class RepeatedPrimitive final : public FieldGeneratorBase { + public: + RepeatedPrimitive(const FieldDescriptor* field, const Options& opts) + : FieldGeneratorBase(field, opts), field_(field), opts_(&opts) {} + ~RepeatedPrimitive() override = default; + + std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); } + + void GenerateClearingCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.Clear(); + )cc"); + } + + void GenerateMergingCode(io::Printer* p) const override { + p->Emit(R"cc( + _this->$field_$.MergeFrom(from.$field_$); + )cc"); + } + + void GenerateSwappingCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.InternalSwap(&other->$field_$); + )cc"); + } + + void GenerateDestructorCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.~RepeatedField(); + )cc"); + } + + void GenerateConstructorCode(io::Printer* p) const override {} + + void GenerateCopyConstructorCode(io::Printer* p) const override { + Y_ABSL_CHECK(!ShouldSplit(field_, *opts_)); + } + + void GenerateConstexprAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + /*decltype($field_$)*/ {} + )cc"); + InitCachedSize(p); + } + + void GenerateAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + decltype($field_$) { arena } + )cc"); + InitCachedSize(p); + } + + void GenerateCopyAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + decltype($field_$) { from.$field_$ } + )cc"); + InitCachedSize(p); + } + + void GeneratePrivateMembers(io::Printer* p) const override; + void GenerateAccessorDeclarations(io::Printer* p) const override; + void GenerateInlineAccessorDefinitions(io::Printer* p) const override; + void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override; + void GenerateByteSize(io::Printer* p) const override; + + private: + bool HasCachedSize() const { + bool is_packed_varint = + field_->is_packed() && !FixedSize(field_->type()).has_value(); + return is_packed_varint && HasGeneratedMethods(field_->file(), *opts_); + } + + void InitCachedSize(io::Printer* p) const { + if (!HasCachedSize()) return; + // std::atomic has no move constructor, which prevents explicit aggregate + // initialization pre-C++17. + p->Emit(R"( + ,/* $_field_cached_byte_size_$ = */ { 0 } + )"); + } + + const FieldDescriptor* field_; + const Options* opts_; +}; + +void RepeatedPrimitive::GeneratePrivateMembers(io::Printer* p) const { + p->Emit(R"cc( + $pb$::RepeatedField<$Type$> $name$_; + )cc"); + + if (HasCachedSize()) { + p->Emit({{"_cached_size_", MakeVarintCachedSizeName(field_)}}, + R"cc( + mutable $pbi$::CachedSize $_cached_size_$; + )cc"); + } +} + +void RepeatedPrimitive::GenerateAccessorDeclarations(io::Printer* p) const { + p->Emit( + { + Sub("name", p->LookupVar("name")).AnnotatedAs(field_), + Sub("set_name", y_absl::StrCat("set_", p->LookupVar("name"))) + .AnnotatedAs(field_), + Sub("add_name", y_absl::StrCat("add_", p->LookupVar("name"))) + .AnnotatedAs(field_), + Sub("mutable_name", y_absl::StrCat("mutable_", p->LookupVar("name"))) + .AnnotatedAs(field_), + + Sub("_internal_name", + y_absl::StrCat("_internal_", p->LookupVar("name"))) + .AnnotatedAs(field_), + Sub("_internal_add_name", + y_absl::StrCat("_internal_add_", p->LookupVar("name"))) + .AnnotatedAs(field_), + Sub("_internal_mutable_name", + y_absl::StrCat("_internal_mutable_", p->LookupVar("name"))) + .AnnotatedAs(field_), + }, + R"cc( + $DEPRECATED$ $Type$ $name$(int index) const; + $DEPRECATED$ void $set_name$(int index, $Type$ value); + $DEPRECATED$ void $add_name$($Type$ value); + $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const; + $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$(); + + private: + $Type$ $_internal_name$(int index) const; + void $_internal_add_name$($Type$ value); + const $pb$::RepeatedField<$Type$>& $_internal_name$() const; + $pb$::RepeatedField<$Type$>* $_internal_mutable_name$(); + + public: + )cc"); +} + +void RepeatedPrimitive::GenerateInlineAccessorDefinitions( + io::Printer* p) const { + p->Emit(R"cc( + inline $Type$ $Msg$::$name$(int index) const { + $annotate_get$; + // @@protoc_insertion_point(field_get:$pkg.Msg.field$) + return _internal_$name$(index); + } + inline void $Msg$::set_$name$(int index, $Type$ value) { + $annotate_set$; + $field_$.Set(index, value); + // @@protoc_insertion_point(field_set:$pkg.Msg.field$) + } + inline void $Msg$::add_$name$($Type$ value) { + _internal_add_$name$(value); + $annotate_add$; + // @@protoc_insertion_point(field_add:$pkg.Msg.field$) + } + inline const $pb$::RepeatedField<$Type$>& $Msg$::$name$() const { + $annotate_list$; + // @@protoc_insertion_point(field_list:$pkg.Msg.field$) + return _internal_$name$(); + } + inline $pb$::RepeatedField<$Type$>* $Msg$::mutable_$name$() { + $annotate_mutable_list$; + // @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$) + return _internal_mutable_$name$(); + } + + inline $Type$ $Msg$::_internal_$name$(int index) const { + return $field_$.Get(index); + } + inline void $Msg$::_internal_add_$name$($Type$ value) { $field_$.Add(value); } + inline const $pb$::RepeatedField<$Type$>& $Msg$::_internal_$name$() const { + return $field_$; + } + inline $pb$::RepeatedField<$Type$>* $Msg$::_internal_mutable_$name$() { + return &$field_$; + } + )cc"); +} + +void RepeatedPrimitive::GenerateSerializeWithCachedSizesToArray( + io::Printer* p) const { + if (!field_->is_packed()) { + p->Emit(R"cc( + for (int i = 0, n = this->_internal_$name$_size(); i < n; ++i) { + target = stream->EnsureSpace(target); + target = ::_pbi::WireFormatLite::Write$DeclaredType$ToArray( + $number$, this->_internal_$name$(i), target); + } + )cc"); + return; + } + + if (FixedSize(field_->type()).has_value()) { + p->Emit(R"cc( + if (this->_internal_$name$_size() > 0) { + target = stream->WriteFixedPacked($number$, _internal_$name$(), target); + } + )cc"); + return; + } + + p->Emit(R"cc( + { + int byte_size = $_field_cached_byte_size_$.Get(); + if (byte_size > 0) { + target = stream->Write$DeclaredType$Packed($number$, _internal_$name$(), + byte_size, target); + } + } + )cc"); +} + +void RepeatedPrimitive::GenerateByteSize(io::Printer* p) const { + p->Emit( + { + Sub{"data_size", + [&] { + auto fixed_size = FixedSize(descriptor_->type()); + if (fixed_size.has_value()) { + p->Emit({{"kFixed", *fixed_size}}, R"cc( + std::size_t{$kFixed$} * + ::_pbi::FromIntSize(this->_internal_$name$_size()) + )cc"); + } else { + p->Emit(R"cc( + ::_pbi::WireFormatLite::$DeclaredType$Size(this->$field_$) + )cc"); + } + }} // Here and below, we need to disable the default ;-chomping + // that closure substitutions do. + .WithSuffix(""), + {"maybe_cache_data_size", + [&] { + if (!HasCachedSize()) return; + p->Emit(R"cc( + $_field_cached_byte_size_$.Set(::_pbi::ToCachedSize(data_size)); + )cc"); + }}, + Sub{"tag_size", + [&] { + if (field_->is_packed()) { + p->Emit(R"cc( + data_size == 0 + ? 0 + : $kTagBytes$ + ::_pbi::WireFormatLite::Int32Size( + static_cast<arc_i32>(data_size)) + )cc"); + } else { + p->Emit(R"cc( + std::size_t{$kTagBytes$} * + ::_pbi::FromIntSize(this->_internal_$name$_size()); + )cc"); + } + }} + .WithSuffix(""), + }, + R"cc( + { + std::size_t data_size = $data_size$; + $maybe_cache_data_size$; + std::size_t tag_size = $tag_size$; + total_size += tag_size + data_size; + } + )cc"); +} +} // namespace + +std::unique_ptr<FieldGeneratorBase> MakeSinguarPrimitiveGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<SingularPrimitive>(desc, options); +} + +std::unique_ptr<FieldGeneratorBase> MakeRepeatedPrimitiveGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<RepeatedPrimitive>(desc, options); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/string_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/string_field.cc new file mode 100644 index 00000000000..11b5b83ea66 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field_generators/string_field.cc @@ -0,0 +1,922 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: [email protected] (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <memory> +#include <string> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/memory/memory.h" +#include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { +namespace { +using ::google::protobuf::internal::cpp::HasHasbit; +using ::google::protobuf::io::AnnotationCollector; +using Sub = ::google::protobuf::io::Printer::Sub; + +std::vector<Sub> Vars(const FieldDescriptor* field, const Options& opts) { + auto trivial_default = + y_absl::StrCat("::", ProtobufNamespace(opts), + "::internal::GetEmptyStringAlreadyInited()"); + auto lazy_var = + y_absl::StrCat(QualifiedClassName(field->containing_type(), opts), + "::", MakeDefaultFieldName(field)); + + bool empty_default = field->default_value_string().empty(); + bool is_bytes = field->type() == FieldDescriptor::TYPE_BYTES; + + return { + {"kDefault", DefaultValue(opts, field)}, + {"kDefaultLen", field->default_value_string().size()}, + {"default_variable_name", MakeDefaultName(field)}, + {"default_variable_field", MakeDefaultFieldName(field)}, + + {"kDefaultStr", + !empty_default ? y_absl::StrCat(lazy_var, ".get()") : trivial_default}, + {"kDefaultValue", + !empty_default ? "nullptr" : y_absl::StrCat("&", trivial_default)}, + + {"lazy_var", lazy_var}, + Sub{"lazy_args", !empty_default ? y_absl::StrCat(lazy_var, ",") : ""} + .WithSuffix(","), + + {"byte", is_bytes ? "void" : "char"}, + {"Set", is_bytes ? "SetBytes" : "Set"}, + }; +} + +class SingularString : public FieldGeneratorBase { + public: + SingularString(const FieldDescriptor* field, const Options& opts) + : FieldGeneratorBase(field, opts), + field_(field), + opts_(&opts), + is_oneof_(field->real_containing_oneof() != nullptr), + inlined_(IsStringInlined(field, opts)) {} + ~SingularString() override = default; + + std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); } + + bool IsInlined() const override { return inlined_; } + + ArenaDtorNeeds NeedsArenaDestructor() const override { + return inlined_ ? ArenaDtorNeeds::kOnDemand : ArenaDtorNeeds::kNone; + } + + void GeneratePrivateMembers(io::Printer* p) const override { + // Skips the automatic destruction if inlined; rather calls it explicitly if + // allocating arena is null. + p->Emit({{"Str", inlined_ ? "InlinedStringField" : "ArenaStringPtr"}}, R"cc( + $pbi$::$Str$ $name$_; + )cc"); + } + + void GenerateMergingCode(io::Printer* p) const override { + p->Emit(R"cc( + _this->_internal_set_$name$(from._internal_$name$()); + )cc"); + } + + void GenerateArenaDestructorCode(io::Printer* p) const override { + if (!inlined_) return; + + p->Emit(R"cc( + if (!_this->_internal_$name$_donated()) { + _this->$field_$.~InlinedStringField(); + } + )cc"); + } + + void GenerateNonInlineAccessorDefinitions(io::Printer* p) const override { + if (EmptyDefault()) return; + p->Emit(R"cc( + /*static*/ const ::_pbi::LazyString $Msg$::$default_variable_field${ + {{$kDefault$, $kDefaultLen$}}, + {nullptr}, + }; + )cc"); + } + + void GenerateByteSize(io::Printer* p) const override { + p->Emit(R"cc( + total_size += $kTagBytes$ + $pbi$::WireFormatLite::$DeclaredType$Size( + this->_internal_$name$()); + )cc"); + } + + void GenerateCopyAggregateInitializer(io::Printer* p) const override { + p->Emit(R"cc( + decltype($field_$) {} + )cc"); + } + + void GenerateStaticMembers(io::Printer* p) const override; + void GenerateAccessorDeclarations(io::Printer* p) const override; + void GenerateInlineAccessorDefinitions(io::Printer* p) const override; + void GenerateClearingCode(io::Printer* p) const override; + void GenerateMessageClearingCode(io::Printer* p) const override; + void GenerateSwappingCode(io::Printer* p) const override; + void GenerateConstructorCode(io::Printer* p) const override; + void GenerateCopyConstructorCode(io::Printer* p) const override; + void GenerateDestructorCode(io::Printer* p) const override; + void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override; + void GenerateConstexprAggregateInitializer(io::Printer* p) const override; + void GenerateAggregateInitializer(io::Printer* p) const override; + + private: + bool EmptyDefault() const { return field_->default_value_string().empty(); } + void ReleaseImpl(io::Printer* p) const; + void SetAllocatedImpl(io::Printer* p) const; + + const FieldDescriptor* field_; + const Options* opts_; + bool is_oneof_; + bool inlined_; +}; + +void SingularString::GenerateStaticMembers(io::Printer* p) const { + if (!EmptyDefault()) { + p->Emit(R"cc( + static const $pbi$::LazyString $default_variable_name$; + )cc"); + } + if (inlined_) { + // `_init_inline_xxx` is used for initializing default instances. + p->Emit(R"cc( + static std::true_type _init_inline_$name$_; + )cc"); + } +} + +void SingularString::GenerateAccessorDeclarations(io::Printer* p) const { + // If we're using SingularString for a field with a ctype, it's + // because that ctype isn't actually implemented. In particular, this is + // true of ctype=CORD and ctype=STRING_PIECE in the open source release. + // We aren't releasing Cord because it has too many Google-specific + // dependencies and we aren't releasing StringPiece because it's hardly + // useful outside of Google and because it would get confusing to have + // multiple instances of the StringPiece class in different libraries (PCRE + // already includes it for their C++ bindings, which came from Google). + // + // In any case, we make all the accessors private while still actually + // using a string to represent the field internally. This way, we can + // guarantee that if we do ever implement the ctype, it won't break any + // existing users who might be -- for whatever reason -- already using .proto + // files that applied the ctype. The field can still be accessed via the + // reflection interface since the reflection interface is independent of + // the string's underlying representation. + bool unknown_ctype = + field_->options().ctype() != EffectiveStringCType(field_, options_); + + if (unknown_ctype) { + p->Emit(R"cc( + private: // Hidden due to unknown ctype option. + )cc"); + } + + auto vars = AnnotatedAccessors(field_, {"", "set_allocated_"}); + vars.push_back(Sub{ + "release_name", + SafeFunctionName(field_->containing_type(), field_, "release_"), + } + .AnnotatedAs(field_)); + auto v1 = p->WithVars(vars); + auto v2 = p->WithVars( + AnnotatedAccessors(field_, {"set_"}, AnnotationCollector::kSet)); + auto v3 = p->WithVars( + AnnotatedAccessors(field_, {"mutable_"}, AnnotationCollector::kAlias)); + + p->Emit( + {{"donated", + [&] { + if (!inlined_) return; + p->Emit(R"cc( + inline PROTOBUF_ALWAYS_INLINE bool _internal_$name$_donated() const; + )cc"); + }}}, + R"cc( + $DEPRECATED$ const TProtoStringType& $name$() const; + //~ Using `Arg_ = const TProtoStringType&` will make the type of `arg` + //~ default to `const TProtoStringType&`, due to reference collapse. This is + //~ necessary because there are a handful of users that rely on this + //~ default. + template <typename Arg_ = const TProtoStringType&, typename... Args_> + $DEPRECATED$ void $set_name$(Arg_&& arg, Args_... args); + $DEPRECATED$ TProtoStringType* $mutable_name$(); + PROTOBUF_NODISCARD $DEPRECATED$ TProtoStringType* $release_name$(); + $DEPRECATED$ void $set_allocated_name$(TProtoStringType* ptr); + + private: + const TProtoStringType& _internal_$name$() const; + inline PROTOBUF_ALWAYS_INLINE void _internal_set_$name$( + const TProtoStringType& value); + TProtoStringType* _internal_mutable_$name$(); + $donated$; + + public: + )cc"); +} + +void UpdateHasbitSet(io::Printer* p, bool is_oneof) { + if (!is_oneof) { + p->Emit(R"cc( + $set_hasbit$; + )cc"); + return; + } + + p->Emit(R"cc( + if ($not_has_field$) { + clear_$oneof_name$(); + + set_has_$name$(); + $field_$.InitDefault(); + } + )cc"); +} + +void ArgsForSetter(io::Printer* p, bool inlined) { + if (!inlined) { + p->Emit("GetArenaForAllocation()"); + return; + } + p->Emit( + "GetArenaForAllocation(), _internal_$name$_donated(), " + "&$donating_states_word$, $mask_for_undonate$, this"); +} + +void SingularString::ReleaseImpl(io::Printer* p) const { + if (is_oneof_) { + p->Emit(R"cc( + if ($not_has_field$) { + return nullptr; + } + clear_has_$oneof_name$(); + return $field_$.Release(); + )cc"); + return; + } + + if (!HasHasbit(field_)) { + p->Emit(R"cc( + return $field_$.Release(); + )cc"); + return; + } + + if (inlined_) { + p->Emit(R"cc( + if (($has_hasbit$) == 0) { + return nullptr; + } + $clear_hasbit$; + + return $field_$.Release(GetArenaForAllocation(), _internal_$name$_donated()); + )cc"); + return; + } + + p->Emit(R"cc( + if (($has_hasbit$) == 0) { + return nullptr; + } + $clear_hasbit$; + )cc"); + + if (!EmptyDefault()) { + p->Emit(R"cc( + return $field_$.Release(); + )cc"); + return; + } + + p->Emit(R"cc( + auto* released = $field_$.Release(); +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + $field_$.Set("", $set_args$); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + return released; + )cc"); +} + +void SingularString::SetAllocatedImpl(io::Printer* p) const { + if (is_oneof_) { + p->Emit(R"cc( + if (has_$oneof_name$()) { + clear_$oneof_name$(); + } + if (value != nullptr) { + set_has_$name$(); + $field_$.InitAllocated(value, GetArenaForAllocation()); + } + )cc"); + return; + } + + if (HasHasbit(field_)) { + p->Emit(R"cc( + if (value != nullptr) { + $set_hasbit$ + } else { + $clear_hasbit$ + } + )cc"); + } + + if (inlined_) { + // Currently, string fields with default value can't be inlined. + p->Emit(R"cc( + $field_$.SetAllocated(nullptr, value, $set_args$); + )cc"); + return; + } + + p->Emit(R"cc( + $field_$.SetAllocated(value, $set_args$); + )cc"); + + if (EmptyDefault()) { + p->Emit(R"cc( +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + if ($field_$.IsDefault()) { + $field_$.Set("", $set_args$); + } +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + )cc"); + } +} + +void SingularString::GenerateInlineAccessorDefinitions(io::Printer* p) const { + p->Emit( + { + {"if_IsDefault", + [&] { + if (EmptyDefault() || is_oneof_) return; + p->Emit(R"cc( + if ($field_$.IsDefault()) { + return $default_variable_field$.get(); + } + )cc"); + }}, + {"update_hasbit", [&] { UpdateHasbitSet(p, is_oneof_); }}, + {"set_args", [&] { ArgsForSetter(p, inlined_); }}, + {"check_hasbit", + [&] { + if (!is_oneof_) return; + p->Emit(R"cc( + if ($not_has_field$) { + return $kDefaultStr$; + } + )cc"); + }}, + {"release_name", + SafeFunctionName(field_->containing_type(), field_, "release_")}, + {"release_impl", [&] { ReleaseImpl(p); }}, + {"set_allocated_impl", [&] { SetAllocatedImpl(p); }}, + }, + R"cc( + inline const TProtoStringType& $Msg$::$name$() const { + $annotate_get$; + // @@protoc_insertion_point(field_get:$pkg.Msg.field$) + $if_IsDefault$; + return _internal_$name$(); + } + template <typename Arg_, typename... Args_> + inline PROTOBUF_ALWAYS_INLINE void $Msg$::set_$name$(Arg_&& arg, + Args_... args) { + $PrepareSplitMessageForWrite$; + $update_hasbit$; + $field_$.$Set$(static_cast<Arg_&&>(arg), args..., $set_args$); + $annotate_set$; + // @@protoc_insertion_point(field_set:$pkg.Msg.field$) + } + inline TProtoStringType* $Msg$::mutable_$name$() { + $PrepareSplitMessageForWrite$; + TProtoStringType* _s = _internal_mutable_$name$(); + $annotate_mutable$; + // @@protoc_insertion_point(field_mutable:$pkg.Msg.field$) + return _s; + } + inline const TProtoStringType& $Msg$::_internal_$name$() const { + $check_hasbit$; + return $field_$.Get(); + } + inline void $Msg$::_internal_set_$name$(const TProtoStringType& value) { + $update_hasbit$; + //~ Don't use $Set$ here; we always want the TProtoStringType variant + //~ regardless of whether this is a `bytes` field. + $field_$.Set(value, $set_args$); + } + inline TProtoStringType* $Msg$::_internal_mutable_$name$() { + $update_hasbit$; + return $field_$.Mutable($lazy_args$, $set_args$); + } + inline TProtoStringType* $Msg$::$release_name$() { + $annotate_release$; + $PrepareSplitMessageForWrite$; + // @@protoc_insertion_point(field_release:$pkg.Msg.field$) + $release_impl$; + } + inline void $Msg$::set_allocated_$name$(TProtoStringType* value) { + $PrepareSplitMessageForWrite$; + $set_allocated_impl$; + $annotate_set$; + // @@protoc_insertion_point(field_set_allocated:$pkg.Msg.field$) + } + )cc"); + + if (inlined_) { + p->Emit(R"cc( + inline bool $Msg$::_internal_$name$_donated() const { + return $inlined_string_donated$; + } + )cc"); + } +} + +void SingularString::GenerateClearingCode(io::Printer* p) const { + if (is_oneof_) { + p->Emit(R"cc( + $field_$.Destroy(); + )cc"); + return; + } + + if (EmptyDefault()) { + p->Emit(R"cc( + $field_$.ClearToEmpty(); + )cc"); + return; + } + + Y_ABSL_DCHECK(!inlined_); + p->Emit(R"cc( + $field_$.ClearToDefault($lazy_var$, GetArenaForAllocation()); + )cc"); +} + +void SingularString::GenerateMessageClearingCode(io::Printer* p) const { + if (is_oneof_) { + p->Emit(R"cc( + $field_$.Destroy(); + )cc"); + return; + } + + // Two-dimension specialization here: supporting arenas, field presence, or + // not, and default value is the empty string or not. Complexity here ensures + // the minimal number of branches / amount of extraneous code at runtime + // (given that the below methods are inlined one-liners)! + + // If we have a hasbit, then the Clear() method of the protocol buffer + // will have checked that this field is set. If so, we can avoid redundant + // checks against the default variable. + + if (inlined_ && HasHasbit(field_)) { + // Calling mutable_$name$() gives us a string reference and sets the has bit + // for $name$ (in proto2). We may get here when the string field is inlined + // but the string's contents have not been changed by the user, so we cannot + // make an assertion about the contents of the string and could never make + // an assertion about the string instance. + // + // For non-inlined strings, we distinguish from non-default by comparing + // instances, rather than contents. + p->Emit(R"cc( + $DCHK$(!$field_$.IsDefault()); + )cc"); + } + + if (!EmptyDefault()) { + // Clear to a non-empty default is more involved, as we try to use the + // Arena if one is present and may need to reallocate the string. + p->Emit(R"cc( + $field_$.ClearToDefault($lazy_var$, GetArenaForAllocation()); + )cc"); + return; + } + + p->Emit({{"Clear", + HasHasbit(field_) ? "ClearNonDefaultToEmpty" : "ClearToEmpty"}}, + R"cc( + $field_$.$Clear$(); + )cc"); +} + +void SingularString::GenerateSwappingCode(io::Printer* p) const { + if (is_oneof_) { + // Don't print any swapping code. Swapping the union will swap this field. + return; + } + + if (!inlined_) { + p->Emit(R"cc( + ::_pbi::ArenaStringPtr::InternalSwap(&$field_$, lhs_arena, + &other->$field_$, rhs_arena); + )cc"); + return; + } + + p->Emit(R"cc( + { + bool lhs_dtor_registered = ($inlined_string_donated_array$[0] & 1) == 0; + bool rhs_dtor_registered = + (other->$inlined_string_donated_array$[0] & 1) == 0; + ::_pbi::InlinedStringField::InternalSwap( + &$field_$, lhs_arena, lhs_dtor_registered, this, &other->$field_$, + rhs_arena, rhs_dtor_registered, other); + } + )cc"); +} + +void SingularString::GenerateConstructorCode(io::Printer* p) const { + if ((inlined_ && EmptyDefault()) || is_oneof_) return; + Y_ABSL_DCHECK(!inlined_); + + p->Emit(R"cc( + $field_$.InitDefault(); + )cc"); + + if (IsString(field_, *opts_) && EmptyDefault()) { + p->Emit(R"cc( +#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING + $field_$.Set("", GetArenaForAllocation()); +#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING + )cc"); + } +} + +void SingularString::GenerateCopyConstructorCode(io::Printer* p) const { + GenerateConstructorCode(p); + + if (inlined_) { + p->Emit(R"cc( + new (&_this->$field_$)::_pbi::InlinedStringField; + )cc"); + } + + p->Emit( + {{"hazzer", + [&] { + if (HasHasbit(field_)) { + p->Emit(R"cc((from.$has_hasbit$) != 0)cc"); + } else { + p->Emit(R"cc(!from._internal_$name$().empty())cc"); + } + }}, + {"set_args", + [&] { + if (!inlined_) { + p->Emit("_this->GetArenaForAllocation()"); + } else { + p->Emit( + "_this->GetArenaForAllocation(), " + "_this->_internal_$name$_donated(), " + "&_this->$donating_states_word$, $mask_for_undonate$, _this"); + } + }}}, + R"cc( + if ($hazzer$) { + _this->$field_$.Set(from._internal_$name$(), $set_args$); + } + )cc"); +} + +void SingularString::GenerateDestructorCode(io::Printer* p) const { + if (inlined_) { + // Explicitly calls ~InlinedStringField as its automatic call is disabled. + // Destructor has been implicitly skipped as a union. + Y_ABSL_DCHECK(!ShouldSplit(field_, *opts_)); + p->Emit(R"cc( + $field_$.~InlinedStringField(); + )cc"); + return; + } + + if (ShouldSplit(field_, *opts_)) { + p->Emit(R"cc( + $cached_split_ptr$->$name$_.Destroy(); + )cc"); + return; + } + + p->Emit(R"cc( + $field_$.Destroy(); + )cc"); +} + +void SingularString::GenerateSerializeWithCachedSizesToArray( + io::Printer* p) const { + p->Emit({{"utf8_check", + [&] { + GenerateUtf8CheckCodeForString(p, field_, options_, false, + "_s.data(), " + "static_cast<int>(_s.length()),"); + }}}, + R"cc( + const TProtoStringType& _s = this->_internal_$name$(); + $utf8_check$; + target = stream->Write$DeclaredType$MaybeAliased($number$, _s, target); + )cc"); +} + +void SingularString::GenerateConstexprAggregateInitializer( + io::Printer* p) const { + if (inlined_) { + p->Emit(R"cc( + /*decltype($field_$)*/ { nullptr, false } + )cc"); + return; + } + + p->Emit(R"cc( + /*decltype($field_$)*/ { + &::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized {} + } + )cc"); +} + +void SingularString::GenerateAggregateInitializer(io::Printer* p) const { + if (ShouldSplit(field_, options_)) { + Y_ABSL_CHECK(!inlined_); + p->Emit(R"cc( + decltype(Impl_::Split::$name$_) {} + )cc"); + return; + } + + if (!inlined_) { + p->Emit(R"cc( + decltype($field_$) {} + )cc"); + } else { + p->Emit(R"cc( + decltype($field_$) { arena } + )cc"); + } +} + +class RepeatedString : public FieldGeneratorBase { + public: + RepeatedString(const FieldDescriptor* field, const Options& opts) + : FieldGeneratorBase(field, opts), field_(field), opts_(&opts) {} + ~RepeatedString() override = default; + + std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); } + + void GeneratePrivateMembers(io::Printer* p) const override { + p->Emit(R"cc( + $pb$::RepeatedPtrField<TProtoStringType> $name$_; + )cc"); + } + + void GenerateClearingCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.Clear(); + )cc"); + } + + void GenerateMergingCode(io::Printer* p) const override { + p->Emit(R"cc( + _this->$field_$.MergeFrom(from.$field_$); + )cc"); + } + + void GenerateSwappingCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.InternalSwap(&other->$field_$); + )cc"); + } + + void GenerateDestructorCode(io::Printer* p) const override { + p->Emit(R"cc( + $field_$.~RepeatedPtrField(); + )cc"); + } + + void GenerateConstructorCode(io::Printer* p) const override {} + + void GenerateCopyConstructorCode(io::Printer* p) const override { + Y_ABSL_CHECK(!ShouldSplit(field_, options_)); + } + + void GenerateByteSize(io::Printer* p) const override { + p->Emit(R"cc( + total_size += $kTagBytes$ * $pbi$::FromIntSize($field_$.size()); + for (int i = 0, n = $field_$.size(); i < n; ++i) { + total_size += $pbi$::WireFormatLite::$DeclaredType$Size($field_$.Get(i)); + } + )cc"); + } + + void GenerateAccessorDeclarations(io::Printer* p) const override; + void GenerateInlineAccessorDefinitions(io::Printer* p) const override; + void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override; + + private: + const FieldDescriptor* field_; + const Options* opts_; +}; + +void RepeatedString::GenerateAccessorDeclarations(io::Printer* p) const { + bool unknown_ctype = + field_->options().ctype() != EffectiveStringCType(field_, options_); + + if (unknown_ctype) { + p->Emit(R"cc( + private: // Hidden due to unknown ctype option. + )cc"); + } + + auto v1 = p->WithVars( + AnnotatedAccessors(field_, {"", "_internal_", "_internal_add_"})); + auto v2 = p->WithVars( + AnnotatedAccessors(field_, {"set_", "add_"}, AnnotationCollector::kSet)); + auto v3 = p->WithVars( + AnnotatedAccessors(field_, {"mutable_"}, AnnotationCollector::kAlias)); + + p->Emit(R"cc( + $DEPRECATED$ const TProtoStringType& $name$(int index) const; + $DEPRECATED$ TProtoStringType* $mutable_name$(int index); + $DEPRECATED$ void $set_name$(int index, const TProtoStringType& value); + $DEPRECATED$ void $set_name$(int index, TProtoStringType&& value); + $DEPRECATED$ void $set_name$(int index, const char* value); + $DEPRECATED$ void $set_name$(int index, const $byte$* value, std::size_t size); + $DEPRECATED$ TProtoStringType* $add_name$(); + $DEPRECATED$ void $add_name$(const TProtoStringType& value); + $DEPRECATED$ void $add_name$(TProtoStringType&& value); + $DEPRECATED$ void $add_name$(const char* value); + $DEPRECATED$ void $add_name$(const $byte$* value, std::size_t size); + $DEPRECATED$ const $pb$::RepeatedPtrField<TProtoStringType>& $name$() const; + $DEPRECATED$ $pb$::RepeatedPtrField<TProtoStringType>* $mutable_name$(); + + private: + const TProtoStringType& $_internal_name$(int index) const; + TProtoStringType* $_internal_add_name$(); + + public: + )cc"); +} + +void RepeatedString::GenerateInlineAccessorDefinitions(io::Printer* p) const { + p->Emit({{"Get", opts_->safe_boundary_check ? "InternalCheckedGet" : "Get"}, + {"get_args", + [&] { + if (!opts_->safe_boundary_check) { + p->Emit("index"); + return; + } + + p->Emit(R"cc(index, $pbi$::GetEmptyStringAlreadyInited())cc"); + }}}, + R"cc( + inline TProtoStringType* $Msg$::add_$name$() { + TProtoStringType* _s = _internal_add_$name$(); + $annotate_add_mutable$; + // @@protoc_insertion_point(field_add_mutable:$pkg.Msg.field$) + return _s; + } + inline const TProtoStringType& $Msg$::_internal_$name$(int index) const { + return $field_$.$Get$($get_args$); + } + inline const TProtoStringType& $Msg$::$name$(int index) const { + $annotate_get$; + // @@protoc_insertion_point(field_get:$pkg.Msg.field$) + return _internal_$name$(index); + } + inline TProtoStringType* $Msg$::mutable_$name$(int index) { + $annotate_mutable$; + // @@protoc_insertion_point(field_mutable:$pkg.Msg.field$) + return $field_$.Mutable(index); + } + inline void $Msg$::set_$name$(int index, const TProtoStringType& value) { + $field_$.Mutable(index)->assign(value); + $annotate_set$; + // @@protoc_insertion_point(field_set:$pkg.Msg.field$) + } + inline void $Msg$::set_$name$(int index, TProtoStringType&& value) { + $field_$.Mutable(index)->assign(std::move(value)); + $annotate_set$; + // @@protoc_insertion_point(field_set:$pkg.Msg.field$) + } + inline void $Msg$::set_$name$(int index, const char* value) { + $DCHK$(value != nullptr); + $field_$.Mutable(index)->assign(value); + $annotate_set$; + // @@protoc_insertion_point(field_set_char:$pkg.Msg.field$) + } + inline void $Msg$::set_$name$(int index, const $byte$* value, + std::size_t size) { + $field_$.Mutable(index)->assign(reinterpret_cast<const char*>(value), size); + $annotate_set$; + // @@protoc_insertion_point(field_set_pointer:$pkg.Msg.field$) + } + inline TProtoStringType* $Msg$::_internal_add_$name$() { return $field_$.Add(); } + inline void $Msg$::add_$name$(const TProtoStringType& value) { + $field_$.Add()->assign(value); + $annotate_add$; + // @@protoc_insertion_point(field_add:$pkg.Msg.field$) + } + inline void $Msg$::add_$name$(TProtoStringType&& value) { + $field_$.Add(std::move(value)); + $annotate_add$; + // @@protoc_insertion_point(field_add:$pkg.Msg.field$) + } + inline void $Msg$::add_$name$(const char* value) { + $DCHK$(value != nullptr); + $field_$.Add()->assign(value); + $annotate_add$; + // @@protoc_insertion_point(field_add_char:$pkg.Msg.field$) + } + inline void $Msg$::add_$name$(const $byte$* value, std::size_t size) { + $field_$.Add()->assign(reinterpret_cast<const char*>(value), size); + $annotate_add$; + // @@protoc_insertion_point(field_add_pointer:$pkg.Msg.field$) + } + inline const ::$proto_ns$::RepeatedPtrField<TProtoStringType>& + $Msg$::$name$() const { + $annotate_list$; + // @@protoc_insertion_point(field_list:$pkg.Msg.field$) + return $field_$; + } + inline ::$proto_ns$::RepeatedPtrField<TProtoStringType>* $Msg$::mutable_$name$() { + $annotate_mutable_list$; + // @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$) + return &$field_$; + } + )cc"); +} + +void RepeatedString::GenerateSerializeWithCachedSizesToArray( + io::Printer* p) const { + p->Emit({{"utf8_check", + [&] { + GenerateUtf8CheckCodeForString( + p, field_, options_, false, + "s.data(), static_cast<int>(s.length()),"); + }}}, + R"cc( + for (int i = 0, n = this->_internal_$name$_size(); i < n; ++i) { + const auto& s = this->_internal_$name$(i); + $utf8_check$; + target = stream->Write$DeclaredType$($number$, s, target); + } + )cc"); +} +} // namespace + +std::unique_ptr<FieldGeneratorBase> MakeSinguarStringGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<SingularString>(desc, options); +} + +std::unique_ptr<FieldGeneratorBase> MakeRepeatedStringGenerator( + const FieldDescriptor* desc, const Options& options, + MessageSCCAnalyzer* scc) { + return y_absl::make_unique<RepeatedString>(desc, options); +} + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.cc index 2d79ec11e59..bb024eb59f5 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.cc @@ -32,133 +32,140 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/file.h> +#include "google/protobuf/compiler/cpp/file.h" #include <iostream> -#include <map> #include <memory> -#include <queue> -#include <set> -#include <unordered_map> -#include <unordered_set> +#include <string> +#include <utility> #include <vector> -#include <google/protobuf/compiler/scc.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/enum.h> -#include <google/protobuf/compiler/cpp/extension.h> -#include <google/protobuf/compiler/cpp/field.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/cpp/message.h> -#include <google/protobuf/compiler/cpp/service.h> -#include <google/protobuf/descriptor.pb.h> +#include "google/protobuf/compiler/scc.h" +#include "y_absl/container/btree_map.h" +#include "y_absl/container/btree_set.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/strings/escaping.h" +#include "y_absl/strings/match.h" +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/str_format.h" +#include "y_absl/strings/string_view.h" +#include "y_absl/strings/strip.h" +#include "google/protobuf/compiler/cpp/enum.h" +#include "google/protobuf/compiler/cpp/extension.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/message.h" +#include "google/protobuf/compiler/cpp/names.h" +#include "google/protobuf/compiler/cpp/service.h" +#include "google/protobuf/compiler/retention.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" // Must be last. -#include <google/protobuf/port_def.inc> +#include "google/protobuf/port_def.inc" namespace google { namespace protobuf { namespace compiler { namespace cpp { - namespace { - -// When we forward-declare things, we want to create a sorted order so our -// output is deterministic and minimizes namespace changes. -template <class T> -TProtoStringType GetSortKey(const T& val) { - return val.full_name(); -} - -template <> -TProtoStringType GetSortKey<FileDescriptor>(const FileDescriptor& val) { - return val.name(); -} - -template <class T> -bool CompareSortKeys(const T* a, const T* b) { - return GetSortKey(*a) < GetSortKey(*b); -} - -template <class T> -std::vector<const T*> Sorted(const std::unordered_set<const T*>& vals) { - std::vector<const T*> sorted(vals.begin(), vals.end()); - std::sort(sorted.begin(), sorted.end(), CompareSortKeys<T>); - return sorted; +using Sub = ::google::protobuf::io::Printer::Sub; + +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> FileVars( + const FileDescriptor* file, const Options& options) { + return { + {"filename", file->name()}, + {"package_ns", Namespace(file, options)}, + {"tablename", UniqueName("TableStruct", file, options)}, + {"desc_table", DescriptorTableName(file, options)}, + {"dllexport_decl", options.dllexport_decl}, + {"file_level_metadata", UniqueName("file_level_metadata", file, options)}, + {"file_level_enum_descriptors", + UniqueName("file_level_enum_descriptors", file, options)}, + {"file_level_service_descriptors", + UniqueName("file_level_service_descriptors", file, options)}, + }; } // TODO(b/203101078): remove pragmas that suppresses uninitialized warnings when // clang bug is fixed. -inline void MuteWuninitialized(Formatter& format) { - format( - "#if defined(__llvm__)\n" - " #pragma clang diagnostic push\n" - " #pragma clang diagnostic ignored \"-Wuninitialized\"\n" - "#endif // __llvm__\n"); +void MuteWuninitialized(io::Printer* p) { + p->Emit(R"( + #if defined(__llvm__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wuninitialized" + #endif // __llvm__ + )"); } -inline void UnmuteWuninitialized(Formatter& format) { - format( - "#if defined(__llvm__)\n" - " #pragma clang diagnostic pop\n" - "#endif // __llvm__\n"); +void UnmuteWuninitialized(io::Printer* p) { + p->Emit(R"( + #if defined(__llvm__) + #pragma clang diagnostic pop + #endif // __llvm__ + )"); } - } // namespace FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) : file_(file), options_(options), scc_analyzer_(options) { - // These variables are the same on a file level - SetCommonVars(options, &variables_); - variables_["dllexport_decl"] = options.dllexport_decl; - variables_["tablename"] = UniqueName("TableStruct", file_, options_); - variables_["file_level_metadata"] = - UniqueName("file_level_metadata", file_, options_); - variables_["desc_table"] = DescriptorTableName(file_, options_); - variables_["file_level_enum_descriptors"] = - UniqueName("file_level_enum_descriptors", file_, options_); - variables_["file_level_service_descriptors"] = - UniqueName("file_level_service_descriptors", file_, options_); - variables_["filename"] = file_->name(); - variables_["package_ns"] = Namespace(file_, options); - std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file); - for (int i = 0; i < msgs.size(); i++) { - // Deleted in destructor - MessageGenerator* msg_gen = - new MessageGenerator(msgs[i], variables_, i, options, &scc_analyzer_); - message_generators_.emplace_back(msg_gen); - msg_gen->AddGenerators(&enum_generators_, &extension_generators_); + + for (int i = 0; i < msgs.size(); ++i) { + message_generators_.push_back(std::make_unique<MessageGenerator>( + msgs[i], variables_, i, options, &scc_analyzer_)); + message_generators_.back()->AddGenerators(&enum_generators_, + &extension_generators_); } - for (int i = 0; i < file->enum_type_count(); i++) { - enum_generators_.emplace_back( - new EnumGenerator(file->enum_type(i), variables_, options)); + for (int i = 0; i < file->enum_type_count(); ++i) { + enum_generators_.push_back( + std::make_unique<EnumGenerator>(file->enum_type(i), options)); } - for (int i = 0; i < file->service_count(); i++) { - service_generators_.emplace_back( - new ServiceGenerator(file->service(i), variables_, options)); + for (int i = 0; i < file->service_count(); ++i) { + service_generators_.push_back(std::make_unique<ServiceGenerator>( + file->service(i), variables_, options)); } if (HasGenericServices(file_, options_)) { - for (int i = 0; i < service_generators_.size(); i++) { + for (int i = 0; i < service_generators_.size(); ++i) { service_generators_[i]->index_in_metadata_ = i; } } - for (int i = 0; i < file->extension_count(); i++) { - extension_generators_.emplace_back( - new ExtensionGenerator(file->extension(i), options, &scc_analyzer_)); + + for (int i = 0; i < file->extension_count(); ++i) { + extension_generators_.push_back(std::make_unique<ExtensionGenerator>( + file->extension(i), options, &scc_analyzer_)); } + for (int i = 0; i < file->weak_dependency_count(); ++i) { weak_deps_.insert(file->weak_dependency(i)); } } -FileGenerator::~FileGenerator() = default; +void FileGenerator::GenerateFile(io::Printer* p, GeneratedFileType file_type, + std::function<void()> cb) { + auto v = p->WithVars(FileVars(file_, options_)); + auto guard = IncludeGuard(file_, file_type, options_); + p->Emit({{"cb", cb}, {"guard", guard}}, R"( + // Generated by the protocol buffer compiler. DO NOT EDIT! + // source: $filename$ -void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { - Formatter format(printer, variables_); + #ifndef $guard$ + #define $guard$ + + #include <limits> + #include <string> + #include <type_traits> + + $cb$; + + #endif // $guard$ + )"); +} + +void FileGenerator::GenerateMacroUndefs(io::Printer* p) { // Only do this for protobuf's own types. There are some google3 protos using // macros as field names and the generated code compiles after the macro // expansion. Undefing these macros actually breaks such code. @@ -166,425 +173,478 @@ void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { file_->name() != "google/protobuf/compiler/plugin.proto") { return; } - std::vector<TProtoStringType> names_to_undef; + std::vector<const FieldDescriptor*> fields; ListAllFields(file_, &fields); - for (int i = 0; i < fields.size(); i++) { - const TProtoStringType& name = fields[i]->name(); - static const char* kMacroNames[] = {"major", "minor"}; - for (int j = 0; j < GOOGLE_ARRAYSIZE(kMacroNames); ++j) { - if (name == kMacroNames[j]) { - names_to_undef.push_back(name); - break; - } - } - } - for (int i = 0; i < names_to_undef.size(); ++i) { - format( - "#ifdef $1$\n" - "#undef $1$\n" - "#endif\n", - names_to_undef[i]); - } -} - -void FileGenerator::GenerateHeader(io::Printer* printer) { - Formatter format(printer, variables_); - // port_def.inc must be included after all other includes. - IncludeFile("net/proto2/public/port_def.inc", printer); - format("#define $1$$ dllexport_decl$\n", FileDllExport(file_, options_)); - GenerateMacroUndefs(printer); - - // For Any support with lite protos, we need to friend AnyMetadata, so we - // forward-declare it here. - format( - "PROTOBUF_NAMESPACE_OPEN\n" - "namespace internal {\n" - "class AnyMetadata;\n" - "} // namespace internal\n" - "PROTOBUF_NAMESPACE_CLOSE\n"); - - GenerateGlobalStateFunctionDeclarations(printer); - - GenerateForwardDeclarations(printer); - - { - NamespaceOpener ns(Namespace(file_, options_), format); - - format("\n"); - - GenerateEnumDefinitions(printer); - - format(kThickSeparator); - format("\n"); - - GenerateMessageDefinitions(printer); - - format("\n"); - format(kThickSeparator); - format("\n"); - - GenerateServiceDefinitions(printer); - - GenerateExtensionIdentifiers(printer); - - format("\n"); - format(kThickSeparator); - format("\n"); + y_absl::flat_hash_set<y_absl::string_view> all_fields; + for (const FieldDescriptor* field : fields) { + all_fields.insert(field->name()); + } - GenerateInlineFunctionDefinitions(printer); + for (y_absl::string_view name : {"major", "minor"}) { + if (!all_fields.contains(name)) { + continue; + } - format( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n" - "\n"); + p->Emit({{"name", TProtoStringType(name)}}, R"( + #)" "ifdef" R"( $name$ + #)" "undef" R"( $name$ + #)" "endif" R"( // $name$ + )"); } +} - // We need to specialize some templates in the ::google::protobuf namespace: - GenerateProto2NamespaceEnumSpecializations(printer); - format( - "\n" - "// @@protoc_insertion_point(global_scope)\n" - "\n"); - IncludeFile("net/proto2/public/port_undef.inc", printer); +void FileGenerator::GenerateSharedHeaderCode(io::Printer* p) { + p->Emit( + { + {"port_def", + [&] { IncludeFile("third_party/protobuf/port_def.inc", p); }}, + {"port_undef", + [&] { IncludeFile("third_party/protobuf/port_undef.inc", p); }}, + {"dllexport_macro", FileDllExport(file_, options_)}, + {"undefs", [&] { GenerateMacroUndefs(p); }}, + {"global_state_decls", + [&] { GenerateGlobalStateFunctionDeclarations(p); }}, + {"fwd_decls", [&] { GenerateForwardDeclarations(p); }}, + {"proto2_ns_enums", + [&] { GenerateProto2NamespaceEnumSpecializations(p); }}, + {"main_decls", + [&] { + NamespaceOpener ns(Namespace(file_, options_), p); + p->Emit( + { + {"enums", [&] { GenerateEnumDefinitions(p); }}, + {"messages", [&] { GenerateMessageDefinitions(p); }}, + {"services", [&] { GenerateServiceDefinitions(p); }}, + {"extensions", [&] { GenerateExtensionIdentifiers(p); }}, + {"inline_fns", + [&] { GenerateInlineFunctionDefinitions(p); }}, + }, + R"( + $enums$ + + $hrule_thick$ + + $messages$ + + $hrule_thick$ + + $services$ + + $extensions$ + + $hrule_thick$ + + $inline_fns$ + + // @@protoc_insertion_point(namespace_scope) + )"); + }}, + }, + R"( + // Must be included last. + $port_def$ + + #define $dllexport_macro$$ dllexport_decl$ + $undefs$ + + PROTOBUF_NAMESPACE_OPEN + namespace internal { + class AnyMetadata; + } // namespace internal + PROTOBUF_NAMESPACE_CLOSE + + $global_state_decls$; + $fwd_decls$ + + $main_decls$ + + $proto2_ns_enums$ + + // @@protoc_insertion_point(global_scope) + + $port_undef$ + )"); } -void FileGenerator::GenerateProtoHeader(io::Printer* printer, - const TProtoStringType& info_path) { - Formatter format(printer, variables_); +void FileGenerator::GenerateProtoHeader(io::Printer* p, + y_absl::string_view info_path) { if (!options_.proto_h) { return; } - GenerateTopHeaderGuard(printer, false); - - if (!options_.opensource_runtime) { - format( - "#ifdef SWIG\n" - "#error \"Do not SWIG-wrap protobufs.\"\n" - "#endif // SWIG\n" - "\n"); - } - - if (IsBootstrapProto(options_, file_)) { - format("// IWYU pragma: private, include \"$1$.proto.h\"\n\n", - StripProto(file_->name())); - } - - GenerateLibraryIncludes(printer); - - for (int i = 0; i < file_->public_dependency_count(); i++) { - const FileDescriptor* dep = file_->public_dependency(i); - format("#include \"$1$.proto.h\"\n", StripProto(dep->name())); - } - - format("// @@protoc_insertion_point(includes)\n"); - - GenerateMetadataPragma(printer, info_path); - - GenerateHeader(printer); - - GenerateBottomHeaderGuard(printer, false); -} - -void FileGenerator::GeneratePBHeader(io::Printer* printer, - const TProtoStringType& info_path) { - Formatter format(printer, variables_); - GenerateTopHeaderGuard(printer, true); - - if (options_.proto_h) { - TProtoStringType target_basename = StripProto(file_->name()); + GenerateFile(p, GeneratedFileType::kProtoH, [&] { if (!options_.opensource_runtime) { - GetBootstrapBasename(options_, target_basename, &target_basename); + p->Emit(R"( + #ifdef SWIG + #error "Do not SWIG-wrap protobufs." + #endif // SWIG + )"); } - format("#include \"$1$.proto.h\" // IWYU pragma: export\n", - target_basename); - } else { - GenerateLibraryIncludes(printer); - } - - if (options_.transitive_pb_h) { - GenerateDependencyIncludes(printer); - } - - // This is unfortunately necessary for some plugins. I don't see why we - // need two of the same insertion points. - // TODO(gerbens) remove this. - format("// @@protoc_insertion_point(includes)\n"); - - GenerateMetadataPragma(printer, info_path); - - if (!options_.proto_h) { - GenerateHeader(printer); - } else { - { - NamespaceOpener ns(Namespace(file_, options_), format); - format( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); + if (IsBootstrapProto(options_, file_)) { + p->Emit({{"name", StripProto(file_->name())}}, R"cc( + // IWYU pragma: private, include "$name$.proto.h" + )cc"); } - format( - "\n" - "// @@protoc_insertion_point(global_scope)\n" - "\n"); - } - GenerateBottomHeaderGuard(printer, true); + p->Emit( + { + {"library_includes", [&] { GenerateLibraryIncludes(p); }}, + {"proto_includes", + [&] { + for (int i = 0; i < file_->public_dependency_count(); ++i) { + const FileDescriptor* dep = file_->public_dependency(i); + p->Emit({{"name", StripProto(dep->name())}}, R"( + #include "$name$.proto.h" + )"); + } + }}, + {"metadata_pragma", [&] { GenerateMetadataPragma(p, info_path); }}, + {"header_main", [&] { GenerateSharedHeaderCode(p); }}, + }, + R"cc( + $library_includes$; + $proto_includes$; + // @@protoc_insertion_point(includes) + + $metadata_pragma$; + $header_main$; + )cc"); + }); } -void FileGenerator::GeneratePBDeps(io::Printer* printer, - const TProtoStringType& info_path) { - Formatter format(printer, variables_); - - GenerateTopHeaderGuard(printer, true, true); - - GenerateDependencyIncludes(printer); - - GenerateBottomHeaderGuard(printer, true, true); +void FileGenerator::GeneratePBHeader(io::Printer* p, + y_absl::string_view info_path) { + GenerateFile(p, GeneratedFileType::kPbH, [&] { + p->Emit( + { + {"library_includes", + [&] { + if (options_.proto_h) { + TProtoStringType target_basename = StripProto(file_->name()); + if (!options_.opensource_runtime) { + GetBootstrapBasename(options_, target_basename, + &target_basename); + } + p->Emit({{"name", target_basename}}, R"( + #include "$name$.proto.h" // IWYU pragma: export + )"); + } else { + GenerateLibraryIncludes(p); + } + }}, + {"proto_includes", + [&] { + if (options_.transitive_pb_h) { + GenerateDependencyIncludes(p); + } + }}, + {"metadata_pragma", [&] { GenerateMetadataPragma(p, info_path); }}, + {"header_main", + [&] { + if (!options_.proto_h) { + GenerateSharedHeaderCode(p); + return; + } + + { + NamespaceOpener ns(Namespace(file_, options_), p); + p->Emit(R"cc( + + // @@protoc_insertion_point(namespace_scope) + )cc"); + } + p->Emit(R"cc( + + // @@protoc_insertion_point(global_scope) + )cc"); + }}, + }, + R"cc( + $library_includes$; + $proto_includes$; + // @@protoc_insertion_point(includes) + + $metadata_pragma$; + $header_main$; + )cc"); + }); } -void FileGenerator::DoIncludeFile(const TProtoStringType& google3_name, - bool do_export, io::Printer* printer) { - Formatter format(printer, variables_); - const TProtoStringType prefix = "net/proto2/"; - GOOGLE_CHECK(google3_name.find(prefix) == 0) << google3_name; +void FileGenerator::DoIncludeFile(y_absl::string_view google3_name, + bool do_export, io::Printer* p) { + constexpr y_absl::string_view prefix = "third_party/protobuf/"; + Y_ABSL_CHECK(y_absl::StartsWith(google3_name, prefix)) << google3_name; + + auto v = p->WithVars( + {{"export_suffix", do_export ? "// IWYU pragma: export" : ""}}); if (options_.opensource_runtime) { - TProtoStringType path = google3_name.substr(prefix.size()); + y_absl::ConsumePrefix(&google3_name, prefix); + y_absl::ConsumePrefix(&google3_name, "internal/"); + y_absl::ConsumePrefix(&google3_name, "proto/"); + y_absl::ConsumePrefix(&google3_name, "public/"); + + TProtoStringType path; + if (y_absl::ConsumePrefix(&google3_name, "io/public/")) { + path = y_absl::StrCat("io/", google3_name); + } else { + path = TProtoStringType(google3_name); + } - path = StringReplace(path, "internal/", "", false); - path = StringReplace(path, "proto/", "", false); - path = StringReplace(path, "public/", "", false); if (options_.runtime_include_base.empty()) { - format("#include <google/protobuf/$1$>", path); + p->Emit({{"path", path}}, R"( + #include "google/protobuf/$path$"$ export_suffix$ + )"); } else { - format("#include \"$1$google/protobuf/$2$\"", - options_.runtime_include_base, path); + p->Emit({{"base", options_.runtime_include_base}, {"path", path}}, + R"( + #include "$base$google/protobuf/$path$"$ export_suffix$ + )"); } } else { - TProtoStringType path = google3_name; + TProtoStringType path(google3_name); // The bootstrapped proto generated code needs to use the // third_party/protobuf header paths to avoid circular dependencies. if (options_.bootstrap) { - path = StringReplace(google3_name, "net/proto2/public", - "third_party/protobuf", false); + constexpr y_absl::string_view bootstrap_prefix = "net/proto2/public"; + if (y_absl::ConsumePrefix(&google3_name, bootstrap_prefix)) { + path = y_absl::StrCat("third_party/protobuf", google3_name); + } } - format("#include \"$1$\"", path); - } - if (do_export) { - format(" // IWYU pragma: export"); + p->Emit({{"path", path}}, R"( + #include "$path$"$ export_suffix$ + )"); } - - format("\n"); } -TProtoStringType FileGenerator::CreateHeaderInclude(const TProtoStringType& basename, +TProtoStringType FileGenerator::CreateHeaderInclude(y_absl::string_view basename, const FileDescriptor* file) { - bool use_system_include = false; - TProtoStringType name = basename; - - if (options_.opensource_runtime) { - if (IsWellKnownMessage(file)) { - if (options_.runtime_include_base.empty()) { - use_system_include = true; - } else { - name = options_.runtime_include_base + basename; - } - } + if (options_.opensource_runtime && IsWellKnownMessage(file) && + !options_.runtime_include_base.empty()) { + return y_absl::StrCat("\"", options_.runtime_include_base, basename, "\""); } - TProtoStringType left = "\""; - TProtoStringType right = "\""; - if (use_system_include) { - left = "<"; - right = ">"; - } - return left + name + right; + return y_absl::StrCat("\"", basename, "\""); } -void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { - Formatter format(printer, variables_); +void FileGenerator::GenerateSourceIncludes(io::Printer* p) { TProtoStringType target_basename = StripProto(file_->name()); if (!options_.opensource_runtime) { GetBootstrapBasename(options_, target_basename, &target_basename); } - target_basename += options_.proto_h ? ".proto.h" : ".pb.h"; - format( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n" - "#include $1$\n" - "\n" - "#include <algorithm>\n" // for swap() - "\n", - CreateHeaderInclude(target_basename, file_)); - if (!options_.transitive_pb_h) { - GenerateDependencyIncludes(printer); - } + y_absl::StrAppend(&target_basename, options_.proto_h ? ".proto.h" : ".pb.h"); + p->Emit({{"h_include", CreateHeaderInclude(target_basename, file_)}}, + R"( + // Generated by the protocol buffer compiler. DO NOT EDIT! + // source: $filename$ - IncludeFile("net/proto2/io/public/coded_stream.h", printer); + #)" "include" R"( $h_include$ + + #include <algorithm> + )"); + + IncludeFile("third_party/protobuf/io/coded_stream.h", p); // TODO(gerbens) This is to include parse_context.h, we need a better way - IncludeFile("net/proto2/public/extension_set.h", printer); - IncludeFile("net/proto2/public/wire_format_lite.h", printer); + IncludeFile("third_party/protobuf/extension_set.h", p); + IncludeFile("third_party/protobuf/wire_format_lite.h", p); // Unknown fields implementation in lite mode uses StringOutputStream if (!UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { - IncludeFile("net/proto2/io/public/zero_copy_stream_impl_lite.h", printer); + IncludeFile("third_party/protobuf/io/zero_copy_stream_impl_lite.h", p); } if (HasDescriptorMethods(file_, options_)) { - IncludeFile("net/proto2/public/descriptor.h", printer); - IncludeFile("net/proto2/public/generated_message_reflection.h", printer); - IncludeFile("net/proto2/public/reflection_ops.h", printer); - IncludeFile("net/proto2/public/wire_format.h", printer); + IncludeFile("third_party/protobuf/descriptor.h", p); + IncludeFile("third_party/protobuf/generated_message_reflection.h", p); + IncludeFile("third_party/protobuf/reflection_ops.h", p); + IncludeFile("third_party/protobuf/wire_format.h", p); } if (HasGeneratedMethods(file_, options_) && options_.tctable_mode != Options::kTCTableNever) { - IncludeFile("net/proto2/public/generated_message_tctable_impl.h", printer); + IncludeFile("third_party/protobuf/generated_message_tctable_impl.h", p); } if (options_.proto_h) { // Use the smaller .proto.h files. - for (int i = 0; i < file_->dependency_count(); i++) { + for (int i = 0; i < file_->dependency_count(); ++i) { const FileDescriptor* dep = file_->dependency(i); - // Do not import weak deps. - if (!options_.opensource_runtime && IsDepWeak(dep)) continue; + + if (!options_.opensource_runtime && + IsDepWeak(dep)) { // Do not import weak deps. + continue; + } + TProtoStringType basename = StripProto(dep->name()); if (IsBootstrapProto(options_, file_)) { GetBootstrapBasename(options_, basename, &basename); } - format("#include \"$1$.proto.h\"\n", basename); + p->Emit({{"name", basename}}, R"( + #include "$name$.proto.h" + )"); } } + if (HasCordFields(file_, options_)) { - format( - "#include \"third_party/absl/strings/internal/string_constant.h\"\n"); + p->Emit(R"( + #include "y_absl/strings/internal/string_constant.h" + )"); } - format("// @@protoc_insertion_point(includes)\n"); - IncludeFile("net/proto2/public/port_def.inc", printer); -} + p->Emit(R"cc( + // @@protoc_insertion_point(includes) -void FileGenerator::GenerateSourcePrelude(io::Printer* printer) { - Formatter format(printer, variables_); + // Must be included last. + )cc"); + IncludeFile("third_party/protobuf/port_def.inc", p); +} +void FileGenerator::GenerateSourcePrelude(io::Printer* p) { // For MSVC builds, we use #pragma init_seg to move the initialization of our // libraries to happen before the user code. // This worksaround the fact that MSVC does not do constant initializers when // required by the standard. - format("\nPROTOBUF_PRAGMA_INIT_SEG\n"); - - // Generate convenience aliases. - format( - "\n" - "namespace _pb = ::$1$;\n" - "namespace _pbi = _pb::internal;\n", - ProtobufNamespace(options_)); + p->Emit(R"cc( + PROTOBUF_PRAGMA_INIT_SEG + namespace _pb = ::$proto_ns$; + namespace _pbi = ::$proto_ns$::internal; + )cc"); + if (HasGeneratedMethods(file_, options_) && options_.tctable_mode != Options::kTCTableNever) { - format("namespace _fl = _pbi::field_layout;\n"); + p->Emit(R"cc( + namespace _fl = ::$proto_ns$::internal::field_layout; + )cc"); } - format("\n"); } -void FileGenerator::GenerateSourceDefaultInstance(int idx, - io::Printer* printer) { - Formatter format(printer, variables_); +void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) { MessageGenerator* generator = message_generators_[idx].get(); + // Generate the split instance first because it's needed in the constexpr // constructor. - if (ShouldSplit(generator->descriptor_, options_)) { + if (ShouldSplit(generator->descriptor(), options_)) { // Use a union to disable the destructor of the _instance member. // We can constant initialize, but the object will still have a non-trivial // destructor that we need to elide. - format( - "struct $1$ {\n" - " PROTOBUF_CONSTEXPR $1$()\n" - " : _instance{", - DefaultInstanceType(generator->descriptor_, options_, - /*split=*/true)); - generator->GenerateInitDefaultSplitInstance(printer); - format( - "} {}\n" - " ~$1$() {}\n" - " union {\n" - " $2$ _instance;\n" - " };\n" - "};\n", - DefaultInstanceType(generator->descriptor_, options_, /*split=*/true), - StrCat(generator->classname_, "::Impl_::Split")); + // // NO_DESTROY is not necessary for correctness. The empty destructor is // enough. However, the empty destructor fails to be elided in some // configurations (like non-opt or with certain sanitizers). NO_DESTROY is // there just to improve performance and binary size in these builds. - format( - "PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT " - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n", - DefaultInstanceType(generator->descriptor_, options_, /*split=*/true), - DefaultInstanceName(generator->descriptor_, options_, /*split=*/true)); - } - - generator->GenerateConstexprConstructor(printer); - format( - "struct $1$ {\n" - " PROTOBUF_CONSTEXPR $1$()\n" - " : _instance(::_pbi::ConstantInitialized{}) {}\n" - " ~$1$() {}\n" - " union {\n" - " $2$ _instance;\n" - " };\n" - "};\n", - DefaultInstanceType(generator->descriptor_, options_), - generator->classname_); - format( - "PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT " - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n", - DefaultInstanceType(generator->descriptor_, options_), - DefaultInstanceName(generator->descriptor_, options_)); - - for (int i = 0; i < generator->descriptor_->field_count(); i++) { - const FieldDescriptor* field = generator->descriptor_->field(i); - if (IsStringInlined(field, options_)) { - // Force the initialization of the inlined string in the default instance. - format( - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 std::true_type " - "$1$::Impl_::_init_inline_$2$_ = " - "($3$._instance.$4$.Init(), std::true_type{});\n", - ClassName(generator->descriptor_), FieldName(field), - DefaultInstanceName(generator->descriptor_, options_), - FieldMemberName(field, ShouldSplit(field, options_))); + p->Emit( + { + {"type", DefaultInstanceType(generator->descriptor(), options_, + /*split=*/true)}, + {"name", DefaultInstanceName(generator->descriptor(), options_, + /*split=*/true)}, + {"default", + [&] { generator->GenerateInitDefaultSplitInstance(p); }}, + {"class", y_absl::StrCat(ClassName(generator->descriptor()), + "::Impl_::Split")}, + }, + R"cc( + struct $type$ { + PROTOBUF_CONSTEXPR $type$() : _instance{$default$} {} + union { + $class$ _instance; + }; + }; + + PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 const $type$ $name$; + )cc"); + } + + generator->GenerateConstexprConstructor(p); + + p->Emit( + { + {"type", DefaultInstanceType(generator->descriptor(), options_)}, + {"name", DefaultInstanceName(generator->descriptor(), options_)}, + {"default", [&] { generator->GenerateInitDefaultSplitInstance(p); }}, + {"class", ClassName(generator->descriptor())}, + }, + R"cc( + struct $type$ { + PROTOBUF_CONSTEXPR $type$() : _instance(::_pbi::ConstantInitialized{}) {} + ~$type$() {} + union { + $class$ _instance; + }; + }; + + PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $type$ $name$; + )cc"); + + for (int i = 0; i < generator->descriptor()->field_count(); ++i) { + const FieldDescriptor* field = generator->descriptor()->field(i); + if (!IsStringInlined(field, options_)) { + continue; } + + // Force the initialization of the inlined string in the default instance. + p->Emit( + { + {"class", ClassName(generator->descriptor())}, + {"field", FieldName(field)}, + {"default", DefaultInstanceName(generator->descriptor(), options_)}, + {"member", FieldMemberName(field, ShouldSplit(field, options_))}, + }, + R"cc( + PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 std::true_type + $class$::Impl_::_init_inline_$field$_ = + ($default$._instance.$member$.Init(), std::true_type{}); + )cc"); } if (options_.lite_implicit_weak_fields) { - format( - "PROTOBUF_CONSTINIT const void* $1$ =\n" - " &$2$;\n", - DefaultInstancePtr(generator->descriptor_, options_), - DefaultInstanceName(generator->descriptor_, options_)); + p->Emit( + { + {"ptr", DefaultInstancePtr(generator->descriptor(), options_)}, + {"name", DefaultInstanceName(generator->descriptor(), options_)}, + }, + R"cc( + PROTOBUF_CONSTINIT const void* $ptr$ = &$name$; + )cc"); } } // A list of things defined in one .pb.cc file that we need to reference from // another .pb.cc file. struct FileGenerator::CrossFileReferences { + // When we forward-declare things, we want to create a sorted order so our + // output is deterministic and minimizes namespace changes. + struct DescCompare { + template <typename T> + bool operator()(const T* const& a, const T* const& b) const { + return a->full_name() < b->full_name(); + } + + bool operator()(const FileDescriptor* const& a, + const FileDescriptor* const& b) const { + return a->name() < b->name(); + } + }; + // Populated if we are referencing from messages or files. - std::unordered_set<const Descriptor*> weak_default_instances; + y_absl::btree_set<const Descriptor*, DescCompare> weak_default_instances; // Only if we are referencing from files. - std::unordered_set<const FileDescriptor*> strong_reflection_files; - std::unordered_set<const FileDescriptor*> weak_reflection_files; + y_absl::btree_set<const FileDescriptor*, DescCompare> strong_reflection_files; + y_absl::btree_set<const FileDescriptor*, DescCompare> weak_reflection_files; }; void FileGenerator::GetCrossFileReferencesForField(const FieldDescriptor* field, CrossFileReferences* refs) { const Descriptor* msg = field->message_type(); - if (msg == nullptr) return; + if (msg == nullptr) { + return; + } if (IsImplicitWeakField(field, options_, &scc_analyzer_) || IsWeak(field, options_)) { @@ -598,10 +658,13 @@ void FileGenerator::GetCrossFileReferencesForFile(const FileDescriptor* file, GetCrossFileReferencesForField(field, refs); }); - if (!HasDescriptorMethods(file, options_)) return; + if (!HasDescriptorMethods(file, options_)) { + return; + } - for (int i = 0; i < file->dependency_count(); i++) { + for (int i = 0; i < file->dependency_count(); ++i) { const FileDescriptor* dep = file->dependency(i); + if (IsDepWeak(dep)) { refs->weak_reflection_files.insert(dep); } else { @@ -612,119 +675,128 @@ void FileGenerator::GetCrossFileReferencesForFile(const FileDescriptor* file, // Generates references to variables defined in other files. void FileGenerator::GenerateInternalForwardDeclarations( - const CrossFileReferences& refs, io::Printer* printer) { - Formatter format(printer, variables_); - + const CrossFileReferences& refs, io::Printer* p) { { - NamespaceOpener ns(format); - for (auto instance : Sorted(refs.weak_default_instances)) { + NamespaceOpener ns(p); + for (auto instance : refs.weak_default_instances) { ns.ChangeTo(Namespace(instance, options_)); + if (options_.lite_implicit_weak_fields) { - format( - "PROTOBUF_CONSTINIT __attribute__((weak)) const void* $1$ =\n" - " &::_pbi::implicit_weak_message_default_instance;\n", - DefaultInstancePtr(instance, options_)); + p->Emit({{"ptr", DefaultInstancePtr(instance, options_)}}, R"cc( + PROTOBUF_CONSTINIT __attribute__((weak)) const void* $ptr$ = + &::_pbi::implicit_weak_message_default_instance; + )cc"); } else { - format("extern __attribute__((weak)) $1$ $2$;\n", - DefaultInstanceType(instance, options_), - DefaultInstanceName(instance, options_)); + p->Emit({{"type", DefaultInstanceType(instance, options_)}, + {"name", DefaultInstanceName(instance, options_)}}, + R"cc( + extern __attribute__((weak)) $type$ $name$; + )cc"); } } } - for (auto file : Sorted(refs.weak_reflection_files)) { - format( - "extern __attribute__((weak)) const ::_pbi::DescriptorTable $1$;\n", - DescriptorTableName(file, options_)); + for (auto file : refs.weak_reflection_files) { + p->Emit({{"table", DescriptorTableName(file, options_)}}, R"cc( + extern __attribute__((weak)) const ::_pbi::DescriptorTable $table$; + )cc"); } } -void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { - Formatter format(printer, variables_); - GenerateSourceIncludes(printer); - GenerateSourcePrelude(printer); +void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* p) { + auto v = p->WithVars(FileVars(file_, options_)); - if (IsAnyMessage(file_, options_)) MuteWuninitialized(format); + GenerateSourceIncludes(p); + GenerateSourcePrelude(p); + + if (IsAnyMessage(file_, options_)) { + MuteWuninitialized(p); + } CrossFileReferences refs; - ForEachField(message_generators_[idx]->descriptor_, + ForEachField(message_generators_[idx]->descriptor(), [this, &refs](const FieldDescriptor* field) { GetCrossFileReferencesForField(field, &refs); }); - GenerateInternalForwardDeclarations(refs, printer); - { // package namespace - NamespaceOpener ns(Namespace(file_, options_), format); + GenerateInternalForwardDeclarations(refs, p); - // Define default instances - GenerateSourceDefaultInstance(idx, printer); + { + NamespaceOpener ns(Namespace(file_, options_), p); + p->Emit( + { + {"defaults", [&] { GenerateSourceDefaultInstance(idx, p); }}, + {"class_methods", + [&] { message_generators_[idx]->GenerateClassMethods(p); }}, + }, + R"cc( + $defaults$; - // Generate classes. - format("\n"); - message_generators_[idx]->GenerateClassMethods(printer); + $class_methods$; - format( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); - } // end package namespace + // @@protoc_insertion_point(namespace_scope) + )cc"); + } { - NamespaceOpener proto_ns(ProtobufNamespace(options_), format); - message_generators_[idx]->GenerateSourceInProto2Namespace(printer); + NamespaceOpener proto_ns(ProtobufNamespace(options_), p); + message_generators_[idx]->GenerateSourceInProto2Namespace(p); } - if (IsAnyMessage(file_, options_)) UnmuteWuninitialized(format); + if (IsAnyMessage(file_, options_)) { + UnmuteWuninitialized(p); + } - format( - "\n" - "// @@protoc_insertion_point(global_scope)\n"); + p->Emit(R"cc( + // @@protoc_insertion_point(global_scope) + )cc"); } -void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) { - Formatter format(printer, variables_); - GenerateSourceIncludes(printer); - GenerateSourcePrelude(printer); - NamespaceOpener ns(Namespace(file_, options_), format); - extension_generators_[idx]->GenerateDefinition(printer); +void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* p) { + auto v = p->WithVars(FileVars(file_, options_)); + GenerateSourceIncludes(p); + GenerateSourcePrelude(p); + + NamespaceOpener ns(Namespace(file_, options_), p); + extension_generators_[idx]->GenerateDefinition(p); } -void FileGenerator::GenerateGlobalSource(io::Printer* printer) { - Formatter format(printer, variables_); - GenerateSourceIncludes(printer); - GenerateSourcePrelude(printer); +void FileGenerator::GenerateGlobalSource(io::Printer* p) { + auto v = p->WithVars(FileVars(file_, options_)); + GenerateSourceIncludes(p); + GenerateSourcePrelude(p); { // Define the code to initialize reflection. This code uses a global // constructor to register reflection data with the runtime pre-main. if (HasDescriptorMethods(file_, options_)) { - GenerateReflectionInitializationCode(printer); + GenerateReflectionInitializationCode(p); } } - NamespaceOpener ns(Namespace(file_, options_), format); - - // Generate enums. - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->GenerateMethods(i, printer); + NamespaceOpener ns(Namespace(file_, options_), p); + for (int i = 0; i < enum_generators_.size(); ++i) { + enum_generators_[i]->GenerateMethods(i, p); } } -void FileGenerator::GenerateSource(io::Printer* printer) { - Formatter format(printer, variables_); - GenerateSourceIncludes(printer); - GenerateSourcePrelude(printer); +void FileGenerator::GenerateSource(io::Printer* p) { + auto v = p->WithVars(FileVars(file_, options_)); + + GenerateSourceIncludes(p); + GenerateSourcePrelude(p); CrossFileReferences refs; GetCrossFileReferencesForFile(file_, &refs); - GenerateInternalForwardDeclarations(refs, printer); + GenerateInternalForwardDeclarations(refs, p); - if (IsAnyMessage(file_, options_)) MuteWuninitialized(format); + if (IsAnyMessage(file_, options_)) { + MuteWuninitialized(p); + } { - NamespaceOpener ns(Namespace(file_, options_), format); - - // Define default instances - for (int i = 0; i < message_generators_.size(); i++) { - GenerateSourceDefaultInstance(i, printer); + NamespaceOpener ns(Namespace(file_, options_), p); + for (int i = 0; i < message_generators_.size(); ++i) { + GenerateSourceDefaultInstance(i, p); } } @@ -732,144 +804,155 @@ void FileGenerator::GenerateSource(io::Printer* printer) { if (HasDescriptorMethods(file_, options_)) { // Define the code to initialize reflection. This code uses a global // constructor to register reflection data with the runtime pre-main. - GenerateReflectionInitializationCode(printer); + GenerateReflectionInitializationCode(p); } } { - NamespaceOpener ns(Namespace(file_, options_), format); + NamespaceOpener ns(Namespace(file_, options_), p); // Actually implement the protos // Generate enums. - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->GenerateMethods(i, printer); + for (int i = 0; i < enum_generators_.size(); ++i) { + enum_generators_[i]->GenerateMethods(i, p); } // Generate classes. - for (int i = 0; i < message_generators_.size(); i++) { - format("\n"); - format(kThickSeparator); - format("\n"); - message_generators_[i]->GenerateClassMethods(printer); + for (int i = 0; i < message_generators_.size(); ++i) { + p->Emit(R"( + $hrule_thick$ + )"); + message_generators_[i]->GenerateClassMethods(p); } if (HasGenericServices(file_, options_)) { // Generate services. - for (int i = 0; i < service_generators_.size(); i++) { - if (i == 0) format("\n"); - format(kThickSeparator); - format("\n"); - service_generators_[i]->GenerateImplementation(printer); + for (int i = 0; i < service_generators_.size(); ++i) { + p->Emit(R"( + $hrule_thick$ + )"); + service_generators_[i]->GenerateImplementation(p); } } // Define extensions. - for (int i = 0; i < extension_generators_.size(); i++) { - extension_generators_[i]->GenerateDefinition(printer); + for (int i = 0; i < extension_generators_.size(); ++i) { + extension_generators_[i]->GenerateDefinition(p); } - format( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); + p->Emit(R"cc( + // @@protoc_insertion_point(namespace_scope) + )cc"); } { - NamespaceOpener proto_ns(ProtobufNamespace(options_), format); - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateSourceInProto2Namespace(printer); + NamespaceOpener proto_ns(ProtobufNamespace(options_), p); + for (int i = 0; i < message_generators_.size(); ++i) { + message_generators_[i]->GenerateSourceInProto2Namespace(p); } } - format( - "\n" - "// @@protoc_insertion_point(global_scope)\n"); + p->Emit(R"cc( + // @@protoc_insertion_point(global_scope) + )cc"); - if (IsAnyMessage(file_, options_)) UnmuteWuninitialized(format); + if (IsAnyMessage(file_, options_)) { + UnmuteWuninitialized(p); + } - IncludeFile("net/proto2/public/port_undef.inc", printer); + IncludeFile("third_party/protobuf/port_undef.inc", p); } -void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { - Formatter format(printer, variables_); - +void FileGenerator::GenerateReflectionInitializationCode(io::Printer* p) { if (!message_generators_.empty()) { - format("static ::_pb::Metadata $file_level_metadata$[$1$];\n", - message_generators_.size()); + p->Emit({{"len", message_generators_.size()}}, R"cc( + static ::_pb::Metadata $file_level_metadata$[$len$]; + )cc"); } + if (!enum_generators_.empty()) { - format( - "static const ::_pb::EnumDescriptor* " - "$file_level_enum_descriptors$[$1$];\n", - enum_generators_.size()); + p->Emit({{"len", enum_generators_.size()}}, R"cc( + static const ::_pb::EnumDescriptor* $file_level_enum_descriptors$[$len$]; + )cc"); } else { - format( - "static " - "constexpr ::_pb::EnumDescriptor const** " - "$file_level_enum_descriptors$ = nullptr;\n"); + p->Emit(R"cc( + static constexpr const ::_pb::EnumDescriptor** + $file_level_enum_descriptors$ = nullptr; + )cc"); } + if (HasGenericServices(file_, options_) && file_->service_count() > 0) { - format( - "static " - "const ::_pb::ServiceDescriptor* " - "$file_level_service_descriptors$[$1$];\n", - file_->service_count()); + p->Emit({{"len", file_->service_count()}}, R"cc( + static const ::_pb::ServiceDescriptor* + $file_level_service_descriptors$[$len$]; + )cc"); } else { - format( - "static " - "constexpr ::_pb::ServiceDescriptor const** " - "$file_level_service_descriptors$ = nullptr;\n"); + p->Emit(R"cc( + static constexpr const ::_pb::ServiceDescriptor** + $file_level_service_descriptors$ = nullptr; + )cc"); } if (!message_generators_.empty()) { - format( - "\n" - "const $uint32$ $tablename$::offsets[] " - "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); - format.Indent(); - std::vector<std::pair<size_t, size_t> > pairs; - pairs.reserve(message_generators_.size()); - for (int i = 0; i < message_generators_.size(); i++) { - pairs.push_back(message_generators_[i]->GenerateOffsets(printer)); - } - format.Outdent(); - format( - "};\n" - "static const ::_pbi::MigrationSchema schemas[] " - "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); - format.Indent(); - { - int offset = 0; - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateSchema(printer, offset, - pairs[i].second); - offset += pairs[i].first; - } - } - format.Outdent(); - format( - "};\n" - "\nstatic const ::_pb::Message* const file_default_instances[] = {\n"); - format.Indent(); - for (int i = 0; i < message_generators_.size(); i++) { - const Descriptor* descriptor = message_generators_[i]->descriptor_; - format("&$1$::_$2$_default_instance_._instance,\n", - Namespace(descriptor, options_), // 1 - ClassName(descriptor)); // 2 - } - format.Outdent(); - format( - "};\n" - "\n"); + std::vector<std::pair<size_t, size_t>> offsets; + offsets.reserve(message_generators_.size()); + + p->Emit( + { + {"offsets", + [&] { + for (int i = 0; i < message_generators_.size(); ++i) { + offsets.push_back(message_generators_[i]->GenerateOffsets(p)); + } + }}, + {"schemas", + [&] { + int offset = 0; + for (int i = 0; i < message_generators_.size(); ++i) { + message_generators_[i]->GenerateSchema(p, offset, + offsets[i].second); + offset += offsets[i].first; + } + }}, + {"defaults", + [&] { + for (auto& gen : message_generators_) { + p->Emit( + { + {"ns", Namespace(gen->descriptor(), options_)}, + {"class", ClassName(gen->descriptor())}, + }, + R"cc( + &$ns$::_$class$_default_instance_._instance, + )cc"); + } + }}, + }, + R"cc( + const ::arc_ui32 $tablename$::offsets[] PROTOBUF_SECTION_VARIABLE( + protodesc_cold) = { + $offsets$, + }; + + static const ::_pbi::MigrationSchema + schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + $schemas$, + }; + + static const ::_pb::Message* const file_default_instances[] = { + $defaults$, + }; + )cc"); } else { - // we still need these symbols to exist - format( - // MSVC doesn't like empty arrays, so we add a dummy. - "const $uint32$ $tablename$::offsets[1] = {};\n" - "static constexpr ::_pbi::MigrationSchema* schemas = nullptr;\n" - "static constexpr ::_pb::Message* const* " - "file_default_instances = nullptr;\n" - "\n"); + // Ee still need these symbols to exist. + // + // MSVC doesn't like empty arrays, so we add a dummy. + p->Emit(R"cc( + const ::arc_ui32 $tablename$::offsets[1] = {}; + static constexpr ::_pbi::MigrationSchema* schemas = nullptr; + static constexpr ::_pb::Message* const* file_default_instances = nullptr; + )cc"); } // --------------------------------------------------------------- @@ -877,63 +960,87 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // Embed the descriptor. We simply serialize the entire // FileDescriptorProto/ and embed it as a string literal, which is parsed and // built into real descriptors at initialization time. - const TProtoStringType protodef_name = - UniqueName("descriptor_table_protodef", file_, options_); - format("const char $1$[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =\n", - protodef_name); - format.Indent(); - FileDescriptorProto file_proto; - file_->CopyTo(&file_proto); + + FileDescriptorProto file_proto = StripSourceRetentionOptions(*file_); TProtoStringType file_data; file_proto.SerializeToString(&file_data); - { - if (file_data.size() > 65535) { - // Workaround for MSVC: "Error C1091: compiler limit: string exceeds - // 65535 bytes in length". Declare a static array of chars rather than - // use a string literal. Only write 25 bytes per line. - static const int kBytesPerLine = 25; - format("{ "); - for (int i = 0; i < file_data.size();) { - for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { - format("'$1$', ", CEscape(file_data.substr(i, 1))); - } - format("\n"); - } - format("'\\0' }"); // null-terminate - } else { - // Only write 40 bytes per line. - static const int kBytesPerLine = 40; - for (int i = 0; i < file_data.size(); i += kBytesPerLine) { - format( - "\"$1$\"\n", - EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine)))); - } - } - format(";\n"); - } - format.Outdent(); + auto desc_name = UniqueName("descriptor_table_protodef", file_, options_); + p->Emit( + {{"desc_name", desc_name}, + {"encoded_file_proto", + [&] { + y_absl::string_view data = file_data; + if (data.size() <= 65535) { + static constexpr size_t kBytesPerLine = 40; + while (!data.empty()) { + auto to_write = std::min(kBytesPerLine, data.size()); + auto chunk = data.substr(0, to_write); + data = data.substr(to_write); + + p->Emit({{"text", EscapeTrigraphs(y_absl::CEscape(chunk))}}, R"cc( + "$text$" + )cc"); + } + return; + } + + // Workaround for MSVC: "Error C1091: compiler limit: string exceeds + // 65535 bytes in length". Declare a static array of chars rather than + // use a string literal. Only write 25 bytes per line. + static constexpr size_t kBytesPerLine = 25; + while (!data.empty()) { + auto to_write = std::min(kBytesPerLine, data.size()); + auto chunk = data.substr(0, to_write); + data = data.substr(to_write); + + TProtoStringType line; + for (char c : chunk) { + y_absl::StrAppend(&line, "'", + y_absl::CEscape(y_absl::string_view(&c, 1)), "', "); + } + + p->Emit({{"line", line}}, R"cc( + $line$ + )cc"); + } + }}}, + R"cc( + const char $desc_name$[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = { + $encoded_file_proto$, + }; + )cc"); CrossFileReferences refs; GetCrossFileReferencesForFile(file_, &refs); - int num_deps = + size_t num_deps = refs.strong_reflection_files.size() + refs.weak_reflection_files.size(); // Build array of DescriptorTable deps. if (num_deps > 0) { - format( - "static const ::_pbi::DescriptorTable* const " - "$desc_table$_deps[$1$] = {\n", - num_deps); - - for (auto dep : Sorted(refs.strong_reflection_files)) { - format(" &::$1$,\n", DescriptorTableName(dep, options_)); - } - for (auto dep : Sorted(refs.weak_reflection_files)) { - format(" &::$1$,\n", DescriptorTableName(dep, options_)); - } - - format("};\n"); + p->Emit( + { + {"len", num_deps}, + {"deps", + [&] { + for (auto dep : refs.strong_reflection_files) { + p->Emit({{"name", DescriptorTableName(dep, options_)}}, R"cc( + &::$name$, + )cc"); + } + for (auto dep : refs.weak_reflection_files) { + p->Emit({{"name", DescriptorTableName(dep, options_)}}, R"cc( + &::$name$, + )cc"); + } + }}, + }, + R"cc( + static const ::_pbi::DescriptorTable* const $desc_table$_deps[$len$] = + { + $deps$, + }; + )cc"); } // The DescriptorTable itself. @@ -941,391 +1048,354 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // however this might cause a tsan failure in superroot b/148382879, // so disable for now. bool eager = false; - format( - "static ::_pbi::once_flag $desc_table$_once;\n" - "const ::_pbi::DescriptorTable $desc_table$ = {\n" - " false, $1$, $2$, $3$,\n" - " \"$filename$\",\n" - " &$desc_table$_once, $4$, $5$, $6$,\n" - " schemas, file_default_instances, $tablename$::offsets,\n" - " $7$, $file_level_enum_descriptors$,\n" - " $file_level_service_descriptors$,\n" - "};\n" - // This function exists to be marked as weak. - // It can significantly speed up compilation by breaking up LLVM's SCC in - // the .pb.cc translation units. Large translation units see a reduction - // of more than 35% of walltime for optimized builds. - // Without the weak attribute all the messages in the file, including all - // the vtables and everything they use become part of the same SCC through - // a cycle like: - // GetMetadata -> descriptor table -> default instances -> - // vtables -> GetMetadata - // By adding a weak function here we break the connection from the - // individual vtables back into the descriptor table. - "PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* " - "$desc_table$_getter() {\n" - " return &$desc_table$;\n" - "}\n" - "\n", - eager ? "true" : "false", file_data.size(), protodef_name, - num_deps == 0 ? "nullptr" : variables_["desc_table"] + "_deps", num_deps, - message_generators_.size(), - message_generators_.empty() ? "nullptr" - : variables_["file_level_metadata"]); + p->Emit( + { + {"eager", eager ? "true" : "false"}, + {"file_proto_len", file_data.size()}, + {"proto_name", desc_name}, + {"deps_ptr", num_deps == 0 + ? "nullptr" + : y_absl::StrCat(p->LookupVar("desc_table"), "_deps")}, + {"num_deps", num_deps}, + {"num_msgs", message_generators_.size()}, + {"msgs_ptr", message_generators_.empty() + ? "nullptr" + : TProtoStringType(p->LookupVar("file_level_metadata"))}, + }, + R"cc( + static ::y_absl::once_flag $desc_table$_once; + const ::_pbi::DescriptorTable $desc_table$ = { + false, + $eager$, + $file_proto_len$, + $proto_name$, + "$filename$", + &$desc_table$_once, + $deps_ptr$, + $num_deps$, + $num_msgs$, + schemas, + file_default_instances, + $tablename$::offsets, + $msgs_ptr$, + $file_level_enum_descriptors$, + $file_level_service_descriptors$, + }; + + // This function exists to be marked as weak. + // It can significantly speed up compilation by breaking up LLVM's SCC + // in the .pb.cc translation units. Large translation units see a + // reduction of more than 35% of walltime for optimized builds. Without + // the weak attribute all the messages in the file, including all the + // vtables and everything they use become part of the same SCC through + // a cycle like: + // GetMetadata -> descriptor table -> default instances -> + // vtables -> GetMetadata + // By adding a weak function here we break the connection from the + // individual vtables back into the descriptor table. + PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* $desc_table$_getter() { + return &$desc_table$; + } + )cc"); // For descriptor.proto we want to avoid doing any dynamic initialization, // because in some situations that would otherwise pull in a lot of // unnecessary code that can't be stripped by --gc-sections. Descriptor // initialization will still be performed lazily when it's needed. - if (file_->name() != "net/proto2/proto/descriptor.proto") { - format( - "// Force running AddDescriptors() at dynamic initialization time.\n" - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 " - "static ::_pbi::AddDescriptorsRunner $1$(&$desc_table$);\n", - UniqueName("dynamic_init_dummy", file_, options_)); + if (file_->name() == "net/proto2/proto/descriptor.proto") { + return; } + + p->Emit({{"dummy", UniqueName("dynamic_init_dummy", file_, options_)}}, R"cc( + // Force running AddDescriptors() at dynamic initialization time. + PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 + static ::_pbi::AddDescriptorsRunner $dummy$(&$desc_table$); + )cc"); } class FileGenerator::ForwardDeclarations { public: - void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; } - void AddEnum(const EnumDescriptor* d) { enums_[ClassName(d)] = d; } - void AddSplit(const Descriptor* d) { splits_[ClassName(d)] = d; } - - void Print(const Formatter& format, const Options& options) const { - for (const auto& p : enums_) { - const TProtoStringType& enumname = p.first; - const EnumDescriptor* enum_desc = p.second; - format( - "enum ${1$$2$$}$ : int;\n" - "bool $2$_IsValid(int value);\n", - enum_desc, enumname); + void AddMessage(const Descriptor* d) { classes_.emplace(ClassName(d), d); } + void AddEnum(const EnumDescriptor* d) { enums_.emplace(ClassName(d), d); } + void AddSplit(const Descriptor* d) { splits_.emplace(ClassName(d), d); } + + void Print(io::Printer* p, const Options& options) const { + for (const auto& e : enums_) { + p->Emit({Sub("enum", e.first).AnnotatedAs(e.second)}, R"cc( + enum $enum$ : int; + bool $enum$_IsValid(int value); + )cc"); } - for (const auto& p : classes_) { - const TProtoStringType& classname = p.first; - const Descriptor* class_desc = p.second; - format( - "class ${1$$2$$}$;\n" - "struct $3$;\n" - "$dllexport_decl $extern $3$ $4$;\n", - class_desc, classname, DefaultInstanceType(class_desc, options), - DefaultInstanceName(class_desc, options)); + + for (const auto& c : classes_) { + const Descriptor* desc = c.second; + p->Emit( + { + Sub("class", c.first).AnnotatedAs(desc), + {"default_type", DefaultInstanceType(desc, options)}, + {"default_name", DefaultInstanceName(desc, options)}, + }, + R"cc( + class $class$; + struct $default_type$; + $dllexport_decl $extern $default_type$ $default_name$; + )cc"); } - for (const auto& p : splits_) { - const Descriptor* class_desc = p.second; - format( - "struct $1$;\n" - "$dllexport_decl $extern $1$ $2$;\n", - DefaultInstanceType(class_desc, options, /*split=*/true), - DefaultInstanceName(class_desc, options, /*split=*/true)); + + for (const auto& s : splits_) { + const Descriptor* desc = s.second; + p->Emit( + { + {"default_type", + DefaultInstanceType(desc, options, /*split=*/true)}, + {"default_name", + DefaultInstanceName(desc, options, /*split=*/true)}, + }, + R"cc( + struct $default_type$; + $dllexport_decl $extern const $default_type$ $default_name$; + )cc"); } } - void PrintTopLevelDecl(const Formatter& format, - const Options& options) const { - for (const auto& pair : classes_) { - format( - "template<> $dllexport_decl $" - "$1$* Arena::CreateMaybeMessage<$1$>(Arena*);\n", - QualifiedClassName(pair.second, options)); + void PrintTopLevelDecl(io::Printer* p, const Options& options) const { + for (const auto& c : classes_) { + p->Emit({{"class", QualifiedClassName(c.second, options)}}, R"cc( + template <> + $dllexport_decl $$class$* Arena::CreateMaybeMessage<$class$>(Arena*); + )cc"); } } private: - std::map<TProtoStringType, const Descriptor*> classes_; - std::map<TProtoStringType, const EnumDescriptor*> enums_; - std::map<TProtoStringType, const Descriptor*> splits_; + y_absl::btree_map<TProtoStringType, const Descriptor*> classes_; + y_absl::btree_map<TProtoStringType, const EnumDescriptor*> enums_; + y_absl::btree_map<TProtoStringType, const Descriptor*> splits_; }; -static void PublicImportDFS(const FileDescriptor* fd, - std::unordered_set<const FileDescriptor*>* fd_set) { - for (int i = 0; i < fd->public_dependency_count(); i++) { +static void PublicImportDFS( + const FileDescriptor* fd, + y_absl::flat_hash_set<const FileDescriptor*>& fd_set) { + for (int i = 0; i < fd->public_dependency_count(); ++i) { const FileDescriptor* dep = fd->public_dependency(i); - if (fd_set->insert(dep).second) PublicImportDFS(dep, fd_set); + if (fd_set.insert(dep).second) { + PublicImportDFS(dep, fd_set); + } } } -void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { - Formatter format(printer, variables_); +void FileGenerator::GenerateForwardDeclarations(io::Printer* p) { std::vector<const Descriptor*> classes; - std::vector<const EnumDescriptor*> enums; - FlattenMessagesInFile(file_, &classes); // All messages need forward decls. - std::vector<const FieldDescriptor*> fields; - if (!options_.transitive_pb_h || options_.proto_h) { - ListAllFields(file_, &fields); - } - - if (!options_.transitive_pb_h) { - // Add forward declaration for all messages, enums, and extended messages - // defined outside the file - for (int i = 0; i < fields.size(); i++) { - const Descriptor* message_type = fields[i]->message_type(); - if (message_type && message_type->file() != file_) { - classes.push_back(message_type); - } - - const EnumDescriptor* enum_type = fields[i]->enum_type(); - if (enum_type && enum_type->file() != file_) { - enums.push_back(enum_type); - } - - if (fields[i]->is_extension()) { - const Descriptor* message_type = fields[i]->containing_type(); - if (message_type && message_type->file() != file_) { - classes.push_back(message_type); - } - } - } - } - + std::vector<const EnumDescriptor*> enums; if (options_.proto_h) { // proto.h needs extra forward declarations. // All classes / enums referred to as field members - for (int i = 0; i < fields.size(); i++) { - classes.push_back(fields[i]->containing_type()); - classes.push_back(fields[i]->message_type()); - enums.push_back(fields[i]->enum_type()); + std::vector<const FieldDescriptor*> fields; + ListAllFields(file_, &fields); + for (const auto* field : fields) { + classes.push_back(field->containing_type()); + classes.push_back(field->message_type()); + enums.push_back(field->enum_type()); } + ListAllTypesForServices(file_, &classes); } // Calculate the set of files whose definitions we get through include. // No need to forward declare types that are defined in these. - std::unordered_set<const FileDescriptor*> public_set; - if (options_.transitive_pb_h) { - PublicImportDFS(file_, &public_set); - } + y_absl::flat_hash_set<const FileDescriptor*> public_set; + PublicImportDFS(file_, public_set); - std::map<TProtoStringType, ForwardDeclarations> decls; - for (int i = 0; i < classes.size(); i++) { - const Descriptor* d = classes[i]; - if (d && !public_set.count(d->file())) + y_absl::btree_map<TProtoStringType, ForwardDeclarations> decls; + for (const auto* d : classes) { + if (d != nullptr && !public_set.count(d->file())) decls[Namespace(d, options_)].AddMessage(d); } - for (int i = 0; i < enums.size(); i++) { - const EnumDescriptor* d = enums[i]; - if (d && !public_set.count(d->file())) - decls[Namespace(d, options_)].AddEnum(d); + for (const auto* e : enums) { + if (e != nullptr && !public_set.count(e->file())) + decls[Namespace(e, options_)].AddEnum(e); } for (const auto& mg : message_generators_) { - const Descriptor* d = mg->descriptor_; - if ((d != nullptr) && (public_set.count(d->file()) == 0u) && - ShouldSplit(mg->descriptor_, options_)) + const Descriptor* d = mg->descriptor(); + if (d != nullptr && public_set.count(d->file()) == 0u && + ShouldSplit(mg->descriptor(), options_)) decls[Namespace(d, options_)].AddSplit(d); } - { - NamespaceOpener ns(format); - for (const auto& pair : decls) { - ns.ChangeTo(pair.first); - pair.second.Print(format, options_); - } - } - format("PROTOBUF_NAMESPACE_OPEN\n"); - for (const auto& pair : decls) { - pair.second.PrintTopLevelDecl(format, options_); + NamespaceOpener ns(p); + for (const auto& decl : decls) { + ns.ChangeTo(decl.first); + decl.second.Print(p, options_); } - format("PROTOBUF_NAMESPACE_CLOSE\n"); -} - -void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, bool pb_h, bool deps) { - Formatter format(printer, variables_); - // Generate top of header. - format( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n" - "#ifndef $1$\n" - "#define $1$\n" - "\n" - "#include <limits>\n" - "#include <string>\n", - IncludeGuard(file_, pb_h, deps, options_)); - if (!options_.opensource_runtime && !enum_generators_.empty()) { - // Add header to provide std::is_integral for safe Enum_Name() function. - format("#include <type_traits>\n"); - } - format("\n"); -} -void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer, bool pb_h, bool deps) { - Formatter format(printer, variables_); - format("#endif // $GOOGLE_PROTOBUF$_INCLUDED_$1$\n", - IncludeGuard(file_, pb_h, deps, options_)); + ns.ChangeTo("PROTOBUF_NAMESPACE_ID"); + for (const auto& decl : decls) { + decl.second.PrintTopLevelDecl(p, options_); + } } -void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { - Formatter format(printer, variables_); +void FileGenerator::GenerateLibraryIncludes(io::Printer* p) { if (UsingImplicitWeakFields(file_, options_)) { - IncludeFile("net/proto2/public/implicit_weak_message.h", printer); + IncludeFile("third_party/protobuf/implicit_weak_message.h", p); } if (HasWeakFields(file_, options_)) { - GOOGLE_CHECK(!options_.opensource_runtime); - IncludeFile("net/proto2/public/weak_field_map.h", printer); + Y_ABSL_CHECK(!options_.opensource_runtime); + IncludeFile("third_party/protobuf/weak_field_map.h", p); } if (HasLazyFields(file_, options_, &scc_analyzer_)) { - GOOGLE_CHECK(!options_.opensource_runtime); - IncludeFile("net/proto2/public/lazy_field.h", printer); + Y_ABSL_CHECK(!options_.opensource_runtime); + IncludeFile("third_party/protobuf/lazy_field.h", p); } if (ShouldVerify(file_, options_, &scc_analyzer_)) { - IncludeFile("net/proto2/public/wire_format_verify.h", printer); + IncludeFile("third_party/protobuf/wire_format_verify.h", p); } if (options_.opensource_runtime) { // Verify the protobuf library header version is compatible with the protoc // version before going any further. - IncludeFile("net/proto2/public/port_def.inc", printer); - format( - "#if PROTOBUF_VERSION < $1$\n" - "#error This file was generated by a newer version of protoc which is\n" - "#error incompatible with your Protocol Buffer headers. Please update\n" - "#error your headers.\n" - "#endif\n" - "#if $2$ < PROTOBUF_MIN_PROTOC_VERSION\n" - "#error This file was generated by an older version of protoc which " - "is\n" - "#error incompatible with your Protocol Buffer headers. Please\n" - "#error regenerate this file with a newer version of protoc.\n" - "#endif\n" - "\n", - PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC, // 1 - PROTOBUF_VERSION); // 2 - IncludeFile("net/proto2/public/port_undef.inc", printer); + IncludeFile("third_party/protobuf/port_def.inc", p); + p->Emit( + { + {"min_version", PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC}, + {"version", PROTOBUF_VERSION}, + }, + R"( + #if PROTOBUF_VERSION < $min_version$ + #error "This file was generated by a newer version of protoc which is" + #error "incompatible with your Protocol Buffer headers. Please update" + #error "your headers." + #endif // PROTOBUF_VERSION + + #if $version$ < PROTOBUF_MIN_PROTOC_VERSION + #error "This file was generated by an older version of protoc which is" + #error "incompatible with your Protocol Buffer headers. Please" + #error "regenerate this file with a newer version of protoc." + #endif // PROTOBUF_MIN_PROTOC_VERSION + )"); + IncludeFile("third_party/protobuf/port_undef.inc", p); } // OK, it's now safe to #include other files. - IncludeFile("net/proto2/io/public/coded_stream.h", printer); - IncludeFile("net/proto2/public/arena.h", printer); - IncludeFile("net/proto2/public/arenastring.h", printer); + IncludeFile("third_party/protobuf/io/coded_stream.h", p); + IncludeFile("third_party/protobuf/arena.h", p); + IncludeFile("third_party/protobuf/arenastring.h", p); if ((options_.force_inline_string || options_.profile_driven_inline_string) && !options_.opensource_runtime) { - IncludeFile("net/proto2/public/inlined_string_field.h", printer); + IncludeFile("third_party/protobuf/inlined_string_field.h", p); } if (HasSimpleBaseClasses(file_, options_)) { - IncludeFile("net/proto2/public/generated_message_bases.h", printer); + IncludeFile("third_party/protobuf/generated_message_bases.h", p); } if (HasGeneratedMethods(file_, options_) && options_.tctable_mode != Options::kTCTableNever) { - IncludeFile("net/proto2/public/generated_message_tctable_decl.h", printer); + IncludeFile("third_party/protobuf/generated_message_tctable_decl.h", p); } - IncludeFile("net/proto2/public/generated_message_util.h", printer); - IncludeFile("net/proto2/public/metadata_lite.h", printer); + IncludeFile("third_party/protobuf/generated_message_util.h", p); + IncludeFile("third_party/protobuf/metadata_lite.h", p); if (HasDescriptorMethods(file_, options_)) { - IncludeFile("net/proto2/public/generated_message_reflection.h", printer); + IncludeFile("third_party/protobuf/generated_message_reflection.h", p); } if (!message_generators_.empty()) { if (HasDescriptorMethods(file_, options_)) { - IncludeFile("net/proto2/public/message.h", printer); + IncludeFile("third_party/protobuf/message.h", p); } else { - IncludeFile("net/proto2/public/message_lite.h", printer); + IncludeFile("third_party/protobuf/message_lite.h", p); } } if (options_.opensource_runtime) { // Open-source relies on unconditional includes of these. - IncludeFileAndExport("net/proto2/public/repeated_field.h", printer); - IncludeFileAndExport("net/proto2/public/extension_set.h", printer); + IncludeFileAndExport("third_party/protobuf/repeated_field.h", p); + IncludeFileAndExport("third_party/protobuf/extension_set.h", p); } else { // Google3 includes these files only when they are necessary. if (HasExtensionsOrExtendableMessage(file_)) { - IncludeFileAndExport("net/proto2/public/extension_set.h", printer); + IncludeFileAndExport("third_party/protobuf/extension_set.h", p); } if (HasRepeatedFields(file_)) { - IncludeFileAndExport("net/proto2/public/repeated_field.h", printer); + IncludeFileAndExport("third_party/protobuf/repeated_field.h", p); } if (HasStringPieceFields(file_, options_)) { - IncludeFile("net/proto2/public/string_piece_field_support.h", printer); + IncludeFile("third_party/protobuf/string_piece_field_support.h", p); } if (HasCordFields(file_, options_)) { - format("#include \"third_party/absl/strings/cord.h\"\n"); + p->Emit(R"( + #include "y_absl/strings/cord.h" + )"); } } if (HasMapFields(file_)) { - IncludeFileAndExport("net/proto2/public/map.h", printer); + IncludeFileAndExport("third_party/protobuf/map.h", p); if (HasDescriptorMethods(file_, options_)) { - IncludeFile("net/proto2/public/map_entry.h", printer); - IncludeFile("net/proto2/public/map_field_inl.h", printer); + IncludeFile("third_party/protobuf/map_entry.h", p); + IncludeFile("third_party/protobuf/map_field_inl.h", p); } else { - IncludeFile("net/proto2/public/map_entry_lite.h", printer); - IncludeFile("net/proto2/public/map_field_lite.h", printer); + IncludeFile("third_party/protobuf/map_entry_lite.h", p); + IncludeFile("third_party/protobuf/map_field_lite.h", p); } } if (HasEnumDefinitions(file_)) { if (HasDescriptorMethods(file_, options_)) { - IncludeFile("net/proto2/public/generated_enum_reflection.h", printer); + IncludeFile("third_party/protobuf/generated_enum_reflection.h", p); } else { - IncludeFile("net/proto2/public/generated_enum_util.h", printer); + IncludeFile("third_party/protobuf/generated_enum_util.h", p); } } if (HasGenericServices(file_, options_)) { - IncludeFile("net/proto2/public/service.h", printer); + IncludeFile("third_party/protobuf/service.h", p); } if (UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { - IncludeFile("net/proto2/public/unknown_field_set.h", printer); + IncludeFile("third_party/protobuf/unknown_field_set.h", p); } } -void FileGenerator::GenerateMetadataPragma(io::Printer* printer, - const TProtoStringType& info_path) { - Formatter format(printer, variables_); - if (!info_path.empty() && !options_.annotation_pragma_name.empty() && - !options_.annotation_guard_name.empty()) { - format.Set("guard", options_.annotation_guard_name); - format.Set("pragma", options_.annotation_pragma_name); - format.Set("info_path", info_path); - format( - "#ifdef $guard$\n" - "#pragma $pragma$ \"$info_path$\"\n" - "#endif // $guard$\n"); +void FileGenerator::GenerateMetadataPragma(io::Printer* p, + y_absl::string_view info_path) { + if (info_path.empty() || options_.annotation_pragma_name.empty() || + options_.annotation_guard_name.empty()) { + return; } -} - -void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { - Formatter format(printer, variables_); - std::queue<const FileDescriptor*> files_queue; - std::unordered_set<const FileDescriptor*> included_files; - files_queue.push(file_); - included_files.insert(file_); - - while (!files_queue.empty()) { - const FileDescriptor* file = files_queue.front(); - files_queue.pop(); - - for (int i = 0; i < file->dependency_count(); i++) { - // try figure out if this file have not been included yet - const FileDescriptor* dependency_file = file->dependency(i); - if (!options_.transitive_pb_h) { - auto [iter, is_inserted] = included_files.insert(dependency_file); - if (is_inserted) { - files_queue.push(dependency_file); - } else { - continue; - } - } - TProtoStringType basename = StripProto(dependency_file->name()); + p->Emit( + { + {"guard", options_.annotation_guard_name}, + {"pragma", options_.annotation_pragma_name}, + {"info_path", TProtoStringType(info_path)}, + }, + R"( + #ifdef $guard$ + #pragma $pragma$ "$info_path$" + #endif // $guard$ + )"); +} - // Do not import weak deps. - if (IsDepWeak(dependency_file)) continue; +void FileGenerator::GenerateDependencyIncludes(io::Printer* p) { + for (int i = 0; i < file_->dependency_count(); ++i) { + const FileDescriptor* dep = file_->dependency(i); - if (IsBootstrapProto(options_, file)) { - GetBootstrapBasename(options_, basename, &basename); - } + // Do not import weak deps. + if (IsDepWeak(dep)) { + continue; + } - format("#include $1$\n", - CreateHeaderInclude(basename + ".pb.h", dependency_file)); + TProtoStringType basename = StripProto(dep->name()); + if (IsBootstrapProto(options_, file_)) { + GetBootstrapBasename(options_, basename, &basename); } + + p->Emit( + {{"name", CreateHeaderInclude(y_absl::StrCat(basename, ".pb.h"), dep)}}, + "#" "include" "$name$\n" + ); } } -void FileGenerator::GenerateGlobalStateFunctionDeclarations( - io::Printer* printer) { - Formatter format(printer, variables_); +void FileGenerator::GenerateGlobalStateFunctionDeclarations(io::Printer* p) { // Forward-declare the DescriptorTable because this is referenced by .pb.cc // files depending on this file. // @@ -1333,114 +1403,102 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( // weak fields must refer to table struct but cannot include the header. // Also it annotates extra weak attributes. // TODO(gerbens) make sure this situation is handled better. - format( - "\n" - "// Internal implementation detail -- do not use these members.\n" - "struct $dllexport_decl $$tablename$ {\n" - " static const $uint32$ offsets[];\n" - "};\n"); + p->Emit(R"cc( + // Internal implementation detail -- do not use these members. + struct $dllexport_decl $$tablename$ { + static const ::arc_ui32 offsets[]; + }; + )cc"); + if (HasDescriptorMethods(file_, options_)) { - format( - "$dllexport_decl $extern const ::$proto_ns$::internal::DescriptorTable " - "$desc_table$;\n"); + p->Emit(R"cc( + $dllexport_decl $extern const ::$proto_ns$::internal::DescriptorTable + $desc_table$; + )cc"); } } -void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { - Formatter format(printer, variables_); - // Generate class definitions. - for (int i = 0; i < message_generators_.size(); i++) { - if (i > 0) { - format("\n"); - format(kThinSeparator); - format("\n"); - } - message_generators_[i]->GenerateClassDefinition(printer); +void FileGenerator::GenerateMessageDefinitions(io::Printer* p) { + for (int i = 0; i < message_generators_.size(); ++i) { + p->Emit(R"cc( + $hrule_thin$ + )cc"); + message_generators_[i]->GenerateClassDefinition(p); } } -void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { - // Generate enum definitions. - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->GenerateDefinition(printer); +void FileGenerator::GenerateEnumDefinitions(io::Printer* p) { + for (int i = 0; i < enum_generators_.size(); ++i) { + enum_generators_[i]->GenerateDefinition(p); } } -void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { - Formatter format(printer, variables_); - if (HasGenericServices(file_, options_)) { - // Generate service definitions. - for (int i = 0; i < service_generators_.size(); i++) { - if (i > 0) { - format("\n"); - format(kThinSeparator); - format("\n"); - } - service_generators_[i]->GenerateDeclarations(printer); - } +void FileGenerator::GenerateServiceDefinitions(io::Printer* p) { + if (!HasGenericServices(file_, options_)) { + return; + } - format("\n"); - format(kThickSeparator); - format("\n"); + for (int i = 0; i < service_generators_.size(); ++i) { + p->Emit(R"cc( + $hrule_thin$ + )cc"); + service_generators_[i]->GenerateDeclarations(p); } + + p->Emit(R"cc( + $hrule_thick$ + )cc"); } -void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { +void FileGenerator::GenerateExtensionIdentifiers(io::Printer* p) { // Declare extension identifiers. These are in global scope and so only // the global scope extensions. for (auto& extension_generator : extension_generators_) { - if (extension_generator->IsScoped()) continue; - extension_generator->GenerateDeclaration(printer); + if (extension_generator->IsScoped()) { + continue; + } + extension_generator->GenerateDeclaration(p); } } -void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { - Formatter format(printer, variables_); +void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* p) { // TODO(gerbens) remove pragmas when gcc is no longer used. Current version // of gcc fires a bogus error when compiled with strict-aliasing. - format( - "#ifdef __GNUC__\n" - " #pragma GCC diagnostic push\n" - " #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n" - "#endif // __GNUC__\n"); - // Generate class inline methods. - for (int i = 0; i < message_generators_.size(); i++) { - if (i > 0) { - format(kThinSeparator); - format("\n"); - } - message_generators_[i]->GenerateInlineMethods(printer); - } - format( - "#ifdef __GNUC__\n" - " #pragma GCC diagnostic pop\n" - "#endif // __GNUC__\n"); + p->Emit(R"( + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-aliasing" + #endif // __GNUC__ + )"); + + for (int i = 0; i < message_generators_.size(); ++i) { + p->Emit(R"cc( + $hrule_thin$ + )cc"); + message_generators_[i]->GenerateInlineMethods(p); + } + + p->Emit(R"( + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif // __GNUC__ + )"); +} - for (int i = 0; i < message_generators_.size(); i++) { - if (i > 0) { - format(kThinSeparator); - format("\n"); - } +void FileGenerator::GenerateProto2NamespaceEnumSpecializations(io::Printer* p) { + // Emit GetEnumDescriptor specializations into google::protobuf namespace. + if (!HasEnumDefinitions(file_)) { + return; } -} -void FileGenerator::GenerateProto2NamespaceEnumSpecializations( - io::Printer* printer) { - Formatter format(printer, variables_); - // Emit GetEnumDescriptor specializations into google::protobuf namespace: - if (HasEnumDefinitions(file_)) { - format("\n"); - { - NamespaceOpener proto_ns(ProtobufNamespace(options_), format); - format("\n"); - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); - } - format("\n"); - } + p->PrintRaw("\n"); + NamespaceOpener ns(ProtobufNamespace(options_), p); + p->PrintRaw("\n"); + for (auto& gen : enum_generators_) { + gen->GenerateGetEnumDescriptorSpecializations(p); } + p->PrintRaw("\n"); } - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.h index 805b4979bf5..7f41bfae12f 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.h @@ -36,53 +36,47 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ #include <algorithm> +#include <functional> #include <memory> -#include <set> #include <string> #include <vector> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/cpp/field.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/scc.h> -#include <google/protobuf/compiler/cpp/options.h> - -namespace google { -namespace protobuf { -class FileDescriptor; // descriptor.h -namespace io { -class Printer; // printer.h -} -} // namespace protobuf -} // namespace google +#include "google/protobuf/stubs/common.h" +#include "google/protobuf/compiler/scc.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/log/absl_check.h" +#include "google/protobuf/compiler/cpp/enum.h" +#include "google/protobuf/compiler/cpp/extension.h" +#include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/message.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/compiler/cpp/service.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/port.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - -class EnumGenerator; // enum.h -class MessageGenerator; // message.h -class ServiceGenerator; // service.h -class ExtensionGenerator; // extension.h - class FileGenerator { public: - // See generator.cc for the meaning of dllexport_decl. FileGenerator(const FileDescriptor* file, const Options& options); - ~FileGenerator(); - // Shared code between the two header generators below. - void GenerateHeader(io::Printer* printer); + FileGenerator(const FileGenerator&) = delete; + FileGenerator& operator=(const FileGenerator&) = delete; + + ~FileGenerator() = default; // info_path, if non-empty, should be the path (relative to printer's // output) to the metadata file describing this proto header. - void GenerateProtoHeader(io::Printer* printer, const TProtoStringType& info_path); + void GenerateProtoHeader(io::Printer* p, y_absl::string_view info_path); // info_path, if non-empty, should be the path (relative to printer's // output) to the metadata file describing this PB header. - void GeneratePBHeader(io::Printer* printer, const TProtoStringType& info_path); - void GeneratePBDeps(io::Printer* printer, const TProtoStringType& info_path); - void GenerateSource(io::Printer* printer); + void GeneratePBHeader(io::Printer* p, y_absl::string_view info_path); + void GenerateSource(io::Printer* p); // The following member functions are used when the lite_implicit_weak_fields // option is set. In this mode the code is organized a bit differently to @@ -93,78 +87,86 @@ class FileGenerator { int NumMessages() const { return message_generators_.size(); } int NumExtensions() const { return extension_generators_.size(); } // Generates the source file for one message. - void GenerateSourceForMessage(int idx, io::Printer* printer); + void GenerateSourceForMessage(int idx, io::Printer* p); // Generates the source file for one extension. - void GenerateSourceForExtension(int idx, io::Printer* printer); + void GenerateSourceForExtension(int idx, io::Printer* p); // Generates a source file containing everything except messages and // extensions. - void GenerateGlobalSource(io::Printer* printer); + void GenerateGlobalSource(io::Printer* p); private: + // Generates a file, setting up the necessary accoutrements that start and + // end the file, calling `cb` in between. + // + // This includes header guards and file-global variables. + void GenerateFile(io::Printer* p, GeneratedFileType file_type, + std::function<void()> cb); + + // Shared code between the two header generators. + void GenerateSharedHeaderCode(io::Printer* p); + // Internal type used by GenerateForwardDeclarations (defined in file.cc). class ForwardDeclarations; struct CrossFileReferences; - void IncludeFile(const TProtoStringType& google3_name, io::Printer* printer) { - DoIncludeFile(google3_name, false, printer); + void IncludeFile(y_absl::string_view google3_name, io::Printer* p) { + DoIncludeFile(google3_name, false, p); } - void IncludeFileAndExport(const TProtoStringType& google3_name, - io::Printer* printer) { - DoIncludeFile(google3_name, true, printer); + void IncludeFileAndExport(y_absl::string_view google3_name, io::Printer* p) { + DoIncludeFile(google3_name, true, p); } - void DoIncludeFile(const TProtoStringType& google3_name, bool do_export, - io::Printer* printer); + void DoIncludeFile(y_absl::string_view google3_name, bool do_export, + io::Printer* p); - TProtoStringType CreateHeaderInclude(const TProtoStringType& basename, + TProtoStringType CreateHeaderInclude(y_absl::string_view basename, const FileDescriptor* file); void GetCrossFileReferencesForField(const FieldDescriptor* field, CrossFileReferences* refs); void GetCrossFileReferencesForFile(const FileDescriptor* file, CrossFileReferences* refs); void GenerateInternalForwardDeclarations(const CrossFileReferences& refs, - io::Printer* printer); - void GenerateSourceIncludes(io::Printer* printer); - void GenerateSourcePrelude(io::Printer* printer); - void GenerateSourceDefaultInstance(int idx, io::Printer* printer); + io::Printer* p); + void GenerateSourceIncludes(io::Printer* p); + void GenerateSourcePrelude(io::Printer* p); + void GenerateSourceDefaultInstance(int idx, io::Printer* p); void GenerateInitForSCC(const SCC* scc, const CrossFileReferences& refs, - io::Printer* printer); - void GenerateReflectionInitializationCode(io::Printer* printer); + io::Printer* p); + void GenerateReflectionInitializationCode(io::Printer* p); // For other imports, generates their forward-declarations. - void GenerateForwardDeclarations(io::Printer* printer); + void GenerateForwardDeclarations(io::Printer* p); // Generates top or bottom of a header file. - void GenerateTopHeaderGuard(io::Printer* printer, bool pb_h, bool deps = false); - void GenerateBottomHeaderGuard(io::Printer* printer, bool pb_h, bool deps = false); + void GenerateTopHeaderGuard(io::Printer* p, GeneratedFileType file_type); + void GenerateBottomHeaderGuard(io::Printer* p, GeneratedFileType file_type); // Generates #include directives. - void GenerateLibraryIncludes(io::Printer* printer); - void GenerateDependencyIncludes(io::Printer* printer); + void GenerateLibraryIncludes(io::Printer* p); + void GenerateDependencyIncludes(io::Printer* p); // Generate a pragma to pull in metadata using the given info_path (if // non-empty). info_path should be relative to printer's output. - void GenerateMetadataPragma(io::Printer* printer, - const TProtoStringType& info_path); + void GenerateMetadataPragma(io::Printer* p, y_absl::string_view info_path); // Generates a couple of different pieces before definitions: - void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); + void GenerateGlobalStateFunctionDeclarations(io::Printer* p); // Generates types for classes. - void GenerateMessageDefinitions(io::Printer* printer); + void GenerateMessageDefinitions(io::Printer* p); - void GenerateEnumDefinitions(io::Printer* printer); + void GenerateEnumDefinitions(io::Printer* p); // Generates generic service definitions. - void GenerateServiceDefinitions(io::Printer* printer); + void GenerateServiceDefinitions(io::Printer* p); // Generates extension identifiers. - void GenerateExtensionIdentifiers(io::Printer* printer); + void GenerateExtensionIdentifiers(io::Printer* p); // Generates inline function definitions. - void GenerateInlineFunctionDefinitions(io::Printer* printer); + void GenerateInlineFunctionDefinitions(io::Printer* p); - void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer); + void GenerateProto2NamespaceEnumSpecializations(io::Printer* p); // Sometimes the names we use in a .proto file happen to be defined as // macros on some platforms (e.g., macro/minor used in plugin.proto are @@ -173,24 +175,27 @@ class FileGenerator { // undef the macro for these few platforms, or rename the field name for all // platforms. Since these names are part of protobuf public API, renaming is // generally a breaking change so we prefer the #undef approach. - void GenerateMacroUndefs(io::Printer* printer); + void GenerateMacroUndefs(io::Printer* p); bool IsDepWeak(const FileDescriptor* dep) const { if (weak_deps_.count(dep) != 0) { - GOOGLE_CHECK(!options_.opensource_runtime); + Y_ABSL_CHECK(!options_.opensource_runtime); return true; } return false; } - std::set<const FileDescriptor*> weak_deps_; + y_absl::flat_hash_set<const FileDescriptor*> weak_deps_; const FileDescriptor* file_; - const Options options_; + Options options_; MessageSCCAnalyzer scc_analyzer_; - std::map<TProtoStringType, TProtoStringType> variables_; + // This member is unused and should be deleted once all old-style variable + // maps are gone. + // TODO(b/245791219) + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> variables_; // Contains the post-order walk of all the messages (and child messages) in // this file. If you need a pre-order walk just reverse iterate. @@ -198,8 +203,6 @@ class FileGenerator { std::vector<std::unique_ptr<EnumGenerator>> enum_generators_; std::vector<std::unique_ptr<ServiceGenerator>> service_generators_; std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); }; } // namespace cpp diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.cc index 0da2027a1e6..6187b72cbab 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.cc @@ -32,31 +32,68 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/generator.h> +#include "google/protobuf/compiler/cpp/generator.h" +#include <cstdlib> #include <memory> #include <string> #include <utility> #include <vector> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/compiler/cpp/file.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/descriptor.pb.h> +#include "y_absl/strings/match.h" +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/string_view.h" +#include "google/protobuf/compiler/cpp/file.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/descriptor.pb.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { +namespace { +TProtoStringType NumberedCcFileName(y_absl::string_view basename, int number) { + return y_absl::StrCat(basename, ".out/", number, ".cc"); +} -CppGenerator::CppGenerator() {} -CppGenerator::~CppGenerator() {} +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> CommonVars( + const Options& options) { + bool is_oss = options.opensource_runtime; + return { + {"proto_ns", ProtobufNamespace(options)}, + {"pb", y_absl::StrCat("::", ProtobufNamespace(options))}, + {"pbi", y_absl::StrCat("::", ProtobufNamespace(options), "::internal")}, -namespace { -TProtoStringType NumberedCcFileName(const TProtoStringType& basename, int number) { - return StrCat(basename, ".out/", number, ".cc"); + {"string", "TProtoStringType"}, + {"int8", "::int8_t"}, + {"int32", "::arc_i32"}, + {"int64", "::arc_i64"}, + {"uint8", "::uint8_t"}, + {"uint32", "::arc_ui32"}, + {"uint64", "::arc_ui64"}, + + {"hrule_thick", kThickSeparator}, + {"hrule_thin", kThinSeparator}, + + // Warning: there is some clever naming/splitting here to avoid extract + // script rewrites. The names of these variables must not be things that + // the extract script will rewrite. That's why we use "CHK" (for example) + // instead of "Y_ABSL_CHECK". + // + // These values are things the extract script would rewrite if we did not + // split them. It might not strictly matter since we don't generate + // google3 code in open-source. But it's good to prevent surprising + // things from happening. + {"GOOGLE_PROTOBUF", is_oss ? "GOOGLE_PROTOBUF" + : "GOOGLE3_PROTOBU" + "F"}, + {"CHK", + "Y_ABSL_CHEC" + "K"}, + {"DCHK", + "Y_ABSL_DCHEC" + "K"}, + }; } } // namespace @@ -64,7 +101,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, const TProtoStringType& parameter, GeneratorContext* generator_context, TProtoStringType* error) const { - std::vector<std::pair<TProtoStringType, TProtoStringType> > options; + std::vector<std::pair<TProtoStringType, TProtoStringType>> options; ParseGeneratorParameter(parameter, &options); // ----------------------------------------------------------------- @@ -93,72 +130,69 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_options.opensource_runtime = opensource_runtime_; file_options.runtime_include_base = runtime_include_base_; - for (int i = 0; i < options.size(); i++) { - if (options[i].first == "dllexport_decl") { - file_options.dllexport_decl = options[i].second; - } else if (options[i].first == "safe_boundary_check") { + for (const auto& option : options) { + const auto& key = option.first; + const auto& value = option.second; + + if (key == "dllexport_decl") { + file_options.dllexport_decl = value; + } else if (key == "safe_boundary_check") { file_options.safe_boundary_check = true; - } else if (options[i].first == "annotate_headers") { + } else if (key == "annotate_headers") { file_options.annotate_headers = true; - } else if (options[i].first == "annotation_pragma_name") { - file_options.annotation_pragma_name = options[i].second; - } else if (options[i].first == "annotation_guard_name") { - file_options.annotation_guard_name = options[i].second; - } else if (options[i].first == "speed") { + } else if (key == "annotation_pragma_name") { + file_options.annotation_pragma_name = value; + } else if (key == "annotation_guard_name") { + file_options.annotation_guard_name = value; + } else if (key == "speed") { file_options.enforce_mode = EnforceOptimizeMode::kSpeed; - } else if (options[i].first == "code_size") { + } else if (key == "code_size") { file_options.enforce_mode = EnforceOptimizeMode::kCodeSize; - } else if (options[i].first == "lite") { + } else if (key == "lite") { file_options.enforce_mode = EnforceOptimizeMode::kLiteRuntime; - } else if (options[i].first == "lite_implicit_weak_fields") { + } else if (key == "lite_implicit_weak_fields") { file_options.enforce_mode = EnforceOptimizeMode::kLiteRuntime; file_options.lite_implicit_weak_fields = true; - if (!options[i].second.empty()) { - file_options.num_cc_files = - strto32(options[i].second.c_str(), nullptr, 10); + if (!value.empty()) { + file_options.num_cc_files = std::strtol(value.c_str(), nullptr, 10); } - } else if (options[i].first == "proto_h") { + } else if (key == "proto_h") { file_options.proto_h = true; - } else if (options[i].first == "annotate_accessor") { + } else if (key == "proto_static_reflection_h") { + } else if (key == "annotate_accessor") { file_options.annotate_accessor = true; - } else if (options[i].first == "inject_field_listener_events") { + } else if (key == "inject_field_listener_events") { file_options.field_listener_options.inject_field_listener_events = true; - } else if (options[i].first == "forbidden_field_listener_events") { + } else if (key == "forbidden_field_listener_events") { std::size_t pos = 0; do { - std::size_t next_pos = options[i].second.find_first_of("+", pos); + std::size_t next_pos = value.find_first_of("+", pos); if (next_pos == TProtoStringType::npos) { - next_pos = options[i].second.size(); + next_pos = value.size(); } if (next_pos > pos) file_options.field_listener_options.forbidden_field_listener_events - .insert(options[i].second.substr(pos, next_pos - pos)); + .emplace(value.substr(pos, next_pos - pos)); pos = next_pos + 1; - } while (pos < options[i].second.size()); - } else if (options[i].first == "verified_lazy") { - file_options.unverified_lazy = false; - } else if (options[i].first == "unverified_lazy_message_sets") { + } while (pos < value.size()); + } else if (key == "unverified_lazy_message_sets") { file_options.unverified_lazy_message_sets = true; - } else if (options[i].first == "message_owned_arena_trial") { - file_options.message_owned_arena_trial = true; - } else if (options[i].first == "force_eagerly_verified_lazy") { + } else if (key == "force_eagerly_verified_lazy") { file_options.force_eagerly_verified_lazy = true; - } else if (options[i].first == "experimental_tail_call_table_mode") { - if (options[i].second == "never") { + } else if (key == "experimental_tail_call_table_mode") { + if (value == "never") { file_options.tctable_mode = Options::kTCTableNever; - } else if (options[i].second == "guarded") { + } else if (value == "guarded") { file_options.tctable_mode = Options::kTCTableGuarded; - } else if (options[i].second == "always") { + } else if (value == "always") { file_options.tctable_mode = Options::kTCTableAlways; } else { - *error = "Unknown value for experimental_tail_call_table_mode: " + - options[i].second; + *error = y_absl::StrCat( + "Unknown value for experimental_tail_call_table_mode: ", value); return false; } - } else if (options[i].first == "transitive_pb_h") { - file_options.transitive_pb_h = options[i].second != "false"; } else { - *error = "Unknown generator option: " + options[i].first; + *error = y_absl::StrCat("Unknown generator option: ", key); return false; } } @@ -176,6 +210,17 @@ bool CppGenerator::Generate(const FileDescriptor* file, TProtoStringType basename = StripProto(file->name()); + auto generate_reserved_static_reflection_header = [&basename, + &generator_context]() { + auto output = y_absl::WrapUnique(generator_context->Open( + y_absl::StrCat(basename, ".proto.static_reflection.h"))); + io::Printer(output.get()).Emit(R"cc( + // Reserved for future use. + )cc"); + }; + // Suppress maybe unused warning. + (void)generate_reserved_static_reflection_header; + if (MaybeBootstrap(file_options, generator_context, file_options.bootstrap, &basename)) { return true; @@ -185,58 +230,51 @@ bool CppGenerator::Generate(const FileDescriptor* file, // Generate header(s). if (file_options.proto_h) { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(basename + ".proto.h")); + auto output = y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(basename, ".proto.h"))); + GeneratedCodeInfo annotations; io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( &annotations); - TProtoStringType info_path = basename + ".proto.h.meta"; - io::Printer printer( - output.get(), '$', - file_options.annotate_headers ? &annotation_collector : nullptr); + io::Printer::Options options; + if (file_options.annotate_headers) { + options.annotation_collector = &annotation_collector; + } + + io::Printer p(output.get(), options); + auto v = p.WithVars(CommonVars(file_options)); + + TProtoStringType info_path = y_absl::StrCat(basename, ".proto.h.meta"); file_generator.GenerateProtoHeader( - &printer, file_options.annotate_headers ? info_path : ""); + &p, file_options.annotate_headers ? info_path : ""); + if (file_options.annotate_headers) { - std::unique_ptr<io::ZeroCopyOutputStream> info_output( - generator_context->Open(info_path)); + auto info_output = y_absl::WrapUnique(generator_context->Open(info_path)); annotations.SerializeToZeroCopyStream(info_output.get()); } } { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(basename + ".pb.h")); + auto output = y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(basename, ".pb.h"))); + GeneratedCodeInfo annotations; io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( &annotations); - TProtoStringType info_path = basename + ".pb.h.meta"; - io::Printer printer( - output.get(), '$', - file_options.annotate_headers ? &annotation_collector : nullptr); - file_generator.GeneratePBHeader( - &printer, file_options.annotate_headers ? info_path : ""); + io::Printer::Options options; if (file_options.annotate_headers) { - std::unique_ptr<io::ZeroCopyOutputStream> info_output( - generator_context->Open(info_path)); - annotations.SerializeToZeroCopyStream(info_output.get()); + options.annotation_collector = &annotation_collector; } - } - if (!file_options.transitive_pb_h) { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(basename + ".deps.pb.h")); - GeneratedCodeInfo annotations; - io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector( - &annotations); - TProtoStringType info_path = basename + ".deps.pb.h.meta"; - io::Printer printer( - output.get(), '$', - file_options.annotate_headers ? &annotation_collector : NULL); - file_generator.GeneratePBDeps( - &printer, file_options.annotate_headers ? info_path : ""); + io::Printer p(output.get(), options); + auto v = p.WithVars(CommonVars(file_options)); + + TProtoStringType info_path = y_absl::StrCat(basename, ".pb.h.meta"); + file_generator.GeneratePBHeader( + &p, file_options.annotate_headers ? info_path : ""); + if (file_options.annotate_headers) { - std::unique_ptr<io::ZeroCopyOutputStream> info_output( - generator_context->Open(info_path)); + auto info_output = y_absl::WrapUnique(generator_context->Open(info_path)); annotations.SerializeToZeroCopyStream(info_output.get()); } } @@ -246,10 +284,12 @@ bool CppGenerator::Generate(const FileDescriptor* file, { // This is the global .cc file, containing // enum/services/tables/reflection - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(basename + ".pb.cc")); - io::Printer printer(output.get(), '$'); - file_generator.GenerateGlobalSource(&printer); + auto output = y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(basename, ".pb.cc"))); + io::Printer p(output.get()); + auto v = p.WithVars(CommonVars(file_options)); + + file_generator.GenerateGlobalSource(&p); } int num_cc_files = @@ -260,40 +300,48 @@ bool CppGenerator::Generate(const FileDescriptor* file, // pb.cc file. If we have more files than messages, then some files will // be generated as empty placeholders. if (file_options.num_cc_files > 0) { - GOOGLE_CHECK_LE(num_cc_files, file_options.num_cc_files) + Y_ABSL_CHECK_LE(num_cc_files, file_options.num_cc_files) << "There must be at least as many numbered .cc files as messages " "and extensions."; num_cc_files = file_options.num_cc_files; } + int cc_file_number = 0; - for (int i = 0; i < file_generator.NumMessages(); i++) { - std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + for (int i = 0; i < file_generator.NumMessages(); ++i) { + auto output = y_absl::WrapUnique(generator_context->Open( NumberedCcFileName(basename, cc_file_number++))); - io::Printer printer(output.get(), '$'); - file_generator.GenerateSourceForMessage(i, &printer); + io::Printer p(output.get()); + auto v = p.WithVars(CommonVars(file_options)); + + file_generator.GenerateSourceForMessage(i, &p); } - for (int i = 0; i < file_generator.NumExtensions(); i++) { - std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + + for (int i = 0; i < file_generator.NumExtensions(); ++i) { + auto output = y_absl::WrapUnique(generator_context->Open( NumberedCcFileName(basename, cc_file_number++))); - io::Printer printer(output.get(), '$'); - file_generator.GenerateSourceForExtension(i, &printer); + io::Printer p(output.get()); + auto v = p.WithVars(CommonVars(file_options)); + + file_generator.GenerateSourceForExtension(i, &p); } + // Create empty placeholder files if necessary to match the expected number // of files. - for (; cc_file_number < num_cc_files; ++cc_file_number) { - std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( - NumberedCcFileName(basename, cc_file_number))); + while (cc_file_number < num_cc_files) { + (void)y_absl::WrapUnique(generator_context->Open( + NumberedCcFileName(basename, cc_file_number++))); } } else { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(basename + ".pb.cc")); - io::Printer printer(output.get(), '$'); - file_generator.GenerateSource(&printer); + auto output = y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(basename, ".pb.cc"))); + io::Printer p(output.get()); + auto v = p.WithVars(CommonVars(file_options)); + + file_generator.GenerateSource(&p); } return true; } - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.h index aa63845d300..5f95dd1d2f5 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.h @@ -38,24 +38,27 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ #include <string> -#include <google/protobuf/compiler/code_generator.h> +#include <utility> + +#include "google/protobuf/compiler/code_generator.h" // Must be included last. -#include <google/protobuf/port_def.inc> +#include "google/protobuf/port_def.inc" namespace google { namespace protobuf { namespace compiler { namespace cpp { - // CodeGenerator implementation which generates a C++ source file and // header. If you create your own protocol compiler binary and you want // it to support C++ output, you can do so by registering an instance of this // CodeGenerator with the CommandLineInterface in your main() function. class PROTOC_EXPORT CppGenerator : public CodeGenerator { public: - CppGenerator(); - ~CppGenerator() override; + CppGenerator() = default; + CppGenerator(const CppGenerator&) = delete; + CppGenerator& operator=(const CppGenerator&) = delete; + ~CppGenerator() override = default; enum class Runtime { kGoogle3, // Use the internal google3 runtime. @@ -74,34 +77,29 @@ class PROTOC_EXPORT CppGenerator : public CodeGenerator { // If set to a non-empty string, generated code will do: // #include "<BASE>/google/protobuf/message.h" // instead of: - // #include <google/protobuf/message.h> + // #include "google/protobuf/message.h" // This has no effect if opensource_runtime = false. - void set_runtime_include_base(const TProtoStringType& base) { - runtime_include_base_ = base; + void set_runtime_include_base(TProtoStringType base) { + runtime_include_base_ = std::move(base); } - // implements CodeGenerator ---------------------------------------- bool Generate(const FileDescriptor* file, const TProtoStringType& parameter, GeneratorContext* generator_context, TProtoStringType* error) const override; uint64_t GetSupportedFeatures() const override { - // We don't fully support this yet, but this is needed to unblock the tests, - // and we will have full support before the experimental flag is removed. return FEATURE_PROTO3_OPTIONAL; } private: - bool opensource_runtime_ = true; + bool opensource_runtime_ = PROTO2_IS_OSS; TProtoStringType runtime_include_base_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator); }; - } // namespace cpp } // namespace compiler } // namespace protobuf } // namespace google -#include <google/protobuf/port_undef.inc> +#include "google/protobuf/port_undef.inc" #endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.cc index 48879f29d57..977aa87d85e 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.cc @@ -32,35 +32,45 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/helpers.h> +#include "google/protobuf/compiler/cpp/helpers.h" +#include <algorithm> #include <cstdint> #include <functional> #include <limits> -#include <map> #include <memory> #include <queue> -#include <unordered_set> +#include <string> +#include <utility> #include <vector> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/names.h> -#include <google/protobuf/compiler/cpp/options.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/compiler/scc.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/wire_format_lite.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/substitute.h> -#include <google/protobuf/stubs/hash.h> +#include "google/protobuf/stubs/common.h" +#include "google/protobuf/compiler/scc.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/log/absl_log.h" +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/escaping.h" +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/str_replace.h" +#include "y_absl/strings/string_view.h" +#include "y_absl/strings/strip.h" +#include "y_absl/strings/substitute.h" +#include "y_absl/synchronization/mutex.h" +#include "google/protobuf/compiler/cpp/names.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/io/strtod.h" +#include "google/protobuf/wire_format.h" +#include "google/protobuf/wire_format_lite.h" + // Must be last. -#include <google/protobuf/port_def.inc> +#include "google/protobuf/port_def.inc" namespace google { namespace protobuf { @@ -72,11 +82,12 @@ namespace { static const char kAnyMessageName[] = "Any"; static const char kAnyProtoFile[] = "google/protobuf/any.proto"; -TProtoStringType DotsToColons(const TProtoStringType& name) { - return StringReplace(name, ".", "::", true); +TProtoStringType DotsToColons(y_absl::string_view name) { + return y_absl::StrReplaceAll(name, {{".", "::"}}); } -static const char* const kKeywordList[] = { // +static const char* const kKeywordList[] = { + // "NULL", "alignas", "alignof", @@ -163,48 +174,36 @@ static const char* const kKeywordList[] = { // "wchar_t", "while", "xor", - "xor_eq"}; - -static std::unordered_set<TProtoStringType>* MakeKeywordsMap() { - auto* result = new std::unordered_set<TProtoStringType>(); - for (const auto keyword : kKeywordList) { - result->emplace(keyword); - } - return result; -} - -static std::unordered_set<TProtoStringType>& kKeywords = *MakeKeywordsMap(); + "xor_eq", + "char8_t", + "char16_t", + "char32_t", + "concept", + "consteval", + "constinit", + "co_await", + "co_return", + "co_yield", + "requires", +}; -TProtoStringType IntTypeName(const Options& options, const TProtoStringType& type) { - return "::NProtoBuf::" + type; -} +const y_absl::flat_hash_set<y_absl::string_view>& Keywords() { + static const auto* keywords = [] { + auto* keywords = new y_absl::flat_hash_set<y_absl::string_view>(); -void SetIntVar(const Options& options, const TProtoStringType& type, - std::map<TProtoStringType, TProtoStringType>* variables) { - (*variables)[type] = IntTypeName(options, type); + for (const auto keyword : kKeywordList) { + keywords->emplace(keyword); + } + return keywords; + }(); + return *keywords; } -// Returns true if the message can potentially allocate memory for its field. -// This is used to determine if message-owned arena will be useful. -bool AllocExpected(const Descriptor* descriptor) { - return false; +TProtoStringType IntTypeName(const Options& options, y_absl::string_view type) { + return y_absl::StrCat("::NProtoBuf::", type); } -// Describes different approaches to detect non-canonical int32 encoding. Only -// kNever or kAlways is eligible for *simple* verification methods. -enum class VerifyInt32Type { - kCustom, // Only check if field number matches. - kNever, // Do not check. - kAlways, // Always check. -}; -inline VerifySimpleType VerifyInt32TypeToVerifyCustom(VerifyInt32Type t) { - static VerifySimpleType kCustomTypes[] = { - VerifySimpleType::kCustom, VerifySimpleType::kCustomInt32Never, - VerifySimpleType::kCustomInt32Always}; - return kCustomTypes[static_cast<arc_i32>(t) - - static_cast<arc_i32>(VerifyInt32Type::kCustom)]; -} } // namespace @@ -232,86 +231,69 @@ bool IsLazilyVerifiedLazy(const FieldDescriptor* field, return false; } -void SetCommonVars(const Options& options, - std::map<TProtoStringType, TProtoStringType>* variables) { - (*variables)["proto_ns"] = ProtobufNamespace(options); - - // Warning: there is some clever naming/splitting here to avoid extract script - // rewrites. The names of these variables must not be things that the extract - // script will rewrite. That's why we use "CHK" (for example) instead of - // "GOOGLE_CHECK". - if (options.opensource_runtime) { - (*variables)["GOOGLE_PROTOBUF"] = "GOOGLE_PROTOBUF"; - (*variables)["CHK"] = "GOOGLE_CHECK"; - (*variables)["DCHK"] = "GOOGLE_DCHECK"; - } else { - // These values are things the extract script would rewrite if we did not - // split them. It might not strictly matter since we don't generate google3 - // code in open-source. But it's good to prevent surprising things from - // happening. - (*variables)["GOOGLE_PROTOBUF"] = - "GOOGLE3" - "_PROTOBUF"; - (*variables)["CHK"] = - "CH" - "ECK"; - (*variables)["DCHK"] = - "DCH" - "ECK"; - } - - SetIntVar(options, "int8", variables); - SetIntVar(options, "uint8", variables); - SetIntVar(options, "uint32", variables); - SetIntVar(options, "uint64", variables); - SetIntVar(options, "int32", variables); - SetIntVar(options, "int64", variables); - (*variables)["string"] = "TProtoStringType"; +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> MessageVars( + const Descriptor* desc) { + y_absl::string_view prefix = IsMapEntryMessage(desc) ? "" : "_impl_."; + return { + {"any_metadata", y_absl::StrCat(prefix, "_any_metadata_")}, + {"cached_size", y_absl::StrCat(prefix, "_cached_size_")}, + {"extensions", y_absl::StrCat(prefix, "_extensions_")}, + {"has_bits", y_absl::StrCat(prefix, "_has_bits_")}, + {"inlined_string_donated_array", + y_absl::StrCat(prefix, "_inlined_string_donated_")}, + {"oneof_case", y_absl::StrCat(prefix, "_oneof_case_")}, + {"tracker", "Impl_::_tracker_"}, + {"weak_field_map", y_absl::StrCat(prefix, "_weak_field_map_")}, + {"split", y_absl::StrCat(prefix, "_split_")}, + {"cached_split_ptr", "cached_split_ptr"}, + }; } void SetCommonMessageDataVariables( const Descriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables) { - TProtoStringType prefix = IsMapEntryMessage(descriptor) ? "" : "_impl_."; - (*variables)["any_metadata"] = prefix + "_any_metadata_"; - (*variables)["cached_size"] = prefix + "_cached_size_"; - (*variables)["extensions"] = prefix + "_extensions_"; - (*variables)["has_bits"] = prefix + "_has_bits_"; - (*variables)["inlined_string_donated_array"] = - prefix + "_inlined_string_donated_"; - (*variables)["oneof_case"] = prefix + "_oneof_case_"; - (*variables)["tracker"] = "Impl_::_tracker_"; - (*variables)["weak_field_map"] = prefix + "_weak_field_map_"; - (*variables)["split"] = prefix + "_split_"; - (*variables)["cached_split_ptr"] = "cached_split_ptr"; -} - -void SetUnknownFieldsVariable(const Descriptor* descriptor, - const Options& options, - std::map<TProtoStringType, TProtoStringType>* variables) { - TProtoStringType proto_ns = ProtobufNamespace(options); + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables) { + for (auto& pair : MessageVars(descriptor)) { + variables->emplace(pair); + } +} + +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> UnknownFieldsVars( + const Descriptor* desc, const Options& opts) { + TProtoStringType proto_ns = ProtobufNamespace(opts); + TProtoStringType unknown_fields_type; - if (UseUnknownFieldSet(descriptor->file(), options)) { - unknown_fields_type = "::" + proto_ns + "::UnknownFieldSet"; - (*variables)["unknown_fields"] = - "_internal_metadata_.unknown_fields<" + unknown_fields_type + ">(" + - unknown_fields_type + "::default_instance)"; + TProtoStringType default_instance; + if (UseUnknownFieldSet(desc->file(), opts)) { + unknown_fields_type = y_absl::StrCat("::", proto_ns, "::UnknownFieldSet"); + default_instance = y_absl::StrCat(unknown_fields_type, "::default_instance"); } else { unknown_fields_type = - PrimitiveTypeName(options, FieldDescriptor::CPPTYPE_STRING); - (*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields<" + - unknown_fields_type + ">(::" + proto_ns + - "::internal::GetEmptyString)"; + PrimitiveTypeName(opts, FieldDescriptor::CPPTYPE_STRING); + default_instance = + y_absl::StrCat("::", proto_ns, "::internal::GetEmptyString"); + } + + return { + {"unknown_fields", + y_absl::Substitute("_internal_metadata_.unknown_fields<$0>($1)", + unknown_fields_type, default_instance)}, + {"unknown_fields_type", unknown_fields_type}, + {"have_unknown_fields", "_internal_metadata_.have_unknown_fields()"}, + {"mutable_unknown_fields", + y_absl::Substitute("_internal_metadata_.mutable_unknown_fields<$0>()", + unknown_fields_type)}, + }; +} + +void SetUnknownFieldsVariable( + const Descriptor* descriptor, const Options& options, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables) { + for (auto& pair : UnknownFieldsVars(descriptor, options)) { + variables->emplace(pair); } - (*variables)["unknown_fields_type"] = unknown_fields_type; - (*variables)["have_unknown_fields"] = - "_internal_metadata_.have_unknown_fields()"; - (*variables)["mutable_unknown_fields"] = - "_internal_metadata_.mutable_unknown_fields<" + unknown_fields_type + - ">()"; } -TProtoStringType UnderscoresToCamelCase(const TProtoStringType& input, +TProtoStringType UnderscoresToCamelCase(y_absl::string_view input, bool cap_next_letter) { TProtoStringType result; // Note: I distrust ctype.h due to locales. @@ -342,7 +324,9 @@ const char kThickSeparator[] = const char kThinSeparator[] = "// -------------------------------------------------------------------\n"; -bool CanInitializeByZeroing(const FieldDescriptor* field) { +bool CanInitializeByZeroing(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) { if (field->is_repeated() || field->is_extension()) return false; switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_ENUM: @@ -361,6 +345,57 @@ bool CanInitializeByZeroing(const FieldDescriptor* field) { return field->default_value_double() == 0; case FieldDescriptor::CPPTYPE_BOOL: return field->default_value_bool() == false; + case FieldDescriptor::CPPTYPE_MESSAGE: + // Non-repeated, non-lazy message fields are raw pointers initialized to + // null. + return !IsLazy(field, options, scc_analyzer); + default: + return false; + } +} + +bool CanClearByZeroing(const FieldDescriptor* field) { + if (field->is_repeated() || field->is_extension()) return false; + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + return field->default_value_enum()->number() == 0; + case FieldDescriptor::CPPTYPE_INT32: + return field->default_value_int32() == 0; + case FieldDescriptor::CPPTYPE_INT64: + return field->default_value_int64() == 0; + case FieldDescriptor::CPPTYPE_UINT32: + return field->default_value_uint32() == 0; + case FieldDescriptor::CPPTYPE_UINT64: + return field->default_value_uint64() == 0; + case FieldDescriptor::CPPTYPE_FLOAT: + return field->default_value_float() == 0; + case FieldDescriptor::CPPTYPE_DOUBLE: + return field->default_value_double() == 0; + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() == false; + default: + return false; + } +} + +// Determines if swap can be implemented via memcpy. +bool HasTrivialSwap(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + if (field->is_repeated() || field->is_extension()) return false; + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_BOOL: + return true; + case FieldDescriptor::CPPTYPE_MESSAGE: + // Non-repeated, non-lazy message fields are simply raw pointers, so we + // can swap them with memcpy. + return !IsLazy(field, options, scc_analyzer); default: return false; } @@ -369,9 +404,9 @@ bool CanInitializeByZeroing(const FieldDescriptor* field) { TProtoStringType ClassName(const Descriptor* descriptor) { const Descriptor* parent = descriptor->containing_type(); TProtoStringType res; - if (parent) res += ClassName(parent) + "_"; - res += descriptor->name(); - if (IsMapEntryMessage(descriptor)) res += "_DoNotUse"; + if (parent) y_absl::StrAppend(&res, ClassName(parent), "_"); + y_absl::StrAppend(&res, descriptor->name()); + if (IsMapEntryMessage(descriptor)) y_absl::StrAppend(&res, "_DoNotUse"); return ResolveKeyword(res); } @@ -379,8 +414,8 @@ TProtoStringType ClassName(const EnumDescriptor* enum_descriptor) { if (enum_descriptor->containing_type() == nullptr) { return ResolveKeyword(enum_descriptor->name()); } else { - return ClassName(enum_descriptor->containing_type()) + "_" + - enum_descriptor->name(); + return y_absl::StrCat(ClassName(enum_descriptor->containing_type()), "_", + enum_descriptor->name()); } } @@ -403,13 +438,13 @@ TProtoStringType QualifiedClassName(const EnumDescriptor* d) { TProtoStringType ExtensionName(const FieldDescriptor* d) { if (const Descriptor* scope = d->extension_scope()) - return StrCat(ClassName(scope), "::", ResolveKeyword(d->name())); + return y_absl::StrCat(ClassName(scope), "::", ResolveKeyword(d->name())); return ResolveKeyword(d->name()); } TProtoStringType QualifiedExtensionName(const FieldDescriptor* d, const Options& options) { - GOOGLE_DCHECK(d->is_extension()); + Y_ABSL_DCHECK(d->is_extension()); return QualifiedFileLevelSymbol(d->file(), ExtensionName(d), options); } @@ -417,32 +452,38 @@ TProtoStringType QualifiedExtensionName(const FieldDescriptor* d) { return QualifiedExtensionName(d, Options()); } -TProtoStringType Namespace(const TProtoStringType& package) { +TProtoStringType Namespace(y_absl::string_view package) { if (package.empty()) return ""; - return "::" + DotsToColons(package); + return y_absl::StrCat("::", DotsToColons(package)); } +TProtoStringType Namespace(const FileDescriptor* d) { return Namespace(d, {}); } TProtoStringType Namespace(const FileDescriptor* d, const Options& options) { - TProtoStringType ret = Namespace(d->package()); + TProtoStringType ns = Namespace(d->package()); if (IsWellKnownMessage(d) && options.opensource_runtime) { // Written with string concatenation to prevent rewriting of // ::google::protobuf. - ret = StringReplace(ret, - "::google::" - "protobuf", - "::PROTOBUF_NAMESPACE_ID", false); + constexpr y_absl::string_view prefix = + "::google::" // prevent clang-format reflowing + "protobuf"; + y_absl::string_view new_ns(ns); + y_absl::ConsumePrefix(&new_ns, prefix); + return y_absl::StrCat("::PROTOBUF_NAMESPACE_ID", new_ns); } - return ret; + return ns; } +TProtoStringType Namespace(const Descriptor* d) { return Namespace(d, {}); } TProtoStringType Namespace(const Descriptor* d, const Options& options) { return Namespace(d->file(), options); } +TProtoStringType Namespace(const FieldDescriptor* d) { return Namespace(d, {}); } TProtoStringType Namespace(const FieldDescriptor* d, const Options& options) { return Namespace(d->file(), options); } +TProtoStringType Namespace(const EnumDescriptor* d) { return Namespace(d, {}); } TProtoStringType Namespace(const EnumDescriptor* d, const Options& options) { return Namespace(d->file(), options); } @@ -455,13 +496,13 @@ TProtoStringType DefaultInstanceType(const Descriptor* descriptor, TProtoStringType DefaultInstanceName(const Descriptor* descriptor, const Options& /*options*/, bool split) { - return "_" + ClassName(descriptor, false) + (split ? "__Impl_Split" : "") + - "_default_instance_"; + return y_absl::StrCat("_", ClassName(descriptor, false), + (split ? "__Impl_Split" : ""), "_default_instance_"); } TProtoStringType DefaultInstancePtr(const Descriptor* descriptor, const Options& options, bool split) { - return DefaultInstanceName(descriptor, options, split) + "ptr_"; + return y_absl::StrCat(DefaultInstanceName(descriptor, options, split), "ptr_"); } TProtoStringType QualifiedDefaultInstanceName(const Descriptor* descriptor, @@ -473,7 +514,8 @@ TProtoStringType QualifiedDefaultInstanceName(const Descriptor* descriptor, TProtoStringType QualifiedDefaultInstancePtr(const Descriptor* descriptor, const Options& options, bool split) { - return QualifiedDefaultInstanceName(descriptor, options, split) + "ptr_"; + return y_absl::StrCat(QualifiedDefaultInstanceName(descriptor, options, split), + "ptr_"); } TProtoStringType DescriptorTableName(const FileDescriptor* file, @@ -488,60 +530,61 @@ TProtoStringType FileDllExport(const FileDescriptor* file, const Options& option TProtoStringType SuperClassName(const Descriptor* descriptor, const Options& options) { if (!HasDescriptorMethods(descriptor->file(), options)) { - return "::" + ProtobufNamespace(options) + "::MessageLite"; + return y_absl::StrCat("::", ProtobufNamespace(options), "::MessageLite"); } auto simple_base = SimpleBaseClass(descriptor, options); if (simple_base.empty()) { - return "::" + ProtobufNamespace(options) + "::Message"; + return y_absl::StrCat("::", ProtobufNamespace(options), "::Message"); } - return "::" + ProtobufNamespace(options) + "::internal::" + simple_base; + return y_absl::StrCat("::", ProtobufNamespace(options), + "::internal::", simple_base); } -TProtoStringType ResolveKeyword(const TProtoStringType& name) { - if (kKeywords.count(name) > 0) { - return name + "_"; +TProtoStringType ResolveKeyword(y_absl::string_view name) { + if (Keywords().count(name) > 0) { + return y_absl::StrCat(name, "_"); } - return name; + return TProtoStringType(name); } TProtoStringType FieldName(const FieldDescriptor* field) { TProtoStringType result = field->name(); - LowerString(&result); - if (kKeywords.count(result) > 0) { + y_absl::AsciiStrToLower(&result); + if (Keywords().count(result) > 0) { result.append("_"); } return result; } TProtoStringType FieldMemberName(const FieldDescriptor* field, bool split) { - StringPiece prefix = + y_absl::string_view prefix = IsMapEntryMessage(field->containing_type()) ? "" : "_impl_."; - StringPiece split_prefix = split ? "_split_->" : ""; + y_absl::string_view split_prefix = split ? "_split_->" : ""; if (field->real_containing_oneof() == nullptr) { - return StrCat(prefix, split_prefix, FieldName(field), "_"); + return y_absl::StrCat(prefix, split_prefix, FieldName(field), "_"); } // Oneof fields are never split. - GOOGLE_CHECK(!split); - return StrCat(prefix, field->containing_oneof()->name(), "_.", + Y_ABSL_CHECK(!split); + return y_absl::StrCat(prefix, field->containing_oneof()->name(), "_.", FieldName(field), "_"); } TProtoStringType OneofCaseConstantName(const FieldDescriptor* field) { - GOOGLE_DCHECK(field->containing_oneof()); + Y_ABSL_DCHECK(field->containing_oneof()); TProtoStringType field_name = UnderscoresToCamelCase(field->name(), true); - return "k" + field_name; + return y_absl::StrCat("k", field_name); } TProtoStringType QualifiedOneofCaseConstantName(const FieldDescriptor* field) { - GOOGLE_DCHECK(field->containing_oneof()); + Y_ABSL_DCHECK(field->containing_oneof()); const TProtoStringType qualification = QualifiedClassName(field->containing_type()); - return StrCat(qualification, "::", OneofCaseConstantName(field)); + return y_absl::StrCat(qualification, "::", OneofCaseConstantName(field)); } TProtoStringType EnumValueName(const EnumValueDescriptor* enum_value) { TProtoStringType result = enum_value->name(); - if (kKeywords.count(result) > 0) { + if (Keywords().count(result) > 0) { result.append("_"); } return result; @@ -567,13 +610,13 @@ int EstimateAlignmentSize(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_MESSAGE: return 8; } - GOOGLE_LOG(FATAL) << "Can't get here."; + Y_ABSL_LOG(FATAL) << "Can't get here."; return -1; // Make compiler happy. } TProtoStringType FieldConstantName(const FieldDescriptor* field) { TProtoStringType field_name = UnderscoresToCamelCase(field->name(), true); - TProtoStringType result = "k" + field_name + "FieldNumber"; + TProtoStringType result = y_absl::StrCat("k", field_name, "FieldNumber"); if (!field->is_extension() && field->containing_type()->FindFieldByCamelcaseName( @@ -581,7 +624,7 @@ TProtoStringType FieldConstantName(const FieldDescriptor* field) { // This field's camelcase name is not unique. As a hack, add the field // number to the constant name. This makes the constant rather useless, // but what can we do? - result += "_" + StrCat(field->number()); + y_absl::StrAppend(&result, "_", field->number()); } return result; @@ -594,7 +637,7 @@ TProtoStringType FieldMessageTypeName(const FieldDescriptor* field, return QualifiedClassName(field->message_type(), options); } -TProtoStringType StripProto(const TProtoStringType& filename) { +TProtoStringType StripProto(y_absl::string_view filename) { /* * TODO(github/georgthegreat) remove this proxy method * once Google's internal codebase will become ready @@ -605,13 +648,13 @@ TProtoStringType StripProto(const TProtoStringType& filename) { const char* PrimitiveTypeName(FieldDescriptor::CppType type) { switch (type) { case FieldDescriptor::CPPTYPE_INT32: - return "arc_i32"; + return "::arc_i32"; case FieldDescriptor::CPPTYPE_INT64: - return "arc_i64"; + return "::arc_i64"; case FieldDescriptor::CPPTYPE_UINT32: - return "arc_ui32"; + return "::arc_ui32"; case FieldDescriptor::CPPTYPE_UINT64: - return "arc_ui64"; + return "::arc_ui64"; case FieldDescriptor::CPPTYPE_DOUBLE: return "double"; case FieldDescriptor::CPPTYPE_FLOAT: @@ -629,7 +672,7 @@ const char* PrimitiveTypeName(FieldDescriptor::CppType type) { // CppTypes are added. } - GOOGLE_LOG(FATAL) << "Can't get here."; + Y_ABSL_LOG(FATAL) << "Can't get here."; return nullptr; } @@ -661,7 +704,7 @@ TProtoStringType PrimitiveTypeName(const Options& options, // CppTypes are added. } - GOOGLE_LOG(FATAL) << "Can't get here."; + Y_ABSL_LOG(FATAL) << "Can't get here."; return ""; } @@ -709,7 +752,7 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { // No default because we want the compiler to complain if any new // types are added. } - GOOGLE_LOG(FATAL) << "Can't get here."; + Y_ABSL_LOG(FATAL) << "Can't get here."; return ""; } @@ -717,9 +760,9 @@ TProtoStringType Int32ToString(int number) { if (number == std::numeric_limits<arc_i32>::min()) { // This needs to be special-cased, see explanation here: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661 - return StrCat(number + 1, " - 1"); + return y_absl::StrCat(number + 1, " - 1"); } else { - return StrCat(number); + return y_absl::StrCat(number); } } @@ -727,13 +770,13 @@ static TProtoStringType Int64ToString(arc_i64 number) { if (number == std::numeric_limits<arc_i64>::min()) { // This needs to be special-cased, see explanation here: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661 - return StrCat("arc_i64{", number + 1, "} - 1"); + return y_absl::StrCat("::arc_i64{", number + 1, "} - 1"); } - return StrCat("arc_i64{", number, "}"); + return y_absl::StrCat("::arc_i64{", number, "}"); } static TProtoStringType UInt64ToString(arc_ui64 number) { - return StrCat("arc_ui64{", number, "u}"); + return y_absl::StrCat("::arc_ui64{", number, "u}"); } TProtoStringType DefaultValue(const FieldDescriptor* field) { @@ -745,7 +788,7 @@ TProtoStringType DefaultValue(const Options& options, const FieldDescriptor* fie case FieldDescriptor::CPPTYPE_INT32: return Int32ToString(field->default_value_int32()); case FieldDescriptor::CPPTYPE_UINT32: - return StrCat(field->default_value_uint32()) + "u"; + return y_absl::StrCat(field->default_value_uint32(), "u"); case FieldDescriptor::CPPTYPE_INT64: return Int64ToString(field->default_value_int64()); case FieldDescriptor::CPPTYPE_UINT64: @@ -759,7 +802,7 @@ TProtoStringType DefaultValue(const Options& options, const FieldDescriptor* fie } else if (value != value) { return "std::numeric_limits<double>::quiet_NaN()"; } else { - return SimpleDtoa(value); + return io::SimpleDtoa(value); } } case FieldDescriptor::CPPTYPE_FLOAT: { @@ -771,7 +814,7 @@ TProtoStringType DefaultValue(const Options& options, const FieldDescriptor* fie } else if (value != value) { return "std::numeric_limits<float>::quiet_NaN()"; } else { - TProtoStringType float_value = SimpleFtoa(value); + TProtoStringType float_value = io::SimpleFtoa(value); // If floating point value contains a period (.) or an exponent // (either E or e), then append suffix 'f' to make it a float // literal. @@ -786,73 +829,73 @@ TProtoStringType DefaultValue(const Options& options, const FieldDescriptor* fie case FieldDescriptor::CPPTYPE_ENUM: // Lazy: Generate a static_cast because we don't have a helper function // that constructs the full name of an enum value. - return strings::Substitute( + return y_absl::Substitute( "static_cast< $0 >($1)", ClassName(field->enum_type(), true), Int32ToString(field->default_value_enum()->number())); case FieldDescriptor::CPPTYPE_STRING: - return "\"" + - EscapeTrigraphs(CEscape(field->default_value_string())) + - "\""; + return y_absl::StrCat( + "\"", EscapeTrigraphs(y_absl::CEscape(field->default_value_string())), + "\""); case FieldDescriptor::CPPTYPE_MESSAGE: - return "*" + FieldMessageTypeName(field, options) + - "::internal_default_instance()"; + return y_absl::StrCat("*", FieldMessageTypeName(field, options), + "::internal_default_instance()"); } // Can't actually get here; make compiler happy. (We could add a default // case above but then we wouldn't get the nice compiler warning when a // new type is added.) - GOOGLE_LOG(FATAL) << "Can't get here."; + Y_ABSL_LOG(FATAL) << "Can't get here."; return ""; } // Convert a file name into a valid identifier. -TProtoStringType FilenameIdentifier(const TProtoStringType& filename) { +TProtoStringType FilenameIdentifier(y_absl::string_view filename) { TProtoStringType result; for (int i = 0; i < filename.size(); i++) { - if (ascii_isalnum(filename[i])) { + if (y_absl::ascii_isalnum(filename[i])) { result.push_back(filename[i]); } else { // Not alphanumeric. To avoid any possibility of name conflicts we // use the hex code for the character. - StrAppend(&result, "_", - strings::Hex(static_cast<uint8_t>(filename[i]))); + y_absl::StrAppend(&result, "_", + y_absl::Hex(static_cast<uint8_t>(filename[i]))); } } return result; } -TProtoStringType UniqueName(const TProtoStringType& name, const TProtoStringType& filename, +TProtoStringType UniqueName(y_absl::string_view name, y_absl::string_view filename, const Options& options) { - return name + "_" + FilenameIdentifier(filename); + return y_absl::StrCat(name, "_", FilenameIdentifier(filename)); } // Return the qualified C++ name for a file level symbol. TProtoStringType QualifiedFileLevelSymbol(const FileDescriptor* file, - const TProtoStringType& name, + y_absl::string_view name, const Options& options) { if (file->package().empty()) { - return StrCat("::", name); + return y_absl::StrCat("::", name); } - return StrCat(Namespace(file, options), "::", name); + return y_absl::StrCat(Namespace(file, options), "::", name); } // Escape C++ trigraphs by escaping question marks to \? -TProtoStringType EscapeTrigraphs(const TProtoStringType& to_escape) { - return StringReplace(to_escape, "?", "\\?", true); +TProtoStringType EscapeTrigraphs(y_absl::string_view to_escape) { + return y_absl::StrReplaceAll(to_escape, {{"?", "\\?"}}); } // Escaped function name to eliminate naming conflict. TProtoStringType SafeFunctionName(const Descriptor* descriptor, const FieldDescriptor* field, - const TProtoStringType& prefix) { + y_absl::string_view prefix) { // Do not use FieldName() since it will escape keywords. TProtoStringType name = field->name(); - LowerString(&name); - TProtoStringType function_name = prefix + name; + y_absl::AsciiStrToLower(&name); + TProtoStringType function_name = y_absl::StrCat(prefix, name); if (descriptor->FindFieldByName(function_name)) { // Single underscore will also make it conflicting with the private data // member. We use double underscore to escape function names. function_name.append("__"); - } else if (kKeywords.count(name) > 0) { + } else if (Keywords().count(name) > 0) { // If the field name is a keyword, we append the underscore back to keep it // consistent with other function names. function_name.append("_"); @@ -860,6 +903,9 @@ TProtoStringType SafeFunctionName(const Descriptor* descriptor, return function_name; } +bool IsProfileDriven(const Options& options) { + return options.access_info_map != nullptr; +} bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options) { (void)descriptor; @@ -907,6 +953,13 @@ bool HasLazyFields(const FileDescriptor* file, const Options& options, bool ShouldSplit(const Descriptor*, const Options&) { return false; } bool ShouldSplit(const FieldDescriptor*, const Options&) { return false; } +bool ShouldForceAllocationOnConstruction(const Descriptor* desc, + const Options& options) { + (void)desc; + (void)options; + return false; +} + static bool HasRepeatedFields(const Descriptor* descriptor) { for (int i = 0; i < descriptor->field_count(); ++i) { if (descriptor->field(i)->label() == FieldDescriptor::LABEL_REPEATED) { @@ -1045,7 +1098,7 @@ bool ShouldVerify(const FileDescriptor* file, const Options& options, bool IsUtf8String(const FieldDescriptor* field) { return IsProto3(field->file()) && - field->type() == FieldDescriptor::TYPE_STRING; + field->type() == FieldDescriptor::TYPE_STRING; } VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor) { @@ -1069,13 +1122,13 @@ bool IsStringOrMessage(const FieldDescriptor* field) { return true; } - GOOGLE_LOG(FATAL) << "Can't get here."; + Y_ABSL_LOG(FATAL) << "Can't get here."; return false; } FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field, const Options& options) { - GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); + Y_ABSL_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); if (options.opensource_runtime) { // Open-source protobuf release only supports STRING ctype. return FieldOptions::STRING; @@ -1095,7 +1148,7 @@ bool IsAnyMessage(const Descriptor* descriptor, const Options& options) { } bool IsWellKnownMessage(const FileDescriptor* file) { - static const std::unordered_set<TProtoStringType> well_known_files{ + static const auto* well_known_files = new y_absl::flat_hash_set<TProtoStringType>{ "google/protobuf/any.proto", "google/protobuf/api.proto", "google/protobuf/compiler/plugin.proto", @@ -1109,94 +1162,127 @@ bool IsWellKnownMessage(const FileDescriptor* file) { "google/protobuf/type.proto", "google/protobuf/wrappers.proto", }; - return well_known_files.find(file->name()) != well_known_files.end(); -} - -static bool FieldEnforceUtf8(const FieldDescriptor* field, - const Options& options) { - return true; + return well_known_files->find(file->name()) != well_known_files->end(); } -static bool FileUtf8Verification(const FileDescriptor* file, - const Options& options) { - return true; -} +void NamespaceOpener::ChangeTo(y_absl::string_view name) { + std::vector<TProtoStringType> new_stack = + y_absl::StrSplit(name, "::", y_absl::SkipEmpty()); + size_t len = std::min(name_stack_.size(), new_stack.size()); + size_t common_idx = 0; + while (common_idx < len) { + if (name_stack_[common_idx] != new_stack[common_idx]) { + break; + } + ++common_idx; + } -// Which level of UTF-8 enforcemant is placed on this file. -Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, - const Options& options) { - if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && - FieldEnforceUtf8(field, options)) { - return Utf8CheckMode::kStrict; - } else if (GetOptimizeFor(field->file(), options) != - FileOptions::LITE_RUNTIME && - FileUtf8Verification(field->file(), options)) { - return Utf8CheckMode::kVerify; - } else { - return Utf8CheckMode::kNone; + for (size_t i = name_stack_.size(); i > common_idx; i--) { + const auto& ns = name_stack_[i - 1]; + if (ns == "PROTOBUF_NAMESPACE_ID") { + p_->Emit(R"cc( + PROTOBUF_NAMESPACE_CLOSE + )cc"); + } else { + p_->Emit({{"ns", ns}}, R"( + } // namespace $ns$ + )"); + } + } + for (size_t i = common_idx; i < new_stack.size(); ++i) { + const auto& ns = new_stack[i]; + if (ns == "PROTOBUF_NAMESPACE_ID") { + p_->Emit(R"cc( + PROTOBUF_NAMESPACE_OPEN + )cc"); + } else { + p_->Emit({{"ns", ns}}, R"( + namespace $ns$ { + )"); + } } + + name_stack_ = std::move(new_stack); } -static void GenerateUtf8CheckCode(const FieldDescriptor* field, +static void GenerateUtf8CheckCode(io::Printer* p, const FieldDescriptor* field, const Options& options, bool for_parse, - const char* parameters, - const char* strict_function, - const char* verify_function, - const Formatter& format) { - switch (GetUtf8CheckMode(field, options)) { - case Utf8CheckMode::kStrict: { + y_absl::string_view params, + y_absl::string_view strict_function, + y_absl::string_view verify_function) { + if (field->type() != FieldDescriptor::TYPE_STRING) return; + + auto v = p->WithVars({ + {"params", params}, + {"Strict", strict_function}, + {"Verify", verify_function}, + }); + + bool is_lite = + GetOptimizeFor(field->file(), options) == FileOptions::LITE_RUNTIME; + switch (internal::cpp::GetUtf8CheckMode(field, is_lite)) { + case internal::cpp::Utf8CheckMode::kStrict: if (for_parse) { - format("DO_("); - } - format("::$proto_ns$::internal::WireFormatLite::$1$(\n", strict_function); - format.Indent(); - format(parameters); - if (for_parse) { - format("::$proto_ns$::internal::WireFormatLite::PARSE,\n"); + p->Emit(R"cc( + DO_($pbi$::WireFormatLite::$Strict$( + $params$ $pbi$::WireFormatLite::PARSE, "$pkg.Msg.field$")); + )cc"); } else { - format("::$proto_ns$::internal::WireFormatLite::SERIALIZE,\n"); + p->Emit(R"cc( + $pbi$::WireFormatLite::$Strict$( + $params$ $pbi$::WireFormatLite::SERIALIZE, "$pkg.Msg.field$"); + )cc"); } - format("\"$1$\")", field->full_name()); - if (for_parse) { - format(")"); - } - format(";\n"); - format.Outdent(); break; - } - case Utf8CheckMode::kVerify: { - format("::$proto_ns$::internal::WireFormat::$1$(\n", verify_function); - format.Indent(); - format(parameters); + + case internal::cpp::Utf8CheckMode::kVerify: if (for_parse) { - format("::$proto_ns$::internal::WireFormat::PARSE,\n"); + p->Emit(R"cc( + $pbi$::WireFormat::$Verify$($params$ $pbi$::WireFormat::PARSE, + "$pkg.Msg.field$"); + )cc"); } else { - format("::$proto_ns$::internal::WireFormat::SERIALIZE,\n"); + p->Emit(R"cc( + $pbi$::WireFormat::$Verify$($params$ $pbi$::WireFormat::SERIALIZE, + "$pkg.Msg.field$"); + )cc"); } - format("\"$1$\");\n", field->full_name()); - format.Outdent(); break; - } - case Utf8CheckMode::kNone: + + case internal::cpp::Utf8CheckMode::kNone: break; } } void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, const Options& options, bool for_parse, - const char* parameters, + y_absl::string_view parameters, const Formatter& format) { - GenerateUtf8CheckCode(field, options, for_parse, parameters, - "VerifyUtf8String", "VerifyUTF8StringNamedField", - format); + GenerateUtf8CheckCode(format.printer(), field, options, for_parse, parameters, + "VerifyUtf8String", "VerifyUTF8StringNamedField"); } void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, const Options& options, bool for_parse, - const char* parameters, + y_absl::string_view parameters, const Formatter& format) { - GenerateUtf8CheckCode(field, options, for_parse, parameters, "VerifyUtf8Cord", - "VerifyUTF8CordNamedField", format); + GenerateUtf8CheckCode(format.printer(), field, options, for_parse, parameters, + "VerifyUtf8Cord", "VerifyUTF8CordNamedField"); +} + +void GenerateUtf8CheckCodeForString(io::Printer* p, + const FieldDescriptor* field, + const Options& options, bool for_parse, + y_absl::string_view parameters) { + GenerateUtf8CheckCode(p, field, options, for_parse, parameters, + "VerifyUtf8String", "VerifyUTF8StringNamedField"); +} + +void GenerateUtf8CheckCodeForCord(io::Printer* p, const FieldDescriptor* field, + const Options& options, bool for_parse, + y_absl::string_view parameters) { + GenerateUtf8CheckCode(p, field, options, for_parse, parameters, + "VerifyUtf8Cord", "VerifyUTF8CordNamedField"); } void FlattenMessagesInFile(const FileDescriptor* file, @@ -1243,7 +1329,9 @@ bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, } MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) { - if (analysis_cache_.count(scc)) return analysis_cache_[scc]; + auto it = analysis_cache_.find(scc); + if (it != analysis_cache_.end()) return it->second; + MessageAnalysis result; if (UsingImplicitWeakFields(scc->GetFile(), options_)) { result.contains_weak = true; @@ -1298,7 +1386,7 @@ MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) { // in the graph, the graph should be a DAG. Hence we shouldn't need to mark // nodes visited as we can never return to them. By inserting them here // we will go in an infinite loop if the SCC is not correct. - return analysis_cache_[scc] = result; + return analysis_cache_[scc] = std::move(result); } void ListAllFields(const Descriptor* d, @@ -1341,23 +1429,26 @@ void ListAllTypesForServices(const FileDescriptor* fd, } } -bool GetBootstrapBasename(const Options& options, const TProtoStringType& basename, +bool GetBootstrapBasename(const Options& options, y_absl::string_view basename, TProtoStringType* bootstrap_basename) { if (options.opensource_runtime) { return false; } - std::unordered_map<TProtoStringType, TProtoStringType> bootstrap_mapping{ - {"net/proto2/proto/descriptor", - "third_party/protobuf/descriptor"}, - {"net/proto2/compiler/proto/plugin", - "net/proto2/compiler/proto/plugin"}, - {"net/proto2/compiler/proto/profile", - "net/proto2/compiler/proto/profile_bootstrap"}, - }; - auto iter = bootstrap_mapping.find(basename); - if (iter == bootstrap_mapping.end()) { - *bootstrap_basename = basename; + static const auto* bootstrap_mapping = + // TODO(b/242858704) Replace these with string_view once we remove + // StringPiece. + new y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>{ + {"net/proto2/proto/descriptor", + "third_party/protobuf/descriptor"}, + {"net/proto2/compiler/proto/plugin", + "net/proto2/compiler/proto/plugin"}, + {"net/proto2/compiler/proto/profile", + "net/proto2/compiler/proto/profile_bootstrap"}, + }; + auto iter = bootstrap_mapping->find(basename); + if (iter == bootstrap_mapping->end()) { + *bootstrap_basename = TProtoStringType(basename); return false; } else { *bootstrap_basename = iter->second; @@ -1381,70 +1472,64 @@ bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, // Adjust basename, but don't abort code generation. *basename = bootstrap_basename; return false; - } else { - const TProtoStringType& forward_to_basename = bootstrap_basename; - - // Generate forwarding headers and empty .pb.cc. - { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(*basename + ".pb.h")); - io::Printer printer(output.get(), '$', nullptr); - printer.Print( - "#ifndef PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n" - "#define PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n" - "#include \"$forward_to_basename$.pb.h\" // IWYU pragma: export\n" - "#endif // PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n", - "forward_to_basename", forward_to_basename, "filename_identifier", - FilenameIdentifier(*basename)); - - if (!options.opensource_runtime) { - // HACK HACK HACK, tech debt from the deeps of proto1 and SWIG - // protocoltype is SWIG'ed and we need to forward - if (*basename == "net/proto/protocoltype") { - printer.Print( - "#ifdef SWIG\n" - "%include \"$forward_to_basename$.pb.h\"\n" - "#endif // SWIG\n", - "forward_to_basename", forward_to_basename); - } - } - } - - { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(*basename + ".proto.h")); - io::Printer printer(output.get(), '$', nullptr); - printer.Print( - "#ifndef PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n" - "#define PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n" - "#include \"$forward_to_basename$.proto.h\" // IWYU pragma: " - "export\n" - "#endif // " - "PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n", - "forward_to_basename", forward_to_basename, "filename_identifier", - FilenameIdentifier(*basename)); - } - - { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(*basename + ".pb.cc")); - io::Printer printer(output.get(), '$', nullptr); - printer.Print("\n"); - } - - { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(*basename + ".pb.h.meta")); - } - - { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(*basename + ".proto.h.meta")); - } - - // Abort code generation. - return true; } + + auto pb_h = y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(*basename, ".pb.h"))); + + io::Printer p(pb_h.get()); + p.Emit( + { + {"fwd_to", bootstrap_basename}, + {"file", FilenameIdentifier(*basename)}, + {"fwd_to_suffix", options.opensource_runtime ? "pb" : "proto"}, + {"swig_evil", + [&] { + if (options.opensource_runtime) { + return; + } + p.Emit(R"( + #ifdef SWIG + %include "$fwd_to$.pb.h" + #endif // SWIG + )"); + }}, + }, + R"( + #ifndef PROTOBUF_INCLUDED_$file$_FORWARD_PB_H + #define PROTOBUF_INCLUDED_$file$_FORWARD_PB_H + #include "$fwd_to$.$fwd_to_suffix$.h" // IWYU pragma: export + #endif // PROTOBUF_INCLUDED_$file$_FORWARD_PB_H + $swig_evil$; + )"); + + auto proto_h = y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(*basename, ".proto.h"))); + io::Printer(proto_h.get()) + .Emit( + { + {"fwd_to", bootstrap_basename}, + {"file", FilenameIdentifier(*basename)}, + }, + R"( + #ifndef PROTOBUF_INCLUDED_$file$_FORWARD_PROTO_H + #define PROTOBUF_INCLUDED_$file$_FORWARD_PROTO_H + #include "$fwd_to$.proto.h" // IWYU pragma: export + #endif // PROTOBUF_INCLUDED_$file$_FORWARD_PROTO_H + )"); + + auto pb_cc = y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(*basename, ".pb.cc"))); + io::Printer(pb_cc.get()).PrintRaw("\n"); + + (void)y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(*basename, ".pb.h.meta"))); + + (void)y_absl::WrapUnique( + generator_context->Open(y_absl::StrCat(*basename, ".proto.h.meta"))); + + // Abort code generation. + return true; } static bool HasExtensionFromFile(const Message& msg, const FileDescriptor* file, @@ -1492,9 +1577,18 @@ static bool HasExtensionFromFile(const Message& msg, const FileDescriptor* file, static bool HasBootstrapProblem(const FileDescriptor* file, const Options& options, bool* has_opt_codesize_extension) { - static auto& cache = *new std::unordered_map<const FileDescriptor*, bool>; - auto it = cache.find(file); - if (it != cache.end()) return it->second; + struct BoostrapGlobals { + y_absl::Mutex mutex; + y_absl::flat_hash_set<const FileDescriptor*> cached Y_ABSL_GUARDED_BY(mutex); + y_absl::flat_hash_set<const FileDescriptor*> non_cached + Y_ABSL_GUARDED_BY(mutex); + }; + static auto& bootstrap_cache = *new BoostrapGlobals(); + + y_absl::MutexLock lock(&bootstrap_cache.mutex); + if (bootstrap_cache.cached.contains(file)) return true; + if (bootstrap_cache.non_cached.contains(file)) return false; + // In order to build the data structures for the reflective parse, it needs // to parse the serialized descriptor describing all the messages defined in // this file. Obviously this presents a bootstrap problem for descriptor @@ -1530,9 +1624,13 @@ static bool HasBootstrapProblem(const FileDescriptor* file, Message* fd_proto = factory.GetPrototype(fd_proto_descriptor)->New(); fd_proto->ParseFromString(linkedin_fd_proto.SerializeAsString()); - bool& res = cache[file]; - res = HasExtensionFromFile(*fd_proto, file, options, - has_opt_codesize_extension); + bool res = HasExtensionFromFile(*fd_proto, file, options, + has_opt_codesize_extension); + if (res) { + bootstrap_cache.cached.insert(file); + } else { + bootstrap_cache.non_cached.insert(file); + } delete fd_proto; return res; } @@ -1557,38 +1655,21 @@ FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, case EnforceOptimizeMode::kNoEnforcement: if (file->options().optimize_for() == FileOptions::CODE_SIZE) { if (HasBootstrapProblem(file, options, has_opt_codesize_extension)) { - GOOGLE_LOG(WARNING) << "Proto states optimize_for = CODE_SIZE, but we " - "cannot honor that because it contains custom option " - "extensions defined in the same proto."; + Y_ABSL_LOG(WARNING) + << "Proto states optimize_for = CODE_SIZE, but we " + "cannot honor that because it contains custom option " + "extensions defined in the same proto."; return FileOptions::SPEED; } } return file->options().optimize_for(); } - GOOGLE_LOG(FATAL) << "Unknown optimization enforcement requested."; + Y_ABSL_LOG(FATAL) << "Unknown optimization enforcement requested."; // The phony return below serves to silence a warning from GCC 8. return FileOptions::SPEED; } -inline bool IsMessageOwnedArenaEligible(const Descriptor* desc, - const Options& options) { - return GetOptimizeFor(desc->file(), options) != FileOptions::LITE_RUNTIME && - !options.bootstrap && !options.opensource_runtime && - AllocExpected(desc); -} - -bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options) { - (void)desc; - (void)options; - return false; -} - -bool EnableMessageOwnedArenaTrial(const Descriptor* desc, - const Options& options) { - return false; -} - bool HasMessageFieldOrExtension(const Descriptor* desc) { if (desc->extension_range_count() > 0) return true; for (const auto* f : FieldRange(desc)) { @@ -1597,6 +1678,21 @@ bool HasMessageFieldOrExtension(const Descriptor* desc) { return false; } +std::vector<io::Printer::Sub> AnnotatedAccessors( + const FieldDescriptor* field, y_absl::Span<const y_absl::string_view> prefixes, + y_absl::optional<google::protobuf::io::AnnotationCollector::Semantic> semantic) { + auto field_name = FieldName(field); + + std::vector<io::Printer::Sub> vars; + for (auto prefix : prefixes) { + vars.push_back(io::Printer::Sub(y_absl::StrCat(prefix, "name"), + y_absl::StrCat(prefix, field_name)) + .AnnotatedAs({field, semantic})); + } + + return vars; +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.h index 690a577591e..437c178c60c 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.h @@ -38,21 +38,27 @@ #include <algorithm> #include <cstdint> #include <iterator> -#include <map> #include <string> - -#include <google/protobuf/compiler/scc.h> -#include <google/protobuf/compiler/code_generator.h> -#include <google/protobuf/compiler/cpp/names.h> -#include <google/protobuf/compiler/cpp/options.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/port.h> -#include <google/protobuf/stubs/strutil.h> +#include <tuple> + +#include "google/protobuf/compiler/scc.h" +#include "google/protobuf/compiler/code_generator.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/strings/match.h" +#include "y_absl/strings/str_split.h" +#include "y_absl/strings/string_view.h" +#include "y_absl/types/optional.h" +#include "google/protobuf/compiler/cpp/names.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/port.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/io/printer.h" // Must be included last. -#include <google/protobuf/port_def.inc> +#include "google/protobuf/port_def.inc" namespace google { namespace protobuf { @@ -84,19 +90,22 @@ inline TProtoStringType DeprecatedAttribute(const Options& /* options */, extern const char kThickSeparator[]; extern const char kThinSeparator[]; -void SetCommonVars(const Options& options, - std::map<TProtoStringType, TProtoStringType>* variables); +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> MessageVars( + const Descriptor* desc); // Variables to access message data from the message scope. void SetCommonMessageDataVariables( const Descriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables); + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables); + +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> UnknownFieldsVars( + const Descriptor* desc, const Options& opts); -void SetUnknownFieldsVariable(const Descriptor* descriptor, - const Options& options, - std::map<TProtoStringType, TProtoStringType>* variables); +void SetUnknownFieldsVariable( + const Descriptor* descriptor, const Options& options, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables); -bool GetBootstrapBasename(const Options& options, const TProtoStringType& basename, +bool GetBootstrapBasename(const Options& options, y_absl::string_view basename, TProtoStringType* bootstrap_basename); bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, bool bootstrap_flag, TProtoStringType* basename); @@ -110,18 +119,31 @@ TProtoStringType Namespace(const FileDescriptor* d, const Options& options); TProtoStringType Namespace(const Descriptor* d, const Options& options); TProtoStringType Namespace(const FieldDescriptor* d, const Options& options); TProtoStringType Namespace(const EnumDescriptor* d, const Options& options); +PROTOC_EXPORT TProtoStringType Namespace(const FileDescriptor* d); +PROTOC_EXPORT TProtoStringType Namespace(const Descriptor* d); +PROTOC_EXPORT TProtoStringType Namespace(const FieldDescriptor* d); +PROTOC_EXPORT TProtoStringType Namespace(const EnumDescriptor* d); + +class MessageSCCAnalyzer; +// Returns true if it's safe to init "field" to zero. +bool CanInitializeByZeroing(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer); // Returns true if it's safe to reset "field" to zero. -bool CanInitializeByZeroing(const FieldDescriptor* field); +bool CanClearByZeroing(const FieldDescriptor* field); +// Determines if swap can be implemented via memcpy. +bool HasTrivialSwap(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); -TProtoStringType ClassName(const Descriptor* descriptor); -TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); +PROTOC_EXPORT TProtoStringType ClassName(const Descriptor* descriptor); +PROTOC_EXPORT TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); TProtoStringType QualifiedClassName(const Descriptor* d, const Options& options); TProtoStringType QualifiedClassName(const EnumDescriptor* d, const Options& options); -TProtoStringType QualifiedClassName(const Descriptor* d); -TProtoStringType QualifiedClassName(const EnumDescriptor* d); +PROTOC_EXPORT TProtoStringType QualifiedClassName(const Descriptor* d); +PROTOC_EXPORT TProtoStringType QualifiedClassName(const EnumDescriptor* d); // DEPRECATED just use ClassName or QualifiedClassName, a boolean is very // unreadable at the callsite. @@ -187,13 +209,13 @@ TProtoStringType SuperClassName(const Descriptor* descriptor, const Options& options); // Adds an underscore if necessary to prevent conflicting with a keyword. -TProtoStringType ResolveKeyword(const TProtoStringType& name); +TProtoStringType ResolveKeyword(y_absl::string_view name); // Get the (unqualified) name that should be used for this field in C++ code. // The name is coerced to lower-case to emulate proto1 behavior. People // should be using lowercase-with-underscores style for proto field names // anyway, so normally this just returns field->name(). -TProtoStringType FieldName(const FieldDescriptor* field); +PROTOC_EXPORT TProtoStringType FieldName(const FieldDescriptor* field); // Returns the (unqualified) private member name for this field in C++ code. TProtoStringType FieldMemberName(const FieldDescriptor* field, bool split); @@ -220,7 +242,7 @@ inline const Descriptor* FieldScope(const FieldDescriptor* field) { TProtoStringType FieldMessageTypeName(const FieldDescriptor* field, const Options& options); -// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.). +// Get the C++ type name for a primitive type (e.g. "double", "::int32", etc.). const char* PrimitiveTypeName(FieldDescriptor::CppType type); TProtoStringType PrimitiveTypeName(const Options& options, FieldDescriptor::CppType type); @@ -239,25 +261,25 @@ TProtoStringType DefaultValue(const Options& options, const FieldDescriptor* fie TProtoStringType DefaultValue(const FieldDescriptor* field); // Convert a file name into a valid identifier. -TProtoStringType FilenameIdentifier(const TProtoStringType& filename); +TProtoStringType FilenameIdentifier(y_absl::string_view filename); // For each .proto file generates a unique name. To prevent collisions of // symbols in the global namespace -TProtoStringType UniqueName(const TProtoStringType& name, const TProtoStringType& filename, +TProtoStringType UniqueName(y_absl::string_view name, y_absl::string_view filename, const Options& options); -inline TProtoStringType UniqueName(const TProtoStringType& name, const FileDescriptor* d, +inline TProtoStringType UniqueName(y_absl::string_view name, const FileDescriptor* d, const Options& options) { return UniqueName(name, d->name(), options); } -inline TProtoStringType UniqueName(const TProtoStringType& name, const Descriptor* d, +inline TProtoStringType UniqueName(y_absl::string_view name, const Descriptor* d, const Options& options) { return UniqueName(name, d->file(), options); } -inline TProtoStringType UniqueName(const TProtoStringType& name, const EnumDescriptor* d, +inline TProtoStringType UniqueName(y_absl::string_view name, const EnumDescriptor* d, const Options& options) { return UniqueName(name, d->file(), options); } -inline TProtoStringType UniqueName(const TProtoStringType& name, +inline TProtoStringType UniqueName(y_absl::string_view name, const ServiceDescriptor* d, const Options& options) { return UniqueName(name, d->file(), options); @@ -270,38 +292,36 @@ inline Options InternalRuntimeOptions() { options.opensource_runtime = false; return options; } -inline TProtoStringType UniqueName(const TProtoStringType& name, - const TProtoStringType& filename) { +inline TProtoStringType UniqueName(y_absl::string_view name, + y_absl::string_view filename) { return UniqueName(name, filename, InternalRuntimeOptions()); } -inline TProtoStringType UniqueName(const TProtoStringType& name, - const FileDescriptor* d) { +inline TProtoStringType UniqueName(y_absl::string_view name, const FileDescriptor* d) { return UniqueName(name, d->name(), InternalRuntimeOptions()); } -inline TProtoStringType UniqueName(const TProtoStringType& name, const Descriptor* d) { +inline TProtoStringType UniqueName(y_absl::string_view name, const Descriptor* d) { return UniqueName(name, d->file(), InternalRuntimeOptions()); } -inline TProtoStringType UniqueName(const TProtoStringType& name, - const EnumDescriptor* d) { +inline TProtoStringType UniqueName(y_absl::string_view name, const EnumDescriptor* d) { return UniqueName(name, d->file(), InternalRuntimeOptions()); } -inline TProtoStringType UniqueName(const TProtoStringType& name, +inline TProtoStringType UniqueName(y_absl::string_view name, const ServiceDescriptor* d) { return UniqueName(name, d->file(), InternalRuntimeOptions()); } // Return the qualified C++ name for a file level symbol. TProtoStringType QualifiedFileLevelSymbol(const FileDescriptor* file, - const TProtoStringType& name, + y_absl::string_view name, const Options& options); // Escape C++ trigraphs by escaping question marks to \? -TProtoStringType EscapeTrigraphs(const TProtoStringType& to_escape); +TProtoStringType EscapeTrigraphs(y_absl::string_view to_escape); // Escaped function name to eliminate naming conflict. TProtoStringType SafeFunctionName(const Descriptor* descriptor, const FieldDescriptor* field, - const TProtoStringType& prefix); + y_absl::string_view prefix); // Returns true if generated messages have public unknown fields accessors inline bool PublicUnknownFieldsAccessors(const Descriptor* message) { @@ -321,12 +341,14 @@ inline bool UseUnknownFieldSet(const FileDescriptor* file, inline bool IsWeak(const FieldDescriptor* field, const Options& options) { if (field->options().weak()) { - GOOGLE_CHECK(!options.opensource_runtime); + Y_ABSL_CHECK(!options.opensource_runtime); return true; } return false; } +bool IsProfileDriven(const Options& options); + bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options); // For a string field, returns the effective ctype. If the actual ctype is @@ -350,8 +372,6 @@ inline bool IsStringPiece(const FieldDescriptor* field, EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE; } -class MessageSCCAnalyzer; - // Does the given FileDescriptor use lazy fields? bool HasLazyFields(const FileDescriptor* file, const Options& options, MessageSCCAnalyzer* scc_analyzer); @@ -377,17 +397,16 @@ bool ShouldSplit(const Descriptor* desc, const Options& options); // Is the given field being split out? bool ShouldSplit(const FieldDescriptor* field, const Options& options); +// Should we generate code that force creating an allocation in the constructor +// of the given message? +bool ShouldForceAllocationOnConstruction(const Descriptor* desc, + const Options& options); + inline bool IsFieldUsed(const FieldDescriptor* /* field */, const Options& /* options */) { return true; } -// Returns true if "field" is stripped. -inline bool IsFieldStripped(const FieldDescriptor* /*field*/, - const Options& /*options*/) { - return false; -} - // Does the file contain any definitions that need extension_set.h? bool HasExtensionsOrExtendableMessage(const FileDescriptor* file); @@ -448,42 +467,20 @@ inline bool IsMapEntryMessage(const Descriptor* descriptor) { // Returns true if the field's CPPTYPE is string or message. bool IsStringOrMessage(const FieldDescriptor* field); -TProtoStringType UnderscoresToCamelCase(const TProtoStringType& input, +TProtoStringType UnderscoresToCamelCase(y_absl::string_view input, bool cap_next_letter); inline bool IsProto3(const FileDescriptor* file) { return file->syntax() == FileDescriptor::SYNTAX_PROTO3; } -inline bool HasHasbit(const FieldDescriptor* field) { - // This predicate includes proto3 message fields only if they have "optional". - // Foo submsg1 = 1; // HasHasbit() == false - // optional Foo submsg2 = 2; // HasHasbit() == true - // This is slightly odd, as adding "optional" to a singular proto3 field does - // not change the semantics or API. However whenever any field in a message - // has a hasbit, it forces reflection to include hasbit offsets for *all* - // fields, even if almost all of them are set to -1 (no hasbit). So to avoid - // causing a sudden size regression for ~all proto3 messages, we give proto3 - // message fields a hasbit only if "optional" is present. If the user is - // explicitly writing "optional", it is likely they are writing it on - // primitive fields also. - return (field->has_optional_keyword() || field->is_required()) && - !field->options().weak(); -} - -// Returns true if 'enum' semantics are such that unknown values are preserved -// in the enum field itself, rather than going to the UnknownFieldSet. -inline bool HasPreservingUnknownEnumSemantics(const FieldDescriptor* field) { - return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3; -} - inline bool IsCrossFileMessage(const FieldDescriptor* field) { return field->type() == FieldDescriptor::TYPE_MESSAGE && field->message_type()->file() != field->file(); } inline TProtoStringType MakeDefaultName(const FieldDescriptor* field) { - return StrCat("_i_give_permission_to_break_this_code_default_", + return y_absl::StrCat("_i_give_permission_to_break_this_code_default_", FieldName(field), "_"); } @@ -498,11 +495,11 @@ inline TProtoStringType MakeDefaultName(const FieldDescriptor* field) { // exists at some nested level like: // internal_container_._i_give_permission_to_break_this_code_default_field_; inline TProtoStringType MakeDefaultFieldName(const FieldDescriptor* field) { - return StrCat("Impl_::", MakeDefaultName(field)); + return y_absl::StrCat("Impl_::", MakeDefaultName(field)); } inline TProtoStringType MakeVarintCachedSizeName(const FieldDescriptor* field) { - return StrCat("_", FieldName(field), "_cached_byte_size_"); + return y_absl::StrCat("_", FieldName(field), "_cached_byte_size_"); } // Semantically distinct from MakeVarintCachedSizeName in that it gives the C++ @@ -518,7 +515,7 @@ inline TProtoStringType MakeVarintCachedSizeName(const FieldDescriptor* field) { // internal_container_._field_cached_byte_size_; inline TProtoStringType MakeVarintCachedSizeFieldName(const FieldDescriptor* field, bool split) { - return StrCat("_impl_.", split ? "_split_->" : "", "_", + return y_absl::StrCat("_impl_.", split ? "_split_->" : "", "_", FieldName(field), "_cached_byte_size_"); } @@ -531,20 +528,34 @@ bool IsAnyMessage(const Descriptor* descriptor, const Options& options); bool IsWellKnownMessage(const FileDescriptor* descriptor); -inline TProtoStringType IncludeGuard(const FileDescriptor* file, bool pb_h, - bool deps, +enum class GeneratedFileType : int { kPbH, kProtoH, kProtoStaticReflectionH }; + +inline TProtoStringType IncludeGuard(const FileDescriptor* file, + GeneratedFileType file_type, const Options& options) { // If we are generating a .pb.h file and the proto_h option is enabled, then // the .pb.h gets an extra suffix. - TProtoStringType filename_identifier = FilenameIdentifier( - file->name() + (deps ? ".deps": "") + (pb_h && options.proto_h ? ".pb.h" : "")); + TProtoStringType extension; + switch (file_type) { + case GeneratedFileType::kPbH: + extension = ".pb.h"; + break; + case GeneratedFileType::kProtoH: + extension = ".proto.h"; + break; + case GeneratedFileType::kProtoStaticReflectionH: + extension = ".proto.static_reflection.h"; + } + TProtoStringType filename_identifier = + FilenameIdentifier(file->name() + extension); if (IsWellKnownMessage(file)) { // For well-known messages we need third_party/protobuf and net/proto2 to // have distinct include guards, because some source files include both and // both need to be defined (the third_party copies will be in the // google::protobuf_opensource namespace). - return MacroPrefix(options) + "_INCLUDED_" + filename_identifier; + return y_absl::StrCat(MacroPrefix(options), "_INCLUDED_", + filename_identifier); } else { // Ideally this case would use distinct include guards for opensource and // google3 protos also. (The behavior of "first #included wins" is not @@ -552,7 +563,7 @@ inline TProtoStringType IncludeGuard(const FileDescriptor* file, bool pb_h, // the identical include guards to avoid compile errors. // // We should clean this up so that this case can be removed. - return "GOOGLE_PROTOBUF_INCLUDED_" + filename_identifier; + return y_absl::StrCat("GOOGLE_PROTOBUF_INCLUDED_", filename_identifier); } } @@ -663,7 +674,7 @@ class PROTOC_EXPORT MessageSCCAnalyzer { }; SCCAnalyzer<DepsGenerator> analyzer_; Options options_; - std::map<const SCC*, MessageAnalysis> analysis_cache_; + y_absl::flat_hash_map<const SCC*, MessageAnalysis> analysis_cache_; }; void ListAllFields(const Descriptor* d, @@ -747,6 +758,8 @@ inline bool HasImplData(const Descriptor* desc, const Options& options) { return !HasSimpleBaseClass(desc, options); } +// DO NOT USE IN NEW CODE! Use io::Printer directly instead. See b/242326974. +// // Formatter is a functor class which acts as a closure around printer and // the variable map. It's much like printer->Print except it supports both named // variables that are substituted using a key value map and direct arguments. In @@ -789,15 +802,15 @@ class PROTOC_EXPORT Formatter { public: explicit Formatter(io::Printer* printer) : printer_(printer) {} Formatter(io::Printer* printer, - const std::map<TProtoStringType, TProtoStringType>& vars) + const y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>& vars) : printer_(printer), vars_(vars) {} template <typename T> - void Set(const TProtoStringType& key, const T& value) { + void Set(y_absl::string_view key, const T& value) { vars_[key] = ToString(value); } - void AddMap(const std::map<TProtoStringType, TProtoStringType>& vars) { + void AddMap(const y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>& vars) { for (const auto& keyval : vars) vars_[keyval.first] = keyval.second; } @@ -839,31 +852,69 @@ class PROTOC_EXPORT Formatter { private: Formatter* format_; - std::map<TProtoStringType, TProtoStringType> vars_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars_; }; private: io::Printer* printer_; - std::map<TProtoStringType, TProtoStringType> vars_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars_; // Convenience overloads to accept different types as arguments. - static TProtoStringType ToString(const TProtoStringType& s) { return s; } + static TProtoStringType ToString(y_absl::string_view s) { return TProtoStringType(s); } template <typename I, typename = typename std::enable_if< std::is_integral<I>::value>::type> static TProtoStringType ToString(I x) { - return StrCat(x); + return y_absl::StrCat(x); + } + static TProtoStringType ToString(y_absl::Hex x) { return y_absl::StrCat(x); } + static TProtoStringType ToString(const FieldDescriptor* d) { + return Payload(d, GeneratedCodeInfo::Annotation::NONE); + } + static TProtoStringType ToString(const Descriptor* d) { + return Payload(d, GeneratedCodeInfo::Annotation::NONE); + } + static TProtoStringType ToString(const EnumDescriptor* d) { + return Payload(d, GeneratedCodeInfo::Annotation::NONE); } - static TProtoStringType ToString(strings::Hex x) { return StrCat(x); } - static TProtoStringType ToString(const FieldDescriptor* d) { return Payload(d); } - static TProtoStringType ToString(const Descriptor* d) { return Payload(d); } - static TProtoStringType ToString(const EnumDescriptor* d) { return Payload(d); } static TProtoStringType ToString(const EnumValueDescriptor* d) { - return Payload(d); + return Payload(d, GeneratedCodeInfo::Annotation::NONE); + } + static TProtoStringType ToString(const OneofDescriptor* d) { + return Payload(d, GeneratedCodeInfo::Annotation::NONE); + } + + static TProtoStringType ToString( + std::tuple<const FieldDescriptor*, + GeneratedCodeInfo::Annotation::Semantic> + p) { + return Payload(std::get<0>(p), std::get<1>(p)); + } + static TProtoStringType ToString( + std::tuple<const Descriptor*, GeneratedCodeInfo::Annotation::Semantic> + p) { + return Payload(std::get<0>(p), std::get<1>(p)); + } + static TProtoStringType ToString( + std::tuple<const EnumDescriptor*, GeneratedCodeInfo::Annotation::Semantic> + p) { + return Payload(std::get<0>(p), std::get<1>(p)); + } + static TProtoStringType ToString( + std::tuple<const EnumValueDescriptor*, + GeneratedCodeInfo::Annotation::Semantic> + p) { + return Payload(std::get<0>(p), std::get<1>(p)); + } + static TProtoStringType ToString( + std::tuple<const OneofDescriptor*, + GeneratedCodeInfo::Annotation::Semantic> + p) { + return Payload(std::get<0>(p), std::get<1>(p)); } - static TProtoStringType ToString(const OneofDescriptor* d) { return Payload(d); } template <typename Descriptor> - static TProtoStringType Payload(const Descriptor* descriptor) { + static TProtoStringType Payload(const Descriptor* descriptor, + GeneratedCodeInfo::Annotation::Semantic semantic) { std::vector<int> path; descriptor->GetLocationPath(&path); GeneratedCodeInfo::Annotation annotation; @@ -871,119 +922,71 @@ class PROTOC_EXPORT Formatter { annotation.add_path(index); } annotation.set_source_file(descriptor->file()->name()); + annotation.set_semantic(semantic); return annotation.SerializeAsString(); } }; -template <class T> -void PrintFieldComment(const Formatter& format, const T* field) { +template <typename T> +TProtoStringType FieldComment(const T* field) { // Print the field's (or oneof's) proto-syntax definition as a comment. // We don't want to print group bodies so we cut off after the first // line. DebugStringOptions options; options.elide_group_body = true; options.elide_oneof_body = true; - TProtoStringType def = field->DebugStringWithOptions(options); - format("// $1$\n", def.substr(0, def.find_first_of('\n'))); + + for (y_absl::string_view chunk : + y_absl::StrSplit(field->DebugStringWithOptions(options), '\n')) { + return TProtoStringType(chunk); + } + + return "<unknown>"; +} + +template <class T> +void PrintFieldComment(const Formatter& format, const T* field) { + format("// $1$\n", FieldComment(field)); } class PROTOC_EXPORT NamespaceOpener { public: - explicit NamespaceOpener(const Formatter& format) - : printer_(format.printer()) {} - NamespaceOpener(const TProtoStringType& name, const Formatter& format) + explicit NamespaceOpener(io::Printer* p) : p_(p) {} + explicit NamespaceOpener(const Formatter& format) : p_(format.printer()) {} + NamespaceOpener(y_absl::string_view name, const Formatter& format) : NamespaceOpener(format) { ChangeTo(name); } + NamespaceOpener(y_absl::string_view name, io::Printer* p) : NamespaceOpener(p) { + ChangeTo(name); + } ~NamespaceOpener() { ChangeTo(""); } - void ChangeTo(const TProtoStringType& name) { - std::vector<TProtoStringType> new_stack_ = - Split(name, "::", true); - size_t len = std::min(name_stack_.size(), new_stack_.size()); - size_t common_idx = 0; - while (common_idx < len) { - if (name_stack_[common_idx] != new_stack_[common_idx]) break; - common_idx++; - } - for (auto it = name_stack_.crbegin(); - it != name_stack_.crend() - common_idx; ++it) { - if (*it == "PROTOBUF_NAMESPACE_ID") { - printer_->Print("PROTOBUF_NAMESPACE_CLOSE\n"); - } else { - printer_->Print("} // namespace $ns$\n", "ns", *it); - } - } - name_stack_.swap(new_stack_); - for (size_t i = common_idx; i < name_stack_.size(); ++i) { - if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") { - printer_->Print("PROTOBUF_NAMESPACE_OPEN\n"); - } else { - printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]); - } - } - } + void ChangeTo(y_absl::string_view name); private: - io::Printer* printer_; + io::Printer* p_; std::vector<TProtoStringType> name_stack_; }; -enum class Utf8CheckMode { - kStrict = 0, // Parsing will fail if non UTF-8 data is in string fields. - kVerify = 1, // Only log an error but parsing will succeed. - kNone = 2, // No UTF-8 check. -}; - -Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, - const Options& options); - void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, const Options& options, bool for_parse, - const char* parameters, + y_absl::string_view parameters, const Formatter& format); void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, const Options& options, bool for_parse, - const char* parameters, + y_absl::string_view parameters, const Formatter& format); -template <typename T> -struct FieldRangeImpl { - struct Iterator { - using iterator_category = std::forward_iterator_tag; - using value_type = const FieldDescriptor*; - using difference_type = int; - - value_type operator*() { return descriptor->field(idx); } - - friend bool operator==(const Iterator& a, const Iterator& b) { - GOOGLE_DCHECK(a.descriptor == b.descriptor); - return a.idx == b.idx; - } - friend bool operator!=(const Iterator& a, const Iterator& b) { - return !(a == b); - } - - Iterator& operator++() { - idx++; - return *this; - } - - int idx; - const T* descriptor; - }; - - Iterator begin() const { return {0, descriptor}; } - Iterator end() const { return {descriptor->field_count(), descriptor}; } - - const T* descriptor; -}; +void GenerateUtf8CheckCodeForString(io::Printer* p, + const FieldDescriptor* field, + const Options& options, bool for_parse, + y_absl::string_view parameters); -template <typename T> -FieldRangeImpl<T> FieldRange(const T* desc) { - return {desc}; -} +void GenerateUtf8CheckCodeForCord(io::Printer* p, const FieldDescriptor* field, + const Options& options, bool for_parse, + y_absl::string_view parameters); struct OneOfRangeImpl { struct Iterator { @@ -994,7 +997,7 @@ struct OneOfRangeImpl { value_type operator*() { return descriptor->oneof_decl(idx); } friend bool operator==(const Iterator& a, const Iterator& b) { - GOOGLE_DCHECK(a.descriptor == b.descriptor); + Y_ABSL_DCHECK(a.descriptor == b.descriptor); return a.idx == b.idx; } friend bool operator!=(const Iterator& a, const Iterator& b) { @@ -1020,12 +1023,8 @@ struct OneOfRangeImpl { inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; } -PROTOC_EXPORT TProtoStringType StripProto(const TProtoStringType& filename); - -bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options); - -bool EnableMessageOwnedArenaTrial(const Descriptor* desc, - const Options& options); +// Strips ".proto" or ".protodevel" from the end of a filename. +PROTOC_EXPORT TProtoStringType StripProto(y_absl::string_view filename); bool ShouldVerify(const Descriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer); @@ -1055,11 +1054,21 @@ bool IsUtf8String(const FieldDescriptor* field); bool HasMessageFieldOrExtension(const Descriptor* desc); +// Generates a vector of substitutions for use with Printer::WithVars that +// contains annotated accessor names for a particular field. +// +// Each substitution will be named `y_absl::StrCat(prefix, "name")`, and will +// be annotated with `field`. +std::vector<io::Printer::Sub> AnnotatedAccessors( + const FieldDescriptor* field, y_absl::Span<const y_absl::string_view> prefixes, + y_absl::optional<google::protobuf::io::AnnotationCollector::Semantic> semantic = + y_absl::nullopt); + } // namespace cpp } // namespace compiler } // namespace protobuf } // namespace google -#include <google/protobuf/port_undef.inc> +#include "google/protobuf/port_undef.inc" #endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.h deleted file mode 100644 index 678a128bd18..00000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.h +++ /dev/null @@ -1,83 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ - -#include <map> -#include <string> - -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/cpp/message_field.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -class MapFieldGenerator : public FieldGenerator { - public: - MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options, - MessageSCCAnalyzer* scc_analyzer); - ~MapFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override {} - void GenerateCopyConstructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - void GenerateIsInitialized(io::Printer* printer) const override; - void GenerateConstexprAggregateInitializer( - io::Printer* printer) const override; - void GenerateCopyAggregateInitializer(io::Printer* printer) const override; - void GenerateAggregateInitializer(io::Printer* printer) const override; - void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateArenaDestructorCode(io::Printer* printer) const override; - ArenaDtorNeeds NeedsArenaDestructor() const override; - - private: - const bool has_required_fields_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); -}; - -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.cc index 77702a68dfc..a80ae0922af 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.cc @@ -32,49 +32,60 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/message.h> +#include "google/protobuf/compiler/cpp/message.h" #include <algorithm> +#include <array> +#include <cmath> #include <cstdint> #include <functional> -#include <map> +#include <limits> #include <memory> -#include <unordered_map> +#include <type_traits> #include <utility> #include <vector> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/generated_message_util.h> -#include <google/protobuf/map_entry_lite.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/stringprintf.h> -#include <google/protobuf/stubs/substitute.h> -#include <google/protobuf/compiler/cpp/enum.h> -#include <google/protobuf/compiler/cpp/extension.h> -#include <google/protobuf/compiler/cpp/field.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/cpp/padding_optimizer.h> -#include <google/protobuf/compiler/cpp/parse_function_generator.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/stubs/hash.h> +#include "google/protobuf/stubs/common.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/generated_message_util.h" +#include "google/protobuf/map_entry_lite.h" +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/log/absl_log.h" +#include "y_absl/strings/ascii.h" +#include "y_absl/strings/escaping.h" +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/str_format.h" +#include "y_absl/strings/str_join.h" +#include "y_absl/strings/string_view.h" +#include "y_absl/strings/substitute.h" +#include "google/protobuf/compiler/cpp/enum.h" +#include "google/protobuf/compiler/cpp/extension.h" +#include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/names.h" +#include "google/protobuf/compiler/cpp/padding_optimizer.h" +#include "google/protobuf/compiler/cpp/parse_function_generator.h" +#include "google/protobuf/compiler/cpp/tracker.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/wire_format.h" // Must be included last. -#include <google/protobuf/port_def.inc> +#include "google/protobuf/port_def.inc" namespace google { namespace protobuf { namespace compiler { namespace cpp { - -using internal::WireFormat; -using internal::WireFormatLite; - namespace { +using ::google::protobuf::internal::WireFormat; +using ::google::protobuf::internal::WireFormatLite; +using ::google::protobuf::internal::cpp::HasHasbit; +using ::google::protobuf::internal::cpp::Utf8CheckMode; +using Sub = ::google::protobuf::io::Printer::Sub; static constexpr int kNoHasbit = -1; @@ -84,27 +95,28 @@ static constexpr int kNoHasbit = -1; // masks must be non-zero. TProtoStringType ConditionalToCheckBitmasks( const std::vector<arc_ui32>& masks, bool return_success = true, - StringPiece has_bits_var = "_impl_._has_bits_") { + y_absl::string_view has_bits_var = "_impl_._has_bits_") { std::vector<TProtoStringType> parts; for (int i = 0; i < masks.size(); i++) { if (masks[i] == 0) continue; - TProtoStringType m = StrCat("0x", strings::Hex(masks[i], strings::ZERO_PAD_8)); + TProtoStringType m = y_absl::StrCat("0x", y_absl::Hex(masks[i], y_absl::kZeroPad8)); // Each xor evaluates to 0 if the expected bits are present. parts.push_back( - StrCat("((", has_bits_var, "[", i, "] & ", m, ") ^ ", m, ")")); + y_absl::StrCat("((", has_bits_var, "[", i, "] & ", m, ") ^ ", m, ")")); } - GOOGLE_CHECK(!parts.empty()); + Y_ABSL_CHECK(!parts.empty()); // If we have multiple parts, each expected to be 0, then bitwise-or them. TProtoStringType result = parts.size() == 1 ? parts[0] - : StrCat("(", Join(parts, "\n | "), ")"); + : y_absl::StrCat("(", y_absl::StrJoin(parts, "\n | "), ")"); return result + (return_success ? " == 0" : " != 0"); } -void PrintPresenceCheck(const Formatter& format, const FieldDescriptor* field, - const std::vector<int>& has_bit_indices, - io::Printer* printer, int* cached_has_word_index) { +void PrintPresenceCheck(const FieldDescriptor* field, + const std::vector<int>& has_bit_indices, io::Printer* p, + int* cached_has_word_index) { + Formatter format(p); if (!field->options().weak()) { int has_bit_index = has_bit_indices[field->index()]; if (*cached_has_word_index != (has_bit_index / 32)) { @@ -112,7 +124,7 @@ void PrintPresenceCheck(const Formatter& format, const FieldDescriptor* field, format("cached_has_bits = $has_bits$[$1$];\n", *cached_has_word_index); } const TProtoStringType mask = - StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + y_absl::StrCat(y_absl::Hex(1u << (has_bit_index % 32), y_absl::kZeroPad8)); format("if (cached_has_bits & 0x$1$u) {\n", mask); } else { format("if (has_$1$()) {\n", FieldName(field)); @@ -166,32 +178,11 @@ bool IsPOD(const FieldDescriptor* field) { } } -// Helper for the code that emits the SharedCtor() and InternalSwap() methods. -// Anything that is a POD or a "normal" message (represented by a pointer) can -// be manipulated as raw bytes. -bool CanBeManipulatedAsRawBytes(const FieldDescriptor* field, - const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - bool ret = CanInitializeByZeroing(field); - - // Non-repeated, non-lazy message fields are simply raw pointers, so we can - // swap them or use memset to initialize these in SharedCtor. We cannot use - // this in Clear, as we need to potentially delete the existing value. - ret = - ret || (!field->is_repeated() && !IsLazy(field, options, scc_analyzer) && - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); - return ret; -} - -bool StrContains(const TProtoStringType& haystack, const TProtoStringType& needle) { - return haystack.find(needle) != TProtoStringType::npos; -} - // Finds runs of fields for which `predicate` is true. // RunMap maps from fields that start each run to the number of fields in that // run. This is optimized for the common case that there are very few runs in // a message and that most of the eligible fields appear together. -using RunMap = std::unordered_map<const FieldDescriptor*, size_t>; +using RunMap = y_absl::flat_hash_map<const FieldDescriptor*, size_t>; RunMap FindRuns(const std::vector<const FieldDescriptor*>& fields, const std::function<bool(const FieldDescriptor*)>& predicate) { RunMap runs; @@ -215,13 +206,14 @@ RunMap FindRuns(const std::vector<const FieldDescriptor*>& fields, // considered non-default (will be sent over the wire), for message types // without true field presence. Should only be called if // !HasHasbit(field). -bool EmitFieldNonDefaultCondition(io::Printer* printer, - const TProtoStringType& prefix, +bool EmitFieldNonDefaultCondition(io::Printer* p, const TProtoStringType& prefix, const FieldDescriptor* field) { - GOOGLE_CHECK(!HasHasbit(field)); - Formatter format(printer); - format.Set("prefix", prefix); - format.Set("name", FieldName(field)); + Y_ABSL_CHECK(!HasHasbit(field)); + Formatter format(p); + auto v = p->WithVars({{ + {"prefix", prefix}, + {"name", FieldName(field)}, + }}); // Merge and serialize semantics: primitive fields are merged/serialized only // if non-zero (numeric) or non-empty (string). if (!field->is_repeated() && !field->containing_oneof()) { @@ -232,18 +224,18 @@ bool EmitFieldNonDefaultCondition(io::Printer* printer, format("if ($prefix$_internal_has_$name$()) {\n"); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) { format( - "static_assert(sizeof(arc_ui32) == sizeof(float), \"Code assumes " - "arc_ui32 and float are the same size.\");\n" + "static_assert(sizeof(::arc_ui32) == sizeof(float), \"Code assumes " + "::arc_ui32 and float are the same size.\");\n" "float tmp_$name$ = $prefix$_internal_$name$();\n" - "arc_ui32 raw_$name$;\n" + "::arc_ui32 raw_$name$;\n" "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n" "if (raw_$name$ != 0) {\n"); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { format( - "static_assert(sizeof(arc_ui64) == sizeof(double), \"Code assumes " - "arc_ui64 and double are the same size.\");\n" + "static_assert(sizeof(::arc_ui64) == sizeof(double), \"Code assumes " + "::arc_ui64 and double are the same size.\");\n" "double tmp_$name$ = $prefix$_internal_$name$();\n" - "arc_ui64 raw_$name$;\n" + "::arc_ui64 raw_$name$;\n" "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n" "if (raw_$name$ != 0) {\n"); } else { @@ -252,7 +244,7 @@ bool EmitFieldNonDefaultCondition(io::Printer* printer, format.Indent(); return true; } else if (field->real_containing_oneof()) { - format("if (_internal_has_$name$()) {\n"); + format("if ($has_field$) {\n"); format.Indent(); return true; } @@ -271,11 +263,17 @@ bool HasHasMethod(const FieldDescriptor* field) { field->has_optional_keyword() || field->real_containing_oneof(); } +bool HasInternalHasMethod(const FieldDescriptor* field) { + return !HasHasbit(field) && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE; +} + // Collects map entry message type information. -void CollectMapInfo(const Options& options, const Descriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables) { - GOOGLE_CHECK(IsMapEntryMessage(descriptor)); - std::map<TProtoStringType, TProtoStringType>& vars = *variables; +void CollectMapInfo( + const Options& options, const Descriptor* descriptor, + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>* variables) { + Y_ABSL_CHECK(IsMapEntryMessage(descriptor)); + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>& vars = *variables; const FieldDescriptor* key = descriptor->map_key(); const FieldDescriptor* val = descriptor->map_value(); vars["key_cpp"] = PrimitiveTypeName(options, key->cpp_type()); @@ -289,26 +287,10 @@ void CollectMapInfo(const Options& options, const Descriptor* descriptor, default: vars["val_cpp"] = PrimitiveTypeName(options, val->cpp_type()); } - vars["key_wire_type"] = - "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type())); - vars["val_wire_type"] = - "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type())); -} - -// Does the given field have a private (internal helper only) has_$name$() -// method? -bool HasPrivateHasMethod(const FieldDescriptor* field) { - // Only for oneofs in message types with no field presence. has_$name$(), - // based on the oneof case, is still useful internally for generated code. - return IsProto3(field->file()) && field->real_containing_oneof(); -} - -// TODO(ckennelly): Cull these exclusions if/when these protos do not have -// their methods overridden by subclasses. - -bool ShouldMarkClassAsFinal(const Descriptor* descriptor, - const Options& options) { - return false; + vars["key_wire_type"] = y_absl::StrCat( + "TYPE_", y_absl::AsciiStrToUpper(DeclaredTypeMethodName(key->type()))); + vars["val_wire_type"] = y_absl::StrCat( + "TYPE_", y_absl::AsciiStrToUpper(DeclaredTypeMethodName(val->type()))); } @@ -376,16 +358,16 @@ std::vector<std::vector<const FieldDescriptor*>> CollectFields( // masked to tell if any thing in "fields" is present. arc_ui32 GenChunkMask(const std::vector<const FieldDescriptor*>& fields, const std::vector<int>& has_bit_indices) { - GOOGLE_CHECK(!fields.empty()); + Y_ABSL_CHECK(!fields.empty()); int first_index_offset = has_bit_indices[fields.front()->index()] / 32; arc_ui32 chunk_mask = 0; for (auto field : fields) { // "index" defines where in the _has_bits_ the field appears. int index = has_bit_indices[field->index()]; - GOOGLE_CHECK_EQ(first_index_offset, index / 32); + Y_ABSL_CHECK_EQ(first_index_offset, index / 32); chunk_mask |= static_cast<arc_ui32>(1) << (index % 32); } - GOOGLE_CHECK_NE(0, chunk_mask); + Y_ABSL_CHECK_NE(0, chunk_mask); return chunk_mask; } @@ -411,7 +393,6 @@ class ColdChunkSkipper { has_bit_indices_(has_bit_indices), access_info_map_(options.access_info_map), cold_threshold_(cold_threshold) { - SetCommonVars(options, &variables_); SetCommonMessageDataVariables(descriptor, &variables_); } @@ -419,8 +400,8 @@ class ColdChunkSkipper { // prefix to _has_bits_ to allow MergeFrom to use "from._has_bits_". // Otherwise, it should be "". void OnStartChunk(int chunk, int cached_has_word_index, - const TProtoStringType& from, io::Printer* printer); - bool OnEndChunk(int chunk, io::Printer* printer); + const TProtoStringType& from, io::Printer* p); + bool OnEndChunk(int chunk, io::Printer* p); private: bool IsColdChunk(int chunk); @@ -433,7 +414,7 @@ class ColdChunkSkipper { const std::vector<int>& has_bit_indices_; const AccessInfoMap* access_info_map_; const double cold_threshold_; - std::map<TProtoStringType, TProtoStringType> variables_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> variables_; int limit_chunk_ = -1; }; @@ -448,9 +429,8 @@ bool ColdChunkSkipper::IsColdChunk(int chunk) { void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, - const TProtoStringType& from, - io::Printer* printer) { - Formatter format(printer, variables_); + const TProtoStringType& from, io::Printer* p) { + Formatter format(p); if (!access_info_map_) { return; } else if (chunk < limit_chunk_) { @@ -484,7 +464,7 @@ void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, for (auto field : chunks_[chunk]) { int hasbit_index = has_bit_indices_[field->index()]; // Fields on a chunk must be in the same word. - GOOGLE_CHECK_EQ(this_word, hasbit_index / 32); + Y_ABSL_CHECK_EQ(this_word, hasbit_index / 32); mask |= 1 << (hasbit_index % 32); } } @@ -492,7 +472,7 @@ void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, if (this_word != first_word) { format(" ||\n "); } - format.Set("mask", strings::Hex(mask, strings::ZERO_PAD_8)); + auto v = p->WithVars({{"mask", y_absl::Hex(mask, y_absl::kZeroPad8)}}); if (this_word == cached_has_word_index) { format("(cached_has_bits & 0x$mask$u) != 0"); } else { @@ -503,8 +483,8 @@ void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, format.Indent(); } -bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) { - Formatter format(printer, variables_); +bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* p) { + Formatter format(p); if (chunk != limit_chunk_ - 1) { return false; } @@ -513,86 +493,37 @@ bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) { return true; } -void MaySetAnnotationVariable(const Options& options, - StringPiece annotation_name, - StringPiece injector_template_prefix, - StringPiece injector_template_suffix, - std::map<TProtoStringType, TProtoStringType>* variables) { - if (options.field_listener_options.forbidden_field_listener_events.count( - TProtoStringType(annotation_name))) - return; - (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute( - StrCat(injector_template_prefix, injector_template_suffix), - (*variables)["classtype"]); +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> ClassVars( + const Descriptor* desc, Options opts) { + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars = MessageVars(desc); + + vars.emplace("pkg", Namespace(desc, opts)); + vars.emplace("Msg", ClassName(desc, false)); + vars.emplace("pkg::Msg", QualifiedClassName(desc, opts)); + vars.emplace("pkg.Msg", desc->full_name()); + + // Old-style names, to be removed once all usages are gone in this and other + // files. + vars.emplace("classname", ClassName(desc, false)); + vars.emplace("classtype", QualifiedClassName(desc, opts)); + vars.emplace("full_name", desc->full_name()); + vars.emplace("superclass", SuperClassName(desc, opts)); + + for (auto& pair : UnknownFieldsVars(desc, opts)) { + vars.emplace(pair); + } + + return vars; } -void GenerateExtensionAnnotations( - const Descriptor* descriptor, const Options& options, - std::map<TProtoStringType, TProtoStringType>* variables) { - const std::map<TProtoStringType, TProtoStringType> accessor_annotations_to_hooks = { - {"annotate_extension_has", "OnHasExtension"}, - {"annotate_extension_clear", "OnClearExtension"}, - {"annotate_extension_repeated_size", "OnExtensionSize"}, - {"annotate_extension_get", "OnGetExtension"}, - {"annotate_extension_mutable", "OnMutableExtension"}, - {"annotate_extension_set", "OnSetExtension"}, - {"annotate_extension_release", "OnReleaseExtension"}, - {"annotate_repeated_extension_get", "OnGetExtension"}, - {"annotate_repeated_extension_mutable", "OnMutableExtension"}, - {"annotate_repeated_extension_set", "OnSetExtension"}, - {"annotate_repeated_extension_add", "OnAddExtension"}, - {"annotate_repeated_extension_add_mutable", "OnAddMutableExtension"}, - {"annotate_repeated_extension_list", "OnListExtension"}, - {"annotate_repeated_extension_list_mutable", "OnMutableListExtension"}, +y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> HasbitVars( + int has_bit_index) { + return { + {"has_array_index", y_absl::StrCat(has_bit_index / 32)}, + {"has_mask", + y_absl::StrCat( + "0x", y_absl::Hex(1u << (has_bit_index % 32), y_absl::kZeroPad8), "u")}, }; - for (const auto& annotation : accessor_annotations_to_hooks) { - (*variables)[annotation.first] = ""; - } - if (!HasTracker(descriptor, options)) { - return; - } - StringPiece tracker = (*variables)["tracker"]; - StringPiece extensions = (*variables)["extensions"]; - for (const auto& annotation : accessor_annotations_to_hooks) { - const TProtoStringType& annotation_name = annotation.first; - const TProtoStringType& listener_call = annotation.second; - if (!StrContains(annotation_name, "repeated") && - !StrContains(annotation_name, "size") && - !StrContains(annotation_name, "clear")) { - // Primitive fields accessors. - // "Has" is here as users calling "has" on a repeated field is a mistake. - (*variables)[annotation_name] = StrCat( - " ", tracker, ".", listener_call, - "(this, id.number(), _proto_TypeTraits::GetPtr(id.number(), ", - extensions, ", id.default_value_ref()));"); - } else if (StrContains(annotation_name, "repeated") && - !StrContains(annotation_name, "list") && - !StrContains(annotation_name, "size")) { - // Repeated index accessors. - TProtoStringType str_index = "index"; - if (StrContains(annotation_name, "add")) { - str_index = StrCat(extensions, ".ExtensionSize(id.number()) - 1"); - } - (*variables)[annotation_name] = - StrCat(" ", tracker, ".", listener_call, - "(this, id.number(), " - "_proto_TypeTraits::GetPtr(id.number(), ", - extensions, ", ", str_index, "));"); - } else if (StrContains(annotation_name, "list") || - StrContains(annotation_name, "size")) { - // Repeated full accessors. - (*variables)[annotation_name] = StrCat( - " ", tracker, ".", listener_call, - "(this, id.number(), _proto_TypeTraits::GetRepeatedPtr(id.number(), ", - extensions, "));"); - } else { - // Generic accessors such as "clear". - // TODO(b/190614678): Generalize clear from both repeated and non repeated - // calls, currently their underlying memory interfaces are very different. - // Or think of removing clear callback as no usages are needed and no - // memory exist after calling clear(). - } - } } } // anonymous namespace @@ -601,68 +532,28 @@ void GenerateExtensionAnnotations( MessageGenerator::MessageGenerator( const Descriptor* descriptor, - const std::map<TProtoStringType, TProtoStringType>& vars, int index_in_file_messages, - const Options& options, MessageSCCAnalyzer* scc_analyzer) + const y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>&, + int index_in_file_messages, const Options& options, + MessageSCCAnalyzer* scc_analyzer) : descriptor_(descriptor), index_in_file_messages_(index_in_file_messages), - classname_(ClassName(descriptor, false)), options_(options), - field_generators_(descriptor, options, scc_analyzer), - max_has_bit_index_(0), - max_inlined_string_index_(0), - num_weak_fields_(0), - scc_analyzer_(scc_analyzer), - variables_(vars) { - if (!message_layout_helper_) { - message_layout_helper_.reset(new PaddingOptimizer()); - } - SetCommonMessageDataVariables(descriptor, &variables_); + field_generators_(descriptor), + scc_analyzer_(scc_analyzer) { - // Variables that apply to this class - variables_["classname"] = classname_; - variables_["classtype"] = QualifiedClassName(descriptor_, options); - variables_["full_name"] = descriptor_->full_name(); - variables_["superclass"] = SuperClassName(descriptor_, options_); - variables_["annotate_serialize"] = ""; - variables_["annotate_deserialize"] = ""; - variables_["annotate_reflection"] = ""; - variables_["annotate_bytesize"] = ""; - variables_["annotate_mergefrom"] = ""; - - if (HasTracker(descriptor_, options_)) { - const TProtoStringType injector_template = - StrCat(" ", variables_["tracker"], "."); - - MaySetAnnotationVariable(options, "serialize", injector_template, - "OnSerialize(this);\n", &variables_); - MaySetAnnotationVariable(options, "deserialize", injector_template, - "OnDeserialize(this);\n", &variables_); - // TODO(danilak): Ideally annotate_reflection should not exist and we need - // to annotate all reflective calls on our own, however, as this is a cause - // for side effects, i.e. reading values dynamically, we want the users know - // that dynamic access can happen. - MaySetAnnotationVariable(options, "reflection", injector_template, - "OnGetMetadata();\n", &variables_); - MaySetAnnotationVariable(options, "bytesize", injector_template, - "OnByteSize(this);\n", &variables_); - MaySetAnnotationVariable(options, "mergefrom", injector_template, - "OnMergeFrom(_this, &from);\n", &variables_); + if (!message_layout_helper_) { + message_layout_helper_ = std::make_unique<PaddingOptimizer>(); } - GenerateExtensionAnnotations(descriptor_, options_, &variables_); - - SetUnknownFieldsVariable(descriptor_, options_, &variables_); - // Compute optimized field order to be used for layout and initialization // purposes. for (auto field : FieldRange(descriptor_)) { - if (IsFieldStripped(field, options_)) { + if (IsWeak(field, options_)) { + ++num_weak_fields_; continue; } - if (IsWeak(field, options_)) { - num_weak_fields_++; - } else if (!field->real_containing_oneof()) { + if (!field->real_containing_oneof()) { optimized_order_.push_back(field); } } @@ -683,34 +574,26 @@ MessageGenerator::MessageGenerator( inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit); // The bitset[0] is for arena dtor tracking. Donating states start from // bitset[1]; - max_inlined_string_index_++; + ++max_inlined_string_index_; } + inlined_string_indices_[field->index()] = max_inlined_string_index_++; } } + field_generators_.Build(options_, scc_analyzer_, has_bit_indices_, + inlined_string_indices_); - if (!has_bit_indices_.empty()) { - field_generators_.SetHasBitIndices(has_bit_indices_); - } - - if (!inlined_string_indices_.empty()) { - field_generators_.SetInlinedStringIndices(inlined_string_indices_); - } - - num_required_fields_ = 0; for (int i = 0; i < descriptor->field_count(); i++) { if (descriptor->field(i)->is_required()) { ++num_required_fields_; } } - parse_function_generator_.reset(new ParseFunctionGenerator( + parse_function_generator_ = std::make_unique<ParseFunctionGenerator>( descriptor_, max_has_bit_index_, has_bit_indices_, - inlined_string_indices_, options_, scc_analyzer_, variables_)); + inlined_string_indices_, options_, scc_analyzer_, variables_); } -MessageGenerator::~MessageGenerator() = default; - size_t MessageGenerator::HasBitsSize() const { return (max_has_bit_index_ + 31) / 32; } @@ -739,94 +622,131 @@ void MessageGenerator::AddGenerators( std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators) { for (int i = 0; i < descriptor_->enum_type_count(); i++) { enum_generators->emplace_back( - new EnumGenerator(descriptor_->enum_type(i), variables_, options_)); + std::make_unique<EnumGenerator>(descriptor_->enum_type(i), options_)); enum_generators_.push_back(enum_generators->back().get()); } for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators->emplace_back(new ExtensionGenerator( + extension_generators->emplace_back(std::make_unique<ExtensionGenerator>( descriptor_->extension(i), options_, scc_analyzer_)); extension_generators_.push_back(extension_generators->back().get()); } } -void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* p) { + auto v = p->WithVars(MessageVars(descriptor_)); + Formatter format(p); + // optimized_fields_ does not contain fields where // field->real_containing_oneof() // so we need to iterate over those as well. // // We place the non-oneof fields in optimized_order_, as that controls the - // order of the _has_bits_ entries and we want GDB's pretty printers to be + // order of the _has_bits_ entries and we want GDB's pretty ps to be // able to infer these indices from the k[FIELDNAME]FieldNumber order. std::vector<const FieldDescriptor*> ordered_fields; ordered_fields.reserve(descriptor_->field_count()); - ordered_fields.insert(ordered_fields.begin(), optimized_order_.begin(), optimized_order_.end()); + for (auto field : FieldRange(descriptor_)) { - if (!field->real_containing_oneof() && !field->options().weak() && - !IsFieldStripped(field, options_)) { + if (!field->real_containing_oneof() && !field->options().weak()) { continue; } ordered_fields.push_back(field); } if (!ordered_fields.empty()) { - format("enum : int {\n"); - for (auto field : ordered_fields) { - Formatter::SaveState save(&format); - - std::map<TProtoStringType, TProtoStringType> vars; - SetCommonFieldVariables(field, &vars, options_); - format.AddMap(vars); - format(" ${1$$2$$}$ = $number$,\n", field, FieldConstantName(field)); - } - format("};\n"); + p->Emit({{ + "kFields", + [&] { + for (auto field : ordered_fields) { + auto v = p->WithVars(FieldVars(field, options_)); + p->Emit({Sub("kField", FieldConstantName(field)) + .AnnotatedAs(field)}, + R"cc( + $kField$ = $number$, + )cc"); + } + }, + }}, + R"cc( + enum : int { + $kFields$, + }; + )cc"); } for (auto field : ordered_fields) { - PrintFieldComment(format, field); - - Formatter::SaveState save(&format); - - std::map<TProtoStringType, TProtoStringType> vars; - SetCommonFieldVariables(field, &vars, options_); - format.AddMap(vars); - - if (field->is_repeated()) { - format("$deprecated_attr$int ${1$$name$_size$}$() const$2$\n", field, - !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}"); - if (!IsFieldStripped(field, options_)) { - format( - "private:\n" - "int ${1$_internal_$name$_size$}$() const;\n" - "public:\n", - field); - } - } else if (HasHasMethod(field)) { - format("$deprecated_attr$bool ${1$has_$name$$}$() const$2$\n", field, - !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}"); - if (!IsFieldStripped(field, options_)) { - format( - "private:\n" - "bool _internal_has_$name$() const;\n" - "public:\n"); - } - } else if (HasPrivateHasMethod(field)) { - if (!IsFieldStripped(field, options_)) { - format( - "private:\n" - "bool ${1$_internal_has_$name$$}$() const;\n" - "public:\n", - field); - } - } - format("$deprecated_attr$void ${1$clear_$name$$}$()$2$\n", field, - !IsFieldStripped(field, options_) ? ";" : "{__builtin_trap();}"); - - // Generate type-specific accessor declarations. - field_generators_.get(field).GenerateAccessorDeclarations(printer); - - format("\n"); + auto name = FieldName(field); + + auto v = p->WithVars(FieldVars(field, options_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_)); + p->Emit( + {{"field_comment", FieldComment(field)}, + Sub("const_impl", "const;").WithSuffix(";"), + Sub("impl", ";").WithSuffix(";"), + {"sizer", + [&] { + if (!field->is_repeated()) return; + p->Emit({Sub("name_size", y_absl::StrCat(name, "_size")) + .AnnotatedAs(field)}, + R"cc( + $deprecated_attr $int $name_size$() $const_impl$; + )cc"); + + p->Emit({Sub("_internal_name_size", + y_absl::StrCat("_internal_", name, "_size")) + .AnnotatedAs(field)}, + R"cc( + private: + int $_internal_name_size$() const; + + public: + )cc"); + }}, + {"hazzer", + [&] { + if (!field->has_presence()) return; + p->Emit({Sub("has_name", y_absl::StrCat("has_", name)) + .AnnotatedAs(field)}, + R"cc( + $deprecated_attr $bool $has_name$() $const_impl$; + )cc"); + }}, + {"internal_hazzer", + [&] { + if (field->is_repeated() || !HasInternalHasMethod(field)) { + return; + } + p->Emit( + {Sub("_internal_has_name", y_absl::StrCat("_internal_has_", name)) + .AnnotatedAs(field)}, + R"cc( + private: + bool $_internal_has_name$() const; + + public: + )cc"); + }}, + {"clearer", + [&] { + p->Emit({Sub("clear_name", y_absl::StrCat("clear_", name)) + .AnnotatedAs(field)}, + R"cc( + $deprecated_attr $void $clear_name$() $impl$; + )cc"); + }}, + {"accessors", + [&] { + field_generators_.get(field).GenerateAccessorDeclarations(p); + }}}, + R"cc( + // $field_comment$ + $sizer$; + $hazzer$; + $internal_hazzer$; + $clearer$; + $accessors$; + )cc"); } if (descriptor_->extension_range_count() > 0) { @@ -839,211 +759,195 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { // For similar reason, we use "_field_type" and "_is_packed" as parameter // names below, so that "field_type" and "is_packed" can be used as field // names. - format(R"( -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline bool HasExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { -$annotate_extension_has$ - return $extensions$.Has(id.number()); -} + p->Emit(R"cc( + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline bool HasExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) const { + $annotate_extension_has$; + return $extensions$.Has(id.number()); + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline void ClearExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { - $extensions$.ClearExtension(id.number()); -$annotate_extension_clear$ -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline void ClearExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) { + $extensions$.ClearExtension(id.number()); + $annotate_extension_clear$; + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline int ExtensionSize( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { -$annotate_extension_repeated_size$ - return $extensions$.ExtensionSize(id.number()); -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline int ExtensionSize( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) const { + $annotate_extension_repeated_size$; + return $extensions$.ExtensionSize(id.number()); + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline typename _proto_TypeTraits::Singular::ConstType GetExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { -$annotate_extension_get$ - return _proto_TypeTraits::Get(id.number(), $extensions$, - id.default_value()); -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline typename _proto_TypeTraits::Singular::ConstType GetExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) const { + $annotate_extension_get$; + return _proto_TypeTraits::Get(id.number(), $extensions$, id.default_value()); + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline typename _proto_TypeTraits::Singular::MutableType MutableExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { -$annotate_extension_mutable$ - return _proto_TypeTraits::Mutable(id.number(), _field_type, - &$extensions$); -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline typename _proto_TypeTraits::Singular::MutableType MutableExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) { + $annotate_extension_mutable$; + return _proto_TypeTraits::Mutable(id.number(), _field_type, &$extensions$); + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline void SetExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, - typename _proto_TypeTraits::Singular::ConstType value) { - _proto_TypeTraits::Set(id.number(), _field_type, value, &$extensions$); -$annotate_extension_set$ -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline void SetExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id, + typename _proto_TypeTraits::Singular::ConstType value) { + _proto_TypeTraits::Set(id.number(), _field_type, value, &$extensions$); + $annotate_extension_set$; + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline void SetAllocatedExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, - typename _proto_TypeTraits::Singular::MutableType value) { - _proto_TypeTraits::SetAllocated(id.number(), _field_type, value, - &$extensions$); -$annotate_extension_set$ -} -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline void UnsafeArenaSetAllocatedExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, - typename _proto_TypeTraits::Singular::MutableType value) { - _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type, - value, &$extensions$); -$annotate_extension_set$ -} -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -PROTOBUF_NODISCARD inline - typename _proto_TypeTraits::Singular::MutableType - ReleaseExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { -$annotate_extension_release$ - return _proto_TypeTraits::Release(id.number(), _field_type, - &$extensions$); -} -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline typename _proto_TypeTraits::Singular::MutableType -UnsafeArenaReleaseExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { -$annotate_extension_release$ - return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type, - &$extensions$); -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline void SetAllocatedExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id, + typename _proto_TypeTraits::Singular::MutableType value) { + _proto_TypeTraits::SetAllocated(id.number(), _field_type, value, + &$extensions$); + $annotate_extension_set$; + } + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline void UnsafeArenaSetAllocatedExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id, + typename _proto_TypeTraits::Singular::MutableType value) { + _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type, + value, &$extensions$); + $annotate_extension_set$; + } + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + PROTOBUF_NODISCARD inline + typename _proto_TypeTraits::Singular::MutableType + ReleaseExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) { + $annotate_extension_release$; + return _proto_TypeTraits::Release(id.number(), _field_type, &$extensions$); + } + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline typename _proto_TypeTraits::Singular::MutableType + UnsafeArenaReleaseExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) { + $annotate_extension_release$; + return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type, + &$extensions$); + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline typename _proto_TypeTraits::Repeated::ConstType GetExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, - int index) const { -$annotate_repeated_extension_get$ - return _proto_TypeTraits::Get(id.number(), $extensions$, index); -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline typename _proto_TypeTraits::Repeated::ConstType GetExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id, + int index) const { + $annotate_repeated_extension_get$; + return _proto_TypeTraits::Get(id.number(), $extensions$, index); + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, - int index) { -$annotate_repeated_extension_mutable$ - return _proto_TypeTraits::Mutable(id.number(), index, &$extensions$); -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id, + int index) { + $annotate_repeated_extension_mutable$; + return _proto_TypeTraits::Mutable(id.number(), index, &$extensions$); + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline void SetExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, - int index, typename _proto_TypeTraits::Repeated::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &$extensions$); -$annotate_repeated_extension_set$ -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline void SetExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id, + int index, typename _proto_TypeTraits::Repeated::ConstType value) { + _proto_TypeTraits::Set(id.number(), index, value, &$extensions$); + $annotate_repeated_extension_set$; + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline typename _proto_TypeTraits::Repeated::MutableType AddExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { - typename _proto_TypeTraits::Repeated::MutableType to_add = - _proto_TypeTraits::Add(id.number(), _field_type, &$extensions$); -$annotate_repeated_extension_add_mutable$ - return to_add; -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline typename _proto_TypeTraits::Repeated::MutableType AddExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) { + typename _proto_TypeTraits::Repeated::MutableType to_add = + _proto_TypeTraits::Add(id.number(), _field_type, &$extensions$); + $annotate_repeated_extension_add_mutable$; + return to_add; + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline void AddExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, - typename _proto_TypeTraits::Repeated::ConstType value) { - _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value, - &$extensions$); -$annotate_repeated_extension_add$ -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline void AddExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id, + typename _proto_TypeTraits::Repeated::ConstType value) { + _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value, + &$extensions$); + $annotate_repeated_extension_add$; + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType& -GetRepeatedExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { -$annotate_repeated_extension_list$ - return _proto_TypeTraits::GetRepeated(id.number(), $extensions$); -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType& + GetRepeatedExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) const { + $annotate_repeated_extension_list$; + return _proto_TypeTraits::GetRepeated(id.number(), $extensions$); + } -template <typename _proto_TypeTraits, - ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, - bool _is_packed> -inline typename _proto_TypeTraits::Repeated::RepeatedFieldType* -MutableRepeatedExtension( - const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< - $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { -$annotate_repeated_extension_list_mutable$ - return _proto_TypeTraits::MutableRepeated(id.number(), _field_type, - _is_packed, &$extensions$); -} + template <typename _proto_TypeTraits, $pbi$::FieldType _field_type, + bool _is_packed> + inline typename _proto_TypeTraits::Repeated::RepeatedFieldType* + MutableRepeatedExtension( + const $pbi$::ExtensionIdentifier<$Msg$, _proto_TypeTraits, + _field_type, _is_packed>& id) { + $annotate_repeated_extension_list_mutable$; + return _proto_TypeTraits::MutableRepeated(id.number(), _field_type, + _is_packed, &$extensions$); + } + )cc"); -)"); // Generate MessageSet specific APIs for proto2 MessageSet. // For testing purposes we don't check for bridge.MessageSet, so // we don't use IsProto2MessageSet if (descriptor_->options().message_set_wire_format() && !options_.opensource_runtime && !options_.lite_implicit_weak_fields) { - // Special-case MessageSet - format("GOOGLE_PROTOBUF_EXTENSION_MESSAGE_SET_ACCESSORS($classname$)\n"); + // Special-case MessageSet. + p->Emit(R"cc( + GOOGLE_PROTOBUF_EXTENSION_MESSAGE_SET_ACCESSORS($Msg$); + )cc"); } } for (auto oneof : OneOfRange(descriptor_)) { Formatter::SaveState saver(&format); - format.Set("oneof_name", oneof->name()); - format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)); + auto v = p->WithVars({ + {"oneof_name", oneof->name()}, + {"camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)}, + }); format( "void ${1$clear_$oneof_name$$}$();\n" "$camel_oneof_name$Case $oneof_name$_case() const;\n", @@ -1052,13 +956,9 @@ $annotate_repeated_extension_list_mutable$ } void MessageGenerator::GenerateSingularFieldHasBits( - const FieldDescriptor* field, Formatter format) { - if (IsFieldStripped(field, options_)) { - format( - "inline bool $classname$::has_$name$() const { " - "__builtin_trap(); }\n"); - return; - } + const FieldDescriptor* field, io::Printer* p) { + auto t = p->WithVars(MakeTrackerCalls(field, options_)); + Formatter format(p); if (field->options().weak()) { format( "inline bool $classname$::has_$name$() const {\n" @@ -1069,15 +969,13 @@ void MessageGenerator::GenerateSingularFieldHasBits( } if (HasHasbit(field)) { int has_bit_index = HasBitIndex(field); - GOOGLE_CHECK_NE(has_bit_index, kNoHasbit); + Y_ABSL_CHECK_NE(has_bit_index, kNoHasbit); - format.Set("has_array_index", has_bit_index / 32); - format.Set("has_mask", - strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + auto v = p->WithVars(HasbitVars(has_bit_index)); format( - "inline bool $classname$::_internal_has_$name$() const {\n" - " bool value = " - "($has_bits$[$has_array_index$] & 0x$has_mask$u) != 0;\n"); + "inline bool $classname$::has_$name$() const {\n" + "$annotate_has$" + " bool value = ($has_bits$[$has_array_index$] & $has_mask$) != 0;\n"); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && !IsLazy(field, options_, scc_analyzer_)) { @@ -1089,10 +987,6 @@ void MessageGenerator::GenerateSingularFieldHasBits( format( " return value;\n" - "}\n" - "inline bool $classname$::has_$name$() const {\n" - "$annotate_has$" - " return _internal_has_$name$();\n" "}\n"); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { // Message fields have a has_$name$() method. @@ -1116,12 +1010,14 @@ void MessageGenerator::GenerateSingularFieldHasBits( } } -void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) { - Formatter format(printer, variables_); - for (auto oneof : OneOfRange(descriptor_)) { - format.Set("oneof_name", oneof->name()); - format.Set("oneof_index", oneof->index()); - format.Set("cap_oneof_name", ToUpper(oneof->name())); +void MessageGenerator::GenerateOneofHasBits(io::Printer* p) { + Formatter format(p); + for (const auto* oneof : OneOfRange(descriptor_)) { + auto v = p->WithVars({ + {"oneof_index", oneof->index()}, + {"oneof_name", oneof->name()}, + {"cap_oneof_name", y_absl::AsciiStrToUpper(oneof->name())}, + }); format( "inline bool $classname$::has_$oneof_name$() const {\n" " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" @@ -1133,40 +1029,24 @@ void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) { } void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, - const Formatter& format) { - if (IsFieldStripped(field, options_)) { - if (HasHasMethod(field)) { - format( - "inline bool $classname$::has_$name$() const { " - "__builtin_trap(); }\n"); - } - format( - "inline void $classname$::set_has_$name$() { __builtin_trap(); " - "}\n"); - return; - } + io::Printer* p) { + auto t = p->WithVars(MakeTrackerCalls(field, options_)); + Formatter format(p); // Singular field in a oneof // N.B.: Without field presence, we do not use has-bits or generate // has_$name$() methods, but oneofs still have set_has_$name$(). - // Oneofs also have has_$name$() but only as a private helper - // method, so that generated code is slightly cleaner (vs. comparing - // _oneof_case_[index] against a constant everywhere). - // - // If has_$name$() is private, there is no need to add an internal accessor. - // Only annotate public accessors. + // Oneofs also have private _internal_has_$name$() a helper method. if (HasHasMethod(field)) { format( - "inline bool $classname$::_internal_has_$name$() const {\n" - " return $oneof_name$_case() == k$field_name$;\n" - "}\n" "inline bool $classname$::has_$name$() const {\n" "$annotate_has$" - " return _internal_has_$name$();\n" + " return $has_field$;\n" "}\n"); - } else if (HasPrivateHasMethod(field)) { + } + if (HasInternalHasMethod(field)) { format( "inline bool $classname$::_internal_has_$name$() const {\n" - " return $oneof_name$_case() == k$field_name$;\n" + " return $has_field$;\n" "}\n"); } // set_has_$name$() for oneof fields is always private; hence should not be @@ -1178,11 +1058,9 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, } void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, - bool is_inline, Formatter format) { - if (IsFieldStripped(field, options_)) { - format("void $classname$::clear_$name$() { __builtin_trap(); }\n"); - return; - } + bool is_inline, io::Printer* p) { + auto t = p->WithVars(MakeTrackerCalls(field, options_)); + Formatter format(p); // Generate clear_$name$(). if (is_inline) { @@ -1195,9 +1073,10 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, if (field->real_containing_oneof()) { // Clear this field only if it is the active field in this oneof, // otherwise ignore - format("if (_internal_has_$name$()) {\n"); + auto t = p->WithVars(MakeTrackerCalls(field, options_)); + format("if ($has_field$) {\n"); format.Indent(); - field_generators_.get(field).GenerateClearingCode(format.printer()); + field_generators_.get(field).GenerateClearingCode(p); format("clear_has_$oneof_name$();\n"); format.Outdent(); format("}\n"); @@ -1205,13 +1084,11 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, if (ShouldSplit(field, options_)) { format("if (IsSplitMessageDefault()) return;\n"); } - field_generators_.get(field).GenerateClearingCode(format.printer()); + field_generators_.get(field).GenerateClearingCode(p); if (HasHasbit(field)) { int has_bit_index = HasBitIndex(field); - format.Set("has_array_index", has_bit_index / 32); - format.Set("has_mask", - strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); - format("$has_bits$[$has_array_index$] &= ~0x$has_mask$u;\n"); + auto v = p->WithVars(HasbitVars(has_bit_index)); + format("$has_bits$[$has_array_index$] &= ~$has_mask$;\n"); } } format("$annotate_clear$"); @@ -1219,81 +1096,60 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, format("}\n"); } -void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* p) { + Formatter format(p); format("// $classname$\n\n"); for (auto field : FieldRange(descriptor_)) { PrintFieldComment(format, field); - if (IsFieldStripped(field, options_)) { - continue; - } - - std::map<TProtoStringType, TProtoStringType> vars; - SetCommonFieldVariables(field, &vars, options_); - - Formatter::SaveState saver(&format); - format.AddMap(vars); - + auto v = p->WithVars(FieldVars(field, options_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_)); // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { - if (IsFieldStripped(field, options_)) { - format( - "inline int $classname$::$name$_size() const { " - "__builtin_trap(); }\n"); - } else { - format( - "inline int $classname$::_internal_$name$_size() const {\n" - " return $field$$1$.size();\n" - "}\n" - "inline int $classname$::$name$_size() const {\n" - "$annotate_size$" - " return _internal_$name$_size();\n" - "}\n", - IsImplicitWeakField(field, options_, scc_analyzer_) && - field->message_type() - ? ".weak" - : ""); - } + format( + "inline int $classname$::_internal_$name$_size() const {\n" + " return $field$$1$.size();\n" + "}\n" + "inline int $classname$::$name$_size() const {\n" + "$annotate_size$" + " return _internal_$name$_size();\n" + "}\n", + IsImplicitWeakField(field, options_, scc_analyzer_) && + field->message_type() + ? ".weak" + : ""); } else if (field->real_containing_oneof()) { - format.Set("field_name", UnderscoresToCamelCase(field->name(), true)); - format.Set("oneof_name", field->containing_oneof()->name()); - format.Set("oneof_index", - StrCat(field->containing_oneof()->index())); - GenerateOneofMemberHasBits(field, format); + GenerateOneofMemberHasBits(field, p); } else { // Singular field. - GenerateSingularFieldHasBits(field, format); + GenerateSingularFieldHasBits(field, p); } if (!IsCrossFileMaybeMap(field)) { - GenerateFieldClear(field, true, format); + GenerateFieldClear(field, true, p); } - // Generate type-specific accessors. - if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateInlineAccessorDefinitions(printer); - } + field_generators_.get(field).GenerateInlineAccessorDefinitions(p); format("\n"); } // Generate has_$name$() and clear_has_$name$() functions for oneofs. - GenerateOneofHasBits(printer); + GenerateOneofHasBits(p); } -void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { - Formatter format(printer, variables_); - format.Set("class_final", - ShouldMarkClassAsFinal(descriptor_, options_) ? "final" : ""); +void MessageGenerator::GenerateClassDefinition(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); + Formatter format(p); if (IsMapEntryMessage(descriptor_)) { - std::map<TProtoStringType, TProtoStringType> vars; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars; CollectMapInfo(options_, descriptor_, &vars); vars["lite"] = HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite"; - format.AddMap(vars); + auto v = p->WithVars(std::move(vars)); format( "class $classname$ : public " "::$proto_ns$::internal::MapEntry$lite$<$classname$, \n" @@ -1314,7 +1170,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { " static const $classname$* internal_default_instance() { return " "reinterpret_cast<const " "$classname$*>(&_$classname$_default_instance_); }\n"); - auto utf8_check = GetUtf8CheckMode(descriptor_->field(0), options_); + auto utf8_check = internal::cpp::GetUtf8CheckMode( + descriptor_->field(0), GetOptimizeFor(descriptor_->file(), options_) == + FileOptions::LITE_RUNTIME); if (descriptor_->field(0)->type() == FieldDescriptor::TYPE_STRING && utf8_check != Utf8CheckMode::kNone) { if (utf8_check == Utf8CheckMode::kStrict) { @@ -1326,7 +1184,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { " }\n", descriptor_->field(0)->full_name()); } else { - GOOGLE_CHECK(utf8_check == Utf8CheckMode::kVerify); + Y_ABSL_CHECK(utf8_check == Utf8CheckMode::kVerify); format( " static bool ValidateKey(TProtoStringType* s) {\n" "#ifndef NDEBUG\n" @@ -1355,7 +1213,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { " }\n", descriptor_->field(1)->full_name()); } else { - GOOGLE_CHECK(utf8_check == Utf8CheckMode::kVerify); + Y_ABSL_CHECK(utf8_check == Utf8CheckMode::kVerify); format( " static bool ValidateValue(TProtoStringType* s) {\n" "#ifndef NDEBUG\n" @@ -1386,25 +1244,14 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { } format( - "class $dllexport_decl $${1$$classname$$}$$ class_final$ :\n" + "class $dllexport_decl $${1$$classname$$}$ final :\n" " public $superclass$ /* @@protoc_insertion_point(" "class_definition:$full_name$) */ {\n", descriptor_); format(" public:\n"); format.Indent(); - if (EnableMessageOwnedArena(descriptor_, options_)) { - format( - "inline $classname$() : $classname$(" - "::$proto_ns$::Arena::InternalCreateMessageOwnedArena(), true) {}\n"); - } else if (EnableMessageOwnedArenaTrial(descriptor_, options_)) { - format( - "inline $classname$() : $classname$(InMoaTrial() ? " - "::$proto_ns$::Arena::InternalCreateMessageOwnedArena() : nullptr, " - "InMoaTrial()) {}\n"); - } else { - format("inline $classname$() : $classname$(nullptr) {}\n"); - } + format("inline $classname$() : $classname$(nullptr) {}\n"); if (!HasSimpleBaseClass(descriptor_, options_)) { format("~$classname$() override;\n"); } @@ -1489,7 +1336,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { format("$1$ = $2$,\n", OneofCaseConstantName(field), // 1 field->number()); // 2 } - format("$1$_NOT_SET = 0,\n", ToUpper(oneof->name())); + format("$1$_NOT_SET = 0,\n", y_absl::AsciiStrToUpper(oneof->name())); format.Outdent(); format( "};\n" @@ -1518,8 +1365,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { " return $any_metadata$.PackFrom(GetArena(), message);\n" "}\n" "bool PackFrom(const ::$proto_ns$::Message& message,\n" - " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " - "type_url_prefix) {\n" + " ::y_absl::string_view type_url_prefix) {\n" " $DCHK$_NE(&message, this);\n" " return $any_metadata$.PackFrom(GetArena(), message, " "type_url_prefix);\n" @@ -1541,8 +1387,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "!std::is_convertible<T, const ::$proto_ns$::Message&>" "::value>::type>\n" "bool PackFrom(const T& message,\n" - " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " - "type_url_prefix) {\n" + " ::y_absl::string_view type_url_prefix) {\n" " return $any_metadata$.PackFrom<T>(GetArena(), message, " "type_url_prefix);" "}\n" @@ -1560,8 +1405,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "}\n" "template <typename T>\n" "bool PackFrom(const T& message,\n" - " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " - "type_url_prefix) {\n" + " ::y_absl::string_view type_url_prefix) {\n" " return $any_metadata$.PackFrom(GetArena(), message, " "type_url_prefix);\n" "}\n" @@ -1574,8 +1418,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "template<typename T> bool Is() const {\n" " return $any_metadata$.Is<T>();\n" "}\n" - "static bool ParseAnyTypeUrl(::PROTOBUF_NAMESPACE_ID::ConstStringParam " - "type_url,\n" + "static bool ParseAnyTypeUrl(::y_absl::string_view type_url,\n" " TProtoStringType* full_type_name);\n"); } @@ -1612,9 +1455,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // For instances that derive from Message (rather than MessageLite), some // methods are virtual and should be marked as final. - format.Set("full_final", HasDescriptorMethods(descriptor_->file(), options_) - ? "final" - : ""); + auto v2 = p->WithVars( + {{"full_final", + HasDescriptorMethods(descriptor_->file(), options_) ? "final" : ""}}); if (HasGeneratedMethods(descriptor_->file(), options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { @@ -1662,9 +1505,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;\n" "bool IsInitialized() const final;\n" "\n" - "size_t ByteSizeLong() const final;\n"); + "::size_t ByteSizeLong() const final;\n"); - parse_function_generator_->GenerateMethodDecls(printer); + parse_function_generator_->GenerateMethodDecls(p); format( "$uint8$* _InternalSerialize(\n" @@ -1683,7 +1526,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "int GetCachedSize() const final { return " "$cached_size$.Get(); }" "\n\nprivate:\n" - "void SharedCtor(::$proto_ns$::Arena* arena, bool is_message_owned);\n" + "void SharedCtor(::$proto_ns$::Arena* arena);\n" "void SharedDtor();\n" "void SetCachedSize(int size) const$ full_final$;\n" "void InternalSwap($classname$* other);\n"); @@ -1693,19 +1536,16 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // Friend AnyMetadata so that it can call this FullMessageName() method. "\nprivate:\n" "friend class ::$proto_ns$::internal::AnyMetadata;\n" - "static $1$ FullMessageName() {\n" + "static ::y_absl::string_view FullMessageName() {\n" " return \"$full_name$\";\n" - "}\n", - options_.opensource_runtime ? "::PROTOBUF_NAMESPACE_ID::StringPiece" - : "::StringPiece"); + "}\n"); format( // TODO(gerbens) Make this private! Currently people are deriving from // protos to give access to this constructor, breaking the invariants // we rely on. "protected:\n" - "explicit $classname$(::$proto_ns$::Arena* arena,\n" - " bool is_message_owned = false);\n"); + "explicit $classname$(::$proto_ns$::Arena* arena);\n"); switch (NeedsArenaDestructor()) { case ArenaDtorNeeds::kOnDemand: @@ -1758,7 +1598,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { format( "private:\n" "inline bool IsSplitMessageDefault() const {\n" - " return $split$ == reinterpret_cast<Impl_::Split*>(&$1$);\n" + " return $split$ == reinterpret_cast<const Impl_::Split*>(&$1$);\n" "}\n" "PROTOBUF_NOINLINE void PrepareSplitMessageForWrite();\n" "public:\n", @@ -1773,8 +1613,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { const Descriptor* nested_type = descriptor_->nested_type(i); if (!IsMapEntryMessage(nested_type)) { - format.Set("nested_full_name", ClassName(nested_type, false)); - format.Set("nested_name", ResolveKeyword(nested_type->name())); + auto v = + p->WithVars({{"nested_full_name", ClassName(nested_type, false)}, + {"nested_name", ResolveKeyword(nested_type->name())}}); format("typedef ${1$$nested_full_name$$}$ ${1$$nested_name$$}$;\n", nested_type); } @@ -1787,7 +1628,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // Import all nested enums and their values into this class's scope with // typedefs and constants. for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateSymbolImports(printer); + enum_generators_[i]->GenerateSymbolImports(p); format("\n"); } @@ -1796,11 +1637,11 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "\n"); // Generate accessor methods for all fields. - GenerateFieldAccessorDeclarations(printer); + GenerateFieldAccessorDeclarations(p); // Declare extension identifiers. for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators_[i]->GenerateDeclaration(printer); + extension_generators_[i]->GenerateDeclaration(p); } @@ -1835,11 +1676,11 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { num_required_fields_ > 1) { format( "// helper for ByteSizeLong()\n" - "size_t RequiredFieldsByteSizeFallback() const;\n\n"); + "::size_t RequiredFieldsByteSizeFallback() const;\n\n"); } if (HasGeneratedMethods(descriptor_->file(), options_)) { - parse_function_generator_->GenerateDataDecls(printer); + parse_function_generator_->GenerateDataDecls(p); } // Prepare decls for _cached_size_ and _has_bits_. Their position in the @@ -1852,7 +1693,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { const size_t sizeof_has_bits = HasBitsSize(); const TProtoStringType has_bits_decl = sizeof_has_bits == 0 ? "" - : StrCat("::$proto_ns$::internal::HasBits<", + : y_absl::StrCat("::$proto_ns$::internal::HasBits<", sizeof_has_bits, "> _has_bits_;\n"); format( @@ -1907,10 +1748,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // Emit some private and static members for (auto field : optimized_order_) { - const FieldGenerator& generator = field_generators_.get(field); - generator.GenerateStaticMembers(printer); + field_generators_.get(field).GenerateStaticMembers(p); if (!ShouldSplit(field, options_)) { - generator.GeneratePrivateMembers(printer); + field_generators_.get(field).GeneratePrivateMembers(p); } } if (ShouldSplit(descriptor_, options_)) { @@ -1918,14 +1758,15 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { format.Indent(); for (auto field : optimized_order_) { if (!ShouldSplit(field, options_)) continue; - const FieldGenerator& generator = field_generators_.get(field); - generator.GeneratePrivateMembers(printer); + field_generators_.get(field).GeneratePrivateMembers(p); } format.Outdent(); format( " typedef void InternalArenaConstructable_;\n" " typedef void DestructorSkippable_;\n" "};\n" + "static_assert(std::is_trivially_copy_constructible<Split>::value);\n" + "static_assert(std::is_trivially_destructible<Split>::value);\n" "Split* _split_;\n"); } @@ -1941,16 +1782,12 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { " ::$proto_ns$::internal::ConstantInitialized _constinit_;\n", camel_oneof_name); for (auto field : FieldRange(oneof)) { - if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GeneratePrivateMembers(printer); - } + field_generators_.get(field).GeneratePrivateMembers(p); } format.Outdent(); format("} $1$_;\n", oneof->name()); for (auto field : FieldRange(oneof)) { - if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateStaticMembers(printer); - } + field_generators_.get(field).GenerateStaticMembers(p); } } @@ -1986,9 +1823,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { } if (ShouldSplit(descriptor_, options_)) { - format( - "static Impl_::Split* CreateSplitMessage(" - "::$proto_ns$::Arena* arena);\n"); format("friend struct $1$;\n", DefaultInstanceType(descriptor_, options_, /*split=*/true)); } @@ -1999,19 +1833,23 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { format.Outdent(); format("};"); - GOOGLE_DCHECK(!need_to_emit_cached_size); + Y_ABSL_DCHECK(!need_to_emit_cached_size); } // NOLINT(readability/fn_size) -void MessageGenerator::GenerateInlineMethods(io::Printer* printer) { +void MessageGenerator::GenerateInlineMethods(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); if (IsMapEntryMessage(descriptor_)) return; - GenerateFieldAccessorDefinitions(printer); + GenerateFieldAccessorDefinitions(p); // Generate oneof_case() functions. for (auto oneof : OneOfRange(descriptor_)) { - Formatter format(printer, variables_); - format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)); - format.Set("oneof_name", oneof->name()); - format.Set("oneof_index", oneof->index()); + Formatter format(p); + auto v = p->WithVars({ + {"camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)}, + {"oneof_name", oneof->name()}, + {"oneof_index", oneof->index()}, + }); format( "inline $classname$::$camel_oneof_name$Case $classname$::" "${1$$oneof_name$_case$}$() const {\n" @@ -2022,9 +1860,11 @@ void MessageGenerator::GenerateInlineMethods(io::Printer* printer) { } } -void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, +void MessageGenerator::GenerateSchema(io::Printer* p, int offset, int has_offset) { - Formatter format(printer, variables_); + auto v = p->WithVars(ClassVars(descriptor_, options_)); + auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); + Formatter format(p); has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor_) ? offset + has_offset : -1; @@ -2032,17 +1872,18 @@ void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, if (inlined_string_indices_.empty()) { inlined_string_indices_offset = -1; } else { - GOOGLE_DCHECK_NE(has_offset, -1); - GOOGLE_DCHECK(!IsMapEntryMessage(descriptor_)); + Y_ABSL_DCHECK_NE(has_offset, -1); + Y_ABSL_DCHECK(!IsMapEntryMessage(descriptor_)); inlined_string_indices_offset = has_offset + has_bit_indices_.size(); } - format("{ $1$, $2$, $3$, sizeof($classtype$)},\n", offset, has_offset, inlined_string_indices_offset); } -void MessageGenerator::GenerateClassMethods(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateClassMethods(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); + Formatter format(p); if (IsMapEntryMessage(descriptor_)) { format( "$classname$::$classname$() {}\n" @@ -2087,7 +1928,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { } format( "bool $classname$::ParseAnyTypeUrl(\n" - " ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,\n" + " ::y_absl::string_view type_url,\n" " TProtoStringType* full_type_name) {\n" " return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);\n" "}\n" @@ -2101,16 +1942,21 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { if (!has_bit_indices_.empty()) { format( "using HasBits = " - "decltype(std::declval<$classname$>().$has_bits$);\n"); + "decltype(std::declval<$classname$>().$has_bits$);\n" + "static constexpr ::arc_i32 kHasBitsOffset =\n" + " 8 * PROTOBUF_FIELD_OFFSET($classname$, _impl_._has_bits_);\n"); + } + if (descriptor_->real_oneof_decl_count() > 0) { + format( + "static constexpr ::arc_i32 kOneofCaseOffset =\n" + " PROTOBUF_FIELD_OFFSET($classtype$, $oneof_case$);\n"); } for (auto field : FieldRange(descriptor_)) { - field_generators_.get(field).GenerateInternalAccessorDeclarations(printer); - if (IsFieldStripped(field, options_)) { - continue; - } + auto t = p->WithVars(MakeTrackerCalls(field, options_)); + field_generators_.get(field).GenerateInternalAccessorDeclarations(p); if (HasHasbit(field)) { int has_bit_index = HasBitIndex(field); - GOOGLE_CHECK_NE(has_bit_index, kNoHasbit) << field->full_name(); + Y_ABSL_CHECK_NE(has_bit_index, kNoHasbit) << field->full_name(); format( "static void set_has_$1$(HasBits* has_bits) {\n" " (*has_bits)[$2$] |= $3$u;\n" @@ -2131,65 +1977,54 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { format.Outdent(); format("};\n\n"); for (auto field : FieldRange(descriptor_)) { - if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateInternalAccessorDefinitions( - printer); - } + field_generators_.get(field).GenerateInternalAccessorDefinitions(p); } // Generate non-inline field definitions. for (auto field : FieldRange(descriptor_)) { - if (IsFieldStripped(field, options_)) { - continue; - } - field_generators_.get(field).GenerateNonInlineAccessorDefinitions(printer); + auto v = p->WithVars(FieldVars(field, options_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_)); + field_generators_.get(field).GenerateNonInlineAccessorDefinitions(p); if (IsCrossFileMaybeMap(field)) { - Formatter::SaveState saver(&format); - std::map<TProtoStringType, TProtoStringType> vars; - SetCommonFieldVariables(field, &vars, options_); - if (field->real_containing_oneof()) { - SetCommonOneofFieldVariables(field, &vars); - } - format.AddMap(vars); - GenerateFieldClear(field, false, format); + GenerateFieldClear(field, false, p); } } - GenerateStructors(printer); + GenerateStructors(p); format("\n"); if (descriptor_->real_oneof_decl_count() > 0) { - GenerateOneofClear(printer); + GenerateOneofClear(p); format("\n"); } if (HasGeneratedMethods(descriptor_->file(), options_)) { - GenerateClear(printer); + GenerateClear(p); format("\n"); if (!HasSimpleBaseClass(descriptor_, options_)) { - parse_function_generator_->GenerateMethodImpls(printer); + parse_function_generator_->GenerateMethodImpls(p); format("\n"); - parse_function_generator_->GenerateDataDefinitions(printer); + parse_function_generator_->GenerateDataDefinitions(p); } - GenerateSerializeWithCachedSizesToArray(printer); + GenerateSerializeWithCachedSizesToArray(p); format("\n"); - GenerateByteSize(printer); + GenerateByteSize(p); format("\n"); - GenerateMergeFrom(printer); + GenerateMergeFrom(p); format("\n"); - GenerateClassSpecificMergeImpl(printer); + GenerateClassSpecificMergeImpl(p); format("\n"); - GenerateCopyFrom(printer); + GenerateCopyFrom(p); format("\n"); - GenerateIsInitialized(printer); + GenerateIsInitialized(p); format("\n"); } @@ -2197,14 +2032,19 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { format( "void $classname$::PrepareSplitMessageForWrite() {\n" " if (IsSplitMessageDefault()) {\n" - " $split$ = CreateSplitMessage(GetArenaForAllocation());\n" + " void* chunk = " + "::PROTOBUF_NAMESPACE_ID::internal::CreateSplitMessageGeneric(" + "GetArenaForAllocation(), &$1$, sizeof(Impl_::Split), this, &$2$);\n" + " $split$ = reinterpret_cast<Impl_::Split*>(chunk);\n" " }\n" - "}\n"); + "}\n", + DefaultInstanceName(descriptor_, options_, /*split=*/true), + DefaultInstanceName(descriptor_, options_, /*split=*/false)); } - GenerateVerify(printer); + GenerateVerify(p); - GenerateSwap(printer); + GenerateSwap(p); format("\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { @@ -2242,9 +2082,10 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { } } -std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( - io::Printer* printer) { - Formatter format(printer, variables_); +std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); + Formatter format(p); if (!has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)) { format("PROTOBUF_FIELD_OFFSET($classtype$, $has_bits$),\n"); @@ -2274,15 +2115,20 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( } else { format("~0u, // no _inlined_string_donated_\n"); } - const int kNumGenericOffsets = 6; // the number of fixed offsets above + if (ShouldSplit(descriptor_, options_)) { + format( + "PROTOBUF_FIELD_OFFSET($classtype$, $split$),\n" + "sizeof($classtype$::Impl_::Split),\n"); + } else { + format( + "~0u, // no _split_\n" + "~0u, // no sizeof(Split)\n"); + } + const int kNumGenericOffsets = 8; // the number of fixed offsets above const size_t offsets = kNumGenericOffsets + descriptor_->field_count() + descriptor_->real_oneof_decl_count(); size_t entries = offsets; for (auto field : FieldRange(descriptor_)) { - if (IsFieldStripped(field, options_)) { - format("~0u, // stripped\n"); - continue; - } // TODO(sbenza): We should not have an entry in the offset table for fields // that do not use them. if (field->options().weak() || field->real_containing_oneof()) { @@ -2293,7 +2139,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( format("PROTOBUF_FIELD_OFFSET($classtype$$1$, $2$)", ShouldSplit(field, options_) ? "::Impl_::Split" : "", ShouldSplit(field, options_) - ? FieldName(field) + "_" + ? y_absl::StrCat(FieldName(field), "_") : FieldMemberName(field, /*cold=*/false)); } @@ -2302,12 +2148,17 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( // offset of the field, so that the information is available when // reflectively accessing the field at run time. // - // Embed whether the field is eagerly verified lazy or inlined string to the - // LSB of the offset. + // We embed whether the field is cold to the MSB of the offset, and whether + // the field is eagerly verified lazy or inlined string to the LSB of the + // offset. + + if (ShouldSplit(field, options_)) { + format(" | ::_pbi::kSplitFieldOffsetMask /*split*/"); + } if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) { - format(" | 0x1u // eagerly verified lazy\n"); + format(" | 0x1u /*eagerly verified lazy*/"); } else if (IsStringInlined(field, options_)) { - format(" | 0x1u // inlined\n"); + format(" | 0x1u /*inlined*/"); } format(",\n"); } @@ -2317,7 +2168,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( format("PROTOBUF_FIELD_OFFSET($classtype$, _impl_.$1$_),\n", oneof->name()); count++; } - GOOGLE_CHECK_EQ(count, descriptor_->real_oneof_decl_count()); + Y_ABSL_CHECK_EQ(count, descriptor_->real_oneof_decl_count()); if (IsMapEntryMessage(descriptor_)) { entries += 2; @@ -2328,7 +2179,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( entries += has_bit_indices_.size(); for (int i = 0; i < has_bit_indices_.size(); i++) { const TProtoStringType index = - has_bit_indices_[i] >= 0 ? StrCat(has_bit_indices_[i]) : "~0u"; + has_bit_indices_[i] >= 0 ? y_absl::StrCat(has_bit_indices_[i]) : "~0u"; format("$1$,\n", index); } } @@ -2337,7 +2188,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( for (int inlined_string_index : inlined_string_indices_) { const TProtoStringType index = inlined_string_index >= 0 - ? StrCat(inlined_string_index, ", // inlined_string_index") + ? y_absl::StrCat(inlined_string_index, ", // inlined_string_index") : "~0u,"; format("$1$\n", index); } @@ -2346,15 +2197,13 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( return std::make_pair(entries, offsets); } -void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { +void MessageGenerator::GenerateSharedConstructorCode(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); format( - "inline void $classname$::SharedCtor(\n" - " ::_pb::Arena* arena, bool is_message_owned) {\n" - " (void)arena;\n" - " (void)is_message_owned;\n"); + "inline void $classname$::SharedCtor(::_pb::Arena* arena) {\n" + " (void)arena;\n"); format.Indent(); // Impl_ _impl_. @@ -2389,17 +2238,23 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { // Initialize member variables with arena constructor. for (auto field : optimized_order_) { - GOOGLE_DCHECK(!IsFieldStripped(field, options_)); if (ShouldSplit(field, options_)) { continue; } put_sep(); - field_generators_.get(field).GenerateAggregateInitializer(printer); + field_generators_.get(field).GenerateAggregateInitializer(p); } if (ShouldSplit(descriptor_, options_)) { put_sep(); - format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}", - DefaultInstanceName(descriptor_, options_, /*split=*/true)); + // We can't assign the default split to this->split without the const_cast + // because the former is a const. The const_cast is safe because we don't + // intend to modify the default split through this pointer, and we also + // expect the default split to be in the rodata section which is protected + // from mutation. + format( + "decltype($split$){const_cast<Impl_::Split*>" + "(reinterpret_cast<const Impl_::Split*>(&$1$))}", + DefaultInstanceName(descriptor_, options_, /*split=*/true)); } for (auto oneof : OneOfRange(descriptor_)) { put_sep(); @@ -2436,13 +2291,7 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { // is needed. format("if (arena != nullptr) {\n"); if (NeedsArenaDestructor() == ArenaDtorNeeds::kOnDemand) { - format( - " if (!is_message_owned) {\n" - " $inlined_string_donated_array$[0] = ~0u;\n" - " } else {\n" - // We should not register ArenaDtor for MOA. - " $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n" - " }\n"); + format(" $inlined_string_donated_array$[0] = ~0u;\n"); } else { format(" $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n"); } @@ -2457,7 +2306,14 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { if (ShouldSplit(field, options_)) { continue; } - field_generators_.get(field).GenerateConstructorCode(printer); + field_generators_.get(field).GenerateConstructorCode(p); + } + + if (ShouldForceAllocationOnConstruction(descriptor_, options_)) { + format( + "#ifdef PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION\n" + "$mutable_unknown_fields$;\n" + "#endif // PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION\n"); } for (auto oneof : OneOfRange(descriptor_)) { @@ -2468,49 +2324,12 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { format("}\n\n"); } -void MessageGenerator::GenerateCreateSplitMessage(io::Printer* printer) { - Formatter format(printer, variables_); - format( - "$classname$::Impl_::Split* " - "$classname$::CreateSplitMessage(::$proto_ns$::Arena* arena) {\n"); - format.Indent(); - const char* field_sep = " "; - const auto put_sep = [&] { - format("\n$1$ ", field_sep); - field_sep = ","; - }; - format( - "const size_t size = sizeof(Impl_::Split);\n" - "void* chunk = (arena == nullptr) ?\n" - " ::operator new(size) :\n" - " arena->AllocateAligned(size, alignof(Impl_::Split));\n" - "Impl_::Split* ptr = reinterpret_cast<Impl_::Split*>(chunk);\n" - "new (ptr) Impl_::Split{"); - format.Indent(); - for (const FieldDescriptor* field : optimized_order_) { - GOOGLE_DCHECK(!IsFieldStripped(field, options_)); - if (ShouldSplit(field, options_)) { - put_sep(); - field_generators_.get(field).GenerateAggregateInitializer(printer); - } - } - format.Outdent(); - format("};\n"); - for (const FieldDescriptor* field : optimized_order_) { - GOOGLE_DCHECK(!IsFieldStripped(field, options_)); - if (ShouldSplit(field, options_)) { - field_generators_.get(field).GenerateCreateSplitMessageCode(printer); - } - } - format("return ptr;\n"); - format.Outdent(); - format("}\n"); -} - -void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* printer) { +void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* p) { if (!ShouldSplit(descriptor_, options_)) return; - Formatter format(printer, variables_); + auto v = p->WithVars(ClassVars(descriptor_, options_)); + auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); + Formatter format(p); const char* field_sep = " "; const auto put_sep = [&] { format("\n$1$ ", field_sep); @@ -2519,15 +2338,14 @@ void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* printer) { for (const auto* field : optimized_order_) { if (ShouldSplit(field, options_)) { put_sep(); - field_generators_.get(field).GenerateConstexprAggregateInitializer( - printer); + field_generators_.get(field).GenerateConstexprAggregateInitializer(p); } } } -void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { +void MessageGenerator::GenerateSharedDestructorCode(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); format("inline void $classname$::SharedDtor() {\n"); format.Indent(); @@ -2543,7 +2361,7 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { if (ShouldSplit(field, options_)) { continue; } - field_generators_.get(field).GenerateDestructorCode(printer); + field_generators_.get(field).GenerateDestructorCode(p); } if (ShouldSplit(descriptor_, options_)) { format("if (!IsSplitMessageDefault()) {\n"); @@ -2551,7 +2369,7 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { format("auto* $cached_split_ptr$ = $split$;\n"); for (auto field : optimized_order_) { if (ShouldSplit(field, options_)) { - field_generators_.get(field).GenerateDestructorCode(printer); + field_generators_.get(field).GenerateDestructorCode(p); } } format("delete $cached_split_ptr$;\n"); @@ -2586,17 +2404,16 @@ ArenaDtorNeeds MessageGenerator::NeedsArenaDestructor() const { if (HasSimpleBaseClass(descriptor_, options_)) return ArenaDtorNeeds::kNone; ArenaDtorNeeds needs = ArenaDtorNeeds::kNone; for (const auto* field : FieldRange(descriptor_)) { - if (IsFieldStripped(field, options_)) continue; needs = std::max(needs, field_generators_.get(field).NeedsArenaDestructor()); } return needs; } -void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { - GOOGLE_CHECK(NeedsArenaDestructor() > ArenaDtorNeeds::kNone); +void MessageGenerator::GenerateArenaDestructorCode(io::Printer* p) { + Y_ABSL_CHECK(NeedsArenaDestructor() > ArenaDtorNeeds::kNone); - Formatter format(printer, variables_); + Formatter format(p); // Generate the ArenaDtor() method. Track whether any fields actually produced // code that needs to be called. @@ -2611,19 +2428,15 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { // Process non-oneof fields first. for (auto field : optimized_order_) { - if (IsFieldStripped(field, options_) || ShouldSplit(field, options_)) - continue; - const FieldGenerator& fg = field_generators_.get(field); - fg.GenerateArenaDestructorCode(printer); + if (ShouldSplit(field, options_)) continue; + field_generators_.get(field).GenerateArenaDestructorCode(p); } if (ShouldSplit(descriptor_, options_)) { format("if (!_this->IsSplitMessageDefault()) {\n"); format.Indent(); for (auto field : optimized_order_) { - if (IsFieldStripped(field, options_) || !ShouldSplit(field, options_)) - continue; - const FieldGenerator& fg = field_generators_.get(field); - fg.GenerateArenaDestructorCode(printer); + if (!ShouldSplit(field, options_)) continue; + field_generators_.get(field).GenerateArenaDestructorCode(p); } format.Outdent(); format("}\n"); @@ -2632,8 +2445,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { // Process oneof fields. for (auto oneof : OneOfRange(descriptor_)) { for (auto field : FieldRange(oneof)) { - if (IsFieldStripped(field, options_)) continue; - field_generators_.get(field).GenerateArenaDestructorCode(printer); + field_generators_.get(field).GenerateArenaDestructorCode(p); } } @@ -2641,8 +2453,10 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateConstexprConstructor(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); + Formatter format(p); if (IsMapEntryMessage(descriptor_) || !HasImplData(descriptor_, options_)) { format( @@ -2685,12 +2499,11 @@ void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { continue; } put_sep(); - field_generators_.get(field).GenerateConstexprAggregateInitializer( - printer); + field_generators_.get(field).GenerateConstexprAggregateInitializer(p); } if (ShouldSplit(descriptor_, options_)) { put_sep(); - format("/*decltype($split$)*/&$1$._instance", + format("/*decltype($split$)*/const_cast<Impl_::Split*>(&$1$._instance)", DefaultInstanceName(descriptor_, options_, /*split=*/true)); } @@ -2725,8 +2538,8 @@ void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { format("} {}\n"); } -void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { - Formatter format(printer, variables_); +void MessageGenerator::GenerateCopyConstructorBody(io::Printer* p) const { + Formatter format(p); const RunMap runs = FindRuns(optimized_order_, [this](const FieldDescriptor* field) { @@ -2735,20 +2548,14 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { TProtoStringType pod_template = "::memcpy(&$first$, &from.$first$,\n" - " static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n" + " static_cast<::size_t>(reinterpret_cast<char*>(&$last$) -\n" " reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n"; - if (ShouldSplit(descriptor_, options_)) { - format("if (!from.IsSplitMessageDefault()) {\n"); - format.Indent(); - format("_this->PrepareSplitMessageForWrite();\n"); - for (auto field : optimized_order_) { - if (ShouldSplit(field, options_)) { - field_generators_.get(field).GenerateCopyConstructorCode(printer); - } - } - format.Outdent(); - format("}\n"); + if (ShouldForceAllocationOnConstruction(descriptor_, options_)) { + format( + "#ifdef PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION\n" + "$mutable_unknown_fields$;\n" + "#endif // PROTOBUF_FORCE_ALLOCATION_ON_CONSTRUCTION\n"); } for (size_t i = 0; i < optimized_order_.size(); ++i) { @@ -2768,33 +2575,47 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { const TProtoStringType last_field_name = FieldMemberName(optimized_order_[i + run_length - 1], /*cold=*/false); - format.Set("first", first_field_name); - format.Set("last", last_field_name); - + auto v = p->WithVars({ + {"first", first_field_name}, + {"last", last_field_name}, + }); format(pod_template.c_str()); i += run_length - 1; // ++i at the top of the loop. } else { - field_generators_.get(field).GenerateCopyConstructorCode(printer); + field_generators_.get(field).GenerateCopyConstructorCode(p); } } + + if (ShouldSplit(descriptor_, options_)) { + format("if (!from.IsSplitMessageDefault()) {\n"); + format.Indent(); + format("_this->PrepareSplitMessageForWrite();\n"); + // TODO(b/122856539): cache the split pointers. + for (auto field : optimized_order_) { + if (ShouldSplit(field, options_)) { + field_generators_.get(field).GenerateCopyConstructorCode(p); + } + } + format.Outdent(); + format("}\n"); + } } -void MessageGenerator::GenerateStructors(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateStructors(io::Printer* p) { + Formatter format(p); format( - "$classname$::$classname$(::$proto_ns$::Arena* arena,\n" - " bool is_message_owned)\n" - " : $1$(arena, is_message_owned) {\n", + "$classname$::$classname$(::$proto_ns$::Arena* arena)\n" + " : $1$(arena) {\n", SuperClassName(descriptor_, options_)); if (!HasSimpleBaseClass(descriptor_, options_)) { - format(" SharedCtor(arena, is_message_owned);\n"); + format(" SharedCtor(arena);\n"); if (NeedsArenaDestructor() == ArenaDtorNeeds::kRequired) { format( - " if (arena != nullptr && !is_message_owned) {\n" + " if (arena != nullptr) {\n" " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" " }\n"); } @@ -2803,9 +2624,30 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" "}\n"); - std::map<TProtoStringType, TProtoStringType> vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); + // If the message contains only scalar fields (ints and enums), + // then we can copy the entire impl_ section with a single statement. + bool copy_construct_impl = + !ShouldSplit(descriptor_, options_) && + !HasSimpleBaseClass(descriptor_, options_) && + (descriptor_->extension_range_count() == 0 && + descriptor_->real_oneof_decl_count() == 0 && num_weak_fields_ == 0); + for (const auto& field : optimized_order_) { + if (!copy_construct_impl) break; + if (field->is_repeated() || field->is_extension()) { + copy_construct_impl = false; + } else if (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && + field->cpp_type() != FieldDescriptor::CPPTYPE_INT32 && + field->cpp_type() != FieldDescriptor::CPPTYPE_INT64 && + field->cpp_type() != FieldDescriptor::CPPTYPE_UINT32 && + field->cpp_type() != FieldDescriptor::CPPTYPE_UINT64 && + field->cpp_type() != FieldDescriptor::CPPTYPE_FLOAT && + field->cpp_type() != FieldDescriptor::CPPTYPE_DOUBLE && + field->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) { + copy_construct_impl = false; + } else { + // non-repeated integer fields are fine to copy en masse. + } + } // Generate the copy constructor. if (UsingImplicitWeakFields(descriptor_->file(), options_)) { @@ -2818,6 +2660,16 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { " : $classname$() {\n" " MergeFrom(from);\n" "}\n"); + } else if (copy_construct_impl) { + format( + "$classname$::$classname$(const $classname$& from)\n" + " : $superclass$(), _impl_(from._impl_) {\n" + " _internal_metadata_.MergeFrom<$unknown_fields_type$>(\n" + " from._internal_metadata_);\n"); + format( + " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" + "}\n" + "\n"); } else { format( "$classname$::$classname$(const $classname$& from)\n" @@ -2863,12 +2715,14 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { continue; } put_sep(); - field_generators_.get(field).GenerateCopyAggregateInitializer(printer); + field_generators_.get(field).GenerateCopyAggregateInitializer(p); } if (ShouldSplit(descriptor_, options_)) { put_sep(); - format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}", - DefaultInstanceName(descriptor_, options_, /*split=*/true)); + format( + "decltype($split$){const_cast<Impl_::Split*>" + "(reinterpret_cast<const Impl_::Split*>(&$1$))}", + DefaultInstanceName(descriptor_, options_, /*split=*/true)); } for (auto oneof : OneOfRange(descriptor_)) { put_sep(); @@ -2907,7 +2761,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { "from.$extensions$);\n"); } - GenerateCopyConstructorBody(printer); + GenerateCopyConstructorBody(p); // Copy oneof fields. Oneof field requires oneof case check. for (auto oneof : OneOfRange(descriptor_)) { @@ -2919,9 +2773,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { for (auto field : FieldRange(oneof)) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); - if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateMergingCode(printer); - } + field_generators_.get(field).GenerateMergingCode(p); format("break;\n"); format.Outdent(); format("}\n"); @@ -2930,7 +2782,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { "case $1$_NOT_SET: {\n" " break;\n" "}\n", - ToUpper(oneof->name())); + y_absl::AsciiStrToUpper(oneof->name())); format.Outdent(); format("}\n"); } @@ -2943,11 +2795,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { } // Generate the shared constructor code. - GenerateSharedConstructorCode(printer); - - if (ShouldSplit(descriptor_, options_)) { - GenerateCreateSplitMessage(printer); - } + GenerateSharedConstructorCode(p); // Generate the destructor. if (!HasSimpleBaseClass(descriptor_, options_)) { @@ -2977,11 +2825,11 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { } // Generate the shared destructor code. - GenerateSharedDestructorCode(printer); + GenerateSharedDestructorCode(p); // Generate the arena-specific destructor code. if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) { - GenerateArenaDestructorCode(printer); + GenerateArenaDestructorCode(p); } if (!HasSimpleBaseClass(descriptor_, options_)) { @@ -2993,8 +2841,10 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { } } -void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* p) { + auto v = p->WithVars(ClassVars(descriptor_, options_)); + auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); + Formatter format(p); format( "template<> " "PROTOBUF_NOINLINE $classtype$*\n" @@ -3003,9 +2853,9 @@ void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { "}\n"); } -void MessageGenerator::GenerateClear(io::Printer* printer) { +void MessageGenerator::GenerateClear(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); // The maximum number of bytes we will memset to zero without checking their // hasbit to see if a zero-init is necessary. @@ -3031,7 +2881,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { // checks all hasbits in the chunk and skips it if none are set. int zero_init_bytes = 0; for (const auto& field : optimized_order_) { - if (CanInitializeByZeroing(field)) { + if (CanClearByZeroing(field)) { zero_init_bytes += EstimateAlignmentSize(field); } } @@ -3044,12 +2894,12 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { chunk_count++; // This predicate guarantees that there is only a single zero-init // (memset) per chunk, and if present it will be at the beginning. - bool same = HasByteIndex(a) == HasByteIndex(b) && - a->is_repeated() == b->is_repeated() && - ShouldSplit(a, options_) == ShouldSplit(b, options_) && - (CanInitializeByZeroing(a) == CanInitializeByZeroing(b) || - (CanInitializeByZeroing(a) && - (chunk_count == 1 || merge_zero_init))); + bool same = + HasByteIndex(a) == HasByteIndex(b) && + a->is_repeated() == b->is_repeated() && + ShouldSplit(a, options_) == ShouldSplit(b, options_) && + (CanClearByZeroing(a) == CanClearByZeroing(b) || + (CanClearByZeroing(a) && (chunk_count == 1 || merge_zero_init))); if (!same) chunk_count = 0; return same; }); @@ -3057,18 +2907,29 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_, kColdRatio); int cached_has_word_index = -1; - - for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + bool first_split_chunk_processed = false; + for (size_t chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; - cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer); + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", p); const FieldDescriptor* memset_start = nullptr; const FieldDescriptor* memset_end = nullptr; bool saw_non_zero_init = false; - bool chunk_is_cold = !chunk.empty() && ShouldSplit(chunk.front(), options_); + bool chunk_is_split = + !chunk.empty() && ShouldSplit(chunk.front(), options_); + // All chunks after the first split chunk should also be split. + Y_ABSL_CHECK(!first_split_chunk_processed || chunk_is_split); + if (chunk_is_split && !first_split_chunk_processed) { + // Some fields are cleared without checking has_bit. So we add the + // condition here to avoid writing to the default split instance. + format("if (!IsSplitMessageDefault()) {\n"); + format.Indent(); + first_split_chunk_processed = true; + } + for (const auto& field : chunk) { - if (CanInitializeByZeroing(field)) { - GOOGLE_CHECK(!saw_non_zero_init); + if (CanClearByZeroing(field)) { + Y_ABSL_CHECK(!saw_non_zero_init); if (!memset_start) memset_start = field; memset_end = field; } else { @@ -3089,13 +2950,13 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { // Emit an if() that will let us skip the whole chunk if none are set. arc_ui32 chunk_mask = GenChunkMask(chunk, has_bit_indices_); TProtoStringType chunk_mask_str = - StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8)); + y_absl::StrCat(y_absl::Hex(chunk_mask, y_absl::kZeroPad8)); // Check (up to) 8 has_bits at a time if we have more than one field in // this chunk. Due to field layout ordering, we may check // _has_bits_[last_chunk * 8 / 32] multiple times. - GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); - GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); + Y_ABSL_DCHECK_LE(2, popcnt(chunk_mask)); + Y_ABSL_DCHECK_GE(8, popcnt(chunk_mask)); if (cached_has_word_index != HasWordIndex(chunk.front())) { cached_has_word_index = HasWordIndex(chunk.front()); @@ -3105,31 +2966,25 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { format.Indent(); } - if (chunk_is_cold) { - format("if (!IsSplitMessageDefault()) {\n"); - format.Indent(); - } - if (memset_start) { if (memset_start == memset_end) { // For clarity, do not memset a single field. - field_generators_.get(memset_start) - .GenerateMessageClearingCode(printer); + field_generators_.get(memset_start).GenerateMessageClearingCode(p); } else { - GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_start, options_)); - GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_end, options_)); + Y_ABSL_CHECK_EQ(chunk_is_split, ShouldSplit(memset_start, options_)); + Y_ABSL_CHECK_EQ(chunk_is_split, ShouldSplit(memset_end, options_)); format( - "::memset(&$1$, 0, static_cast<size_t>(\n" + "::memset(&$1$, 0, static_cast<::size_t>(\n" " reinterpret_cast<char*>(&$2$) -\n" " reinterpret_cast<char*>(&$1$)) + sizeof($2$));\n", - FieldMemberName(memset_start, chunk_is_cold), - FieldMemberName(memset_end, chunk_is_cold)); + FieldMemberName(memset_start, chunk_is_split), + FieldMemberName(memset_end, chunk_is_split)); } } // Clear all non-zero-initializable fields in the chunk. for (const auto& field : chunk) { - if (CanInitializeByZeroing(field)) continue; + if (CanClearByZeroing(field)) continue; // It's faster to just overwrite primitive types, but we should only // clear strings and messages if they were set. // @@ -3140,11 +2995,10 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); if (have_enclosing_if) { - PrintPresenceCheck(format, field, has_bit_indices_, printer, - &cached_has_word_index); + PrintPresenceCheck(field, has_bit_indices_, p, &cached_has_word_index); } - field_generators_.get(field).GenerateMessageClearingCode(printer); + field_generators_.get(field).GenerateMessageClearingCode(p); if (have_enclosing_if) { format.Outdent(); @@ -3152,17 +3006,19 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { } } - if (chunk_is_cold) { + if (have_outer_if) { format.Outdent(); format("}\n"); } - if (have_outer_if) { - format.Outdent(); - format("}\n"); + if (chunk_index == chunks.size() - 1) { + if (first_split_chunk_processed) { + format.Outdent(); + format("}\n"); + } } - if (cold_skipper.OnEndChunk(chunk_index, printer)) { + if (cold_skipper.OnEndChunk(chunk_index, p)) { // Reset here as it may have been updated in just closed if statement. cached_has_word_index = -1; } @@ -3184,21 +3040,18 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { format("$has_bits$.Clear();\n"); } - std::map<TProtoStringType, TProtoStringType> vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); format("_internal_metadata_.Clear<$unknown_fields_type$>();\n"); format.Outdent(); format("}\n"); } -void MessageGenerator::GenerateOneofClear(io::Printer* printer) { +void MessageGenerator::GenerateOneofClear(io::Printer* p) { // Generated function clears the active field and union case (e.g. foo_case_). int i = 0; for (auto oneof : OneOfRange(descriptor_)) { - Formatter format(printer, variables_); - format.Set("oneofname", oneof->name()); + Formatter format(p); + auto v = p->WithVars({{"oneofname", oneof->name()}}); format( "void $classname$::clear_$oneofname$() {\n" @@ -3210,10 +3063,10 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); // We clear only allocated objects in oneofs - if (!IsStringOrMessage(field) || IsFieldStripped(field, options_)) { + if (!IsStringOrMessage(field)) { format("// No need to clear\n"); } else { - field_generators_.get(field).GenerateClearingCode(printer); + field_generators_.get(field).GenerateClearingCode(p); } format("break;\n"); format.Outdent(); @@ -3223,12 +3076,12 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) { "case $1$_NOT_SET: {\n" " break;\n" "}\n", - ToUpper(oneof->name())); + y_absl::AsciiStrToUpper(oneof->name())); format.Outdent(); format( "}\n" "$oneof_case$[$1$] = $2$_NOT_SET;\n", - i, ToUpper(oneof->name())); + i, y_absl::AsciiStrToUpper(oneof->name())); format.Outdent(); format( "}\n" @@ -3237,9 +3090,9 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) { } } -void MessageGenerator::GenerateSwap(io::Printer* printer) { +void MessageGenerator::GenerateSwap(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); format("void $classname$::InternalSwap($classname$* other) {\n"); format.Indent(); @@ -3252,9 +3105,6 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { "\n"); } - std::map<TProtoStringType, TProtoStringType> vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); if (HasNonSplitOptionalString(descriptor_, options_)) { format( "auto* lhs_arena = GetArenaForAllocation();\n" @@ -3272,7 +3122,7 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { const RunMap runs = FindRuns(optimized_order_, [this](const FieldDescriptor* field) { return !ShouldSplit(field, options_) && - CanBeManipulatedAsRawBytes(field, options_, scc_analyzer_); + HasTrivialSwap(field, options_, scc_analyzer_); }); for (size_t i = 0; i < optimized_order_.size(); ++i) { @@ -3293,8 +3143,10 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { const TProtoStringType last_field_name = FieldMemberName( optimized_order_[i + run_length - 1], /*cold=*/false); - format.Set("first", first_field_name); - format.Set("last", last_field_name); + auto v = p->WithVars({ + {"first", first_field_name}, + {"last", last_field_name}, + }); format( "::PROTOBUF_NAMESPACE_ID::internal::memswap<\n" @@ -3307,7 +3159,7 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { i += run_length - 1; // ++i at the top of the loop. } else { - field_generators_.get(field).GenerateSwappingCode(printer); + field_generators_.get(field).GenerateSwappingCode(p); } } if (ShouldSplit(descriptor_, options_)) { @@ -3344,8 +3196,8 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { - Formatter format(printer, variables_); +void MessageGenerator::GenerateMergeFrom(io::Printer* p) { + Formatter format(p); if (!HasSimpleBaseClass(descriptor_, options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { // We don't override the generalized MergeFrom (aka that which @@ -3391,10 +3243,11 @@ void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { } } -void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { +void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. - Formatter format(printer, variables_); + // Generate the class-specific MergeFrom, which avoids the Y_ABSL_CHECK and + // cast. + Formatter format(p); if (!HasDescriptorMethods(descriptor_->file(), options_)) { // For messages that don't inherit from Message, just implement MergeFrom // directly. @@ -3445,20 +3298,19 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; bool have_outer_if = chunk.size() > 1 && HasByteIndex(chunk.front()) != kNoHasbit; - cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "from.", - printer); + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "from.", p); if (have_outer_if) { // Emit an if() that will let us skip the whole chunk if none are set. arc_ui32 chunk_mask = GenChunkMask(chunk, has_bit_indices_); TProtoStringType chunk_mask_str = - StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8)); + y_absl::StrCat(y_absl::Hex(chunk_mask, y_absl::kZeroPad8)); // Check (up to) 8 has_bits at a time if we have more than one field in // this chunk. Due to field layout ordering, we may check // _has_bits_[last_chunk * 8 / 32] multiple times. - GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); - GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); + Y_ABSL_DCHECK_LE(2, popcnt(chunk_mask)); + Y_ABSL_DCHECK_GE(8, popcnt(chunk_mask)); if (cached_has_word_index != HasWordIndex(chunk.front())) { cached_has_word_index = HasWordIndex(chunk.front()); @@ -3473,16 +3325,16 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { // Go back and emit merging code for each of the fields we processed. bool deferred_has_bit_changes = false; for (const auto field : chunk) { - const FieldGenerator& generator = field_generators_.get(field); + const auto& generator = field_generators_.get(field); if (field->is_repeated()) { - generator.GenerateMergingCode(printer); + generator.GenerateMergingCode(p); } else if (field->is_optional() && !HasHasbit(field)) { // Merge semantics without true field presence: primitive fields are // merged only if non-zero (numeric) or non-empty (string). bool have_enclosing_if = - EmitFieldNonDefaultCondition(printer, "from.", field); - generator.GenerateMergingCode(printer); + EmitFieldNonDefaultCondition(p, "from.", field); + generator.GenerateMergingCode(p); if (have_enclosing_if) { format.Outdent(); format("}\n"); @@ -3490,18 +3342,20 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { } else if (field->options().weak() || cached_has_word_index != HasWordIndex(field)) { // Check hasbit, not using cached bits. - GOOGLE_CHECK(HasHasbit(field)); - format("if (from._internal_has_$1$()) {\n", FieldName(field)); + Y_ABSL_CHECK(HasHasbit(field)); + auto v = p->WithVars(HasbitVars(HasBitIndex(field))); + format( + "if ((from.$has_bits$[$has_array_index$] & $has_mask$) != 0) {\n"); format.Indent(); - generator.GenerateMergingCode(printer); + generator.GenerateMergingCode(p); format.Outdent(); format("}\n"); } else { // Check hasbit, using cached bits. - GOOGLE_CHECK(HasHasbit(field)); + Y_ABSL_CHECK(HasHasbit(field)); int has_bit_index = has_bit_indices_[field->index()]; - const TProtoStringType mask = StrCat( - strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + const TProtoStringType mask = y_absl::StrCat( + y_absl::Hex(1u << (has_bit_index % 32), y_absl::kZeroPad8)); format("if (cached_has_bits & 0x$1$u) {\n", mask); format.Indent(); @@ -3509,9 +3363,9 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { // Defer hasbit modification until the end of chunk. // This can reduce the number of loads/stores by up to 7 per 8 fields. deferred_has_bit_changes = true; - generator.GenerateCopyConstructorCode(printer); + generator.GenerateCopyConstructorCode(p); } else { - generator.GenerateMergingCode(printer); + generator.GenerateMergingCode(p); } format.Outdent(); @@ -3522,7 +3376,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { if (have_outer_if) { if (deferred_has_bit_changes) { // Flush the has bits for the primitives we deferred. - GOOGLE_CHECK_LE(0, cached_has_word_index); + Y_ABSL_CHECK_LE(0, cached_has_word_index); format("_this->$has_bits$[$1$] |= cached_has_bits;\n", cached_has_word_index); } @@ -3531,7 +3385,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { format("}\n"); } - if (cold_skipper.OnEndChunk(chunk_index, printer)) { + if (cold_skipper.OnEndChunk(chunk_index, p)) { // Reset here as it may have been updated in just closed if statement. cached_has_word_index = -1; } @@ -3544,9 +3398,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { for (auto field : FieldRange(oneof)) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); - if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateMergingCode(printer); - } + field_generators_.get(field).GenerateMergingCode(p); format("break;\n"); format.Outdent(); format("}\n"); @@ -3555,7 +3407,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { "case $1$_NOT_SET: {\n" " break;\n" "}\n", - ToUpper(oneof->name())); + y_absl::AsciiStrToUpper(oneof->name())); format.Outdent(); format("}\n"); } @@ -3582,9 +3434,9 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { +void MessageGenerator::GenerateCopyFrom(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); if (HasDescriptorMethods(descriptor_->file(), options_)) { // We don't override the generalized CopyFrom (aka that which // takes in the Message base class as a parameter); instead we just @@ -3613,21 +3465,22 @@ void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { // It is also disabled if a message has neither message fields nor // extensions, as it's impossible to copy from its descendant. // - // Note that FailIfCopyFromDescendant is implemented by reflection and not - // available for lite runtime. In that case, check if the size of the source - // has changed after Clear. - format("#ifndef NDEBUG\n"); + // Note that IsDescendant is implemented by reflection and not available for + // lite runtime. In that case, check if the size of the source has changed + // after Clear. if (HasDescriptorMethods(descriptor_->file(), options_)) { - format("FailIfCopyFromDescendant(*this, from);\n"); + format( + "$DCHK$(!::_pbi::IsDescendant(*this, from))\n" + " << \"Source of CopyFrom cannot be a descendant of the " + "target.\";\n" + "Clear();\n"); } else { - format("size_t from_size = from.ByteSizeLong();\n"); - } - format( - "#endif\n" - "Clear();\n"); - if (!HasDescriptorMethods(descriptor_->file(), options_)) { format( "#ifndef NDEBUG\n" + "::size_t from_size = from.ByteSizeLong();\n" + "#endif\n" + "Clear();\n" + "#ifndef NDEBUG\n" "$CHK$_EQ(from_size, from.ByteSizeLong())\n" " << \"Source of CopyFrom changed when clearing target. Either \"\n" " \"source is a nested message in target (not allowed), or \"\n" @@ -3643,15 +3496,15 @@ void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateVerify(io::Printer* printer) { +void MessageGenerator::GenerateVerify(io::Printer* p) { } void MessageGenerator::GenerateSerializeOneofFields( - io::Printer* printer, const std::vector<const FieldDescriptor*>& fields) { - Formatter format(printer, variables_); - GOOGLE_CHECK(!fields.empty()); + io::Printer* p, const std::vector<const FieldDescriptor*>& fields) { + Formatter format(p); + Y_ABSL_CHECK(!fields.empty()); if (fields.size() == 1) { - GenerateSerializeOneField(printer, fields[0], -1); + GenerateSerializeOneField(p, fields[0], -1); return; } // We have multiple mutually exclusive choices. Emit a switch statement. @@ -3661,8 +3514,7 @@ void MessageGenerator::GenerateSerializeOneofFields( for (auto field : fields) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); - field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( - printer); + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(p); format("break;\n"); format.Outdent(); format("}\n"); @@ -3674,10 +3526,11 @@ void MessageGenerator::GenerateSerializeOneofFields( "}\n"); } -void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, +void MessageGenerator::GenerateSerializeOneField(io::Printer* p, const FieldDescriptor* field, int cached_has_bits_index) { - Formatter format(printer, variables_); + auto v = p->WithVars(FieldVars(field, options_)); + Formatter format(p); if (!field->options().weak()) { // For weakfields, PrintFieldComment is called during iteration. PrintFieldComment(format, field); @@ -3688,22 +3541,20 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, } else if (HasHasbit(field)) { // Attempt to use the state of cached_has_bits, if possible. int has_bit_index = HasBitIndex(field); + auto v = p->WithVars(HasbitVars(has_bit_index)); if (cached_has_bits_index == has_bit_index / 32) { - const TProtoStringType mask = - StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); - - format("if (cached_has_bits & 0x$1$u) {\n", mask); + format("if (cached_has_bits & $has_mask$) {\n"); } else { - format("if (_internal_has_$1$()) {\n", FieldName(field)); + field_generators_.get(field).GenerateIfHasField(p); } format.Indent(); have_enclosing_if = true; } else if (field->is_optional() && !HasHasbit(field)) { - have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field); + have_enclosing_if = EmitFieldNonDefaultCondition(p, "this->", field); } - field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(printer); + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(p); if (have_enclosing_if) { format.Outdent(); @@ -3713,21 +3564,20 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, } void MessageGenerator::GenerateSerializeOneExtensionRange( - io::Printer* printer, const Descriptor::ExtensionRange* range) { - std::map<TProtoStringType, TProtoStringType> vars = variables_; - vars["start"] = StrCat(range->start); - vars["end"] = StrCat(range->end); - Formatter format(printer, vars); + io::Printer* p, const Descriptor::ExtensionRange* range) { + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars = variables_; + vars["start"] = y_absl::StrCat(range->start); + vars["end"] = y_absl::StrCat(range->end); + Formatter format(p, vars); format("// Extension range [$start$, $end$)\n"); format( "target = $extensions$._InternalSerialize(\n" "internal_default_instance(), $start$, $end$, target, stream);\n\n"); } -void MessageGenerator::GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) { +void MessageGenerator::GenerateSerializeWithCachedSizesToArray(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. format( @@ -3738,9 +3588,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( " target = $extensions$." "InternalSerializeMessageSetWithCachedSizesToArray(\n" // "internal_default_instance(), target, stream);\n"); - std::map<TProtoStringType, TProtoStringType> vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); + format( " target = ::_pbi::" "InternalSerializeUnknownMessageSetItemsToArray(\n" @@ -3766,14 +3614,14 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( format.Indent(); } - GenerateSerializeWithCachedSizesBody(printer); + GenerateSerializeWithCachedSizesBody(p); if (!ShouldSerializeInOrder(descriptor_, options_)) { format.Outdent(); format("#else // NDEBUG\n"); format.Indent(); - GenerateSerializeWithCachedSizesBodyShuffled(printer); + GenerateSerializeWithCachedSizesBodyShuffled(p); format.Outdent(); format("#endif // !NDEBUG\n"); @@ -3788,10 +3636,9 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( "}\n"); } -void MessageGenerator::GenerateSerializeWithCachedSizesBody( - io::Printer* printer) { +void MessageGenerator::GenerateSerializeWithCachedSizesBody(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); // If there are multiple fields in a row from the same oneof then we // coalesce them and emit a switch statement. This is more efficient // because it lets the C++ compiler know this is a "at most one can happen" @@ -3799,9 +3646,9 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // compiler's emitted code might check has_y() even when has_x() is true. class LazySerializerEmitter { public: - LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer) + LazySerializerEmitter(MessageGenerator* mg, io::Printer* p) : mg_(mg), - format_(printer), + p_(p), eager_(IsProto3(mg->descriptor_->file())), cached_has_bit_index_(kNoHasbit) {} @@ -3810,6 +3657,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // If conditions allow, try to accumulate a run of fields from the same // oneof, and handle them at the next Flush(). void Emit(const FieldDescriptor* field) { + Formatter format(p_); if (eager_ || MustFlush(field)) { Flush(); } @@ -3825,14 +3673,13 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // Reload. int new_index = has_bit_index / 32; - format_("cached_has_bits = _impl_._has_bits_[$1$];\n", new_index); + format("cached_has_bits = _impl_._has_bits_[$1$];\n", new_index); cached_has_bit_index_ = new_index; } } - mg_->GenerateSerializeOneField(format_.printer(), field, - cached_has_bit_index_); + mg_->GenerateSerializeOneField(p_, field, cached_has_bit_index_); } else { v_.push_back(field); } @@ -3846,7 +3693,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( void Flush() { if (!v_.empty()) { - mg_->GenerateSerializeOneofFields(format_.printer(), v_); + mg_->GenerateSerializeOneofFields(p_, v_); v_.clear(); } } @@ -3860,8 +3707,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( } MessageGenerator* mg_; - Formatter format_; - const bool eager_; + io::Printer* p_; + bool eager_; std::vector<const FieldDescriptor*> v_; // cached_has_bit_index_ maintains that: @@ -3872,8 +3719,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( class LazyExtensionRangeEmitter { public: - LazyExtensionRangeEmitter(MessageGenerator* mg, io::Printer* printer) - : mg_(mg), format_(printer) {} + LazyExtensionRangeEmitter(MessageGenerator* mg, io::Printer* p) + : mg_(mg), p_(p) {} void AddToRange(const Descriptor::ExtensionRange* range) { if (!has_current_range_) { @@ -3889,15 +3736,14 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( void Flush() { if (has_current_range_) { - mg_->GenerateSerializeOneExtensionRange(format_.printer(), - ¤t_combined_range_); + mg_->GenerateSerializeOneExtensionRange(p_, ¤t_combined_range_); } has_current_range_ = false; } private: MessageGenerator* mg_; - Formatter format_; + io::Printer* p_; bool has_current_range_ = false; Descriptor::ExtensionRange current_combined_range_; }; @@ -3947,8 +3793,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // Merge the fields and the extension ranges, both sorted by field number. { - LazySerializerEmitter e(this, printer); - LazyExtensionRangeEmitter re(this, printer); + LazySerializerEmitter e(this, p); + LazyExtensionRangeEmitter re(this, p); LargestWeakFieldHolder largest_weak_field; int i, j; for (i = 0, j = 0; @@ -3957,9 +3803,6 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( (i < descriptor_->field_count() && ordered_fields[i]->number() < sorted_extensions[j]->start)) { const FieldDescriptor* field = ordered_fields[i++]; - if (IsFieldStripped(field, options_)) { - continue; - } re.Flush(); if (field->options().weak()) { largest_weak_field.ReplaceIfLarger(field); @@ -3978,9 +3821,6 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( e.EmitIfNotNull(largest_weak_field.Release()); } - std::map<TProtoStringType, TProtoStringType> vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); format.Indent(); if (UseUnknownFieldSet(descriptor_->file(), options_)) { @@ -3999,8 +3839,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( } void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( - io::Printer* printer) { - Formatter format(printer, variables_); + io::Printer* p) { + Formatter format(p); std::vector<const FieldDescriptor*> ordered_fields = SortFieldsByNumber(descriptor_); @@ -4021,7 +3861,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( int num_fields = ordered_fields.size() + sorted_extensions.size(); constexpr int kLargePrime = 1000003; - GOOGLE_CHECK_LT(num_fields, kLargePrime) + Y_ABSL_CHECK_LT(num_fields, kLargePrime) << "Prime offset must be greater than the number of fields to ensure " "those are coprime."; @@ -4042,7 +3882,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( format("case $1$: {\n", index++); format.Indent(); - GenerateSerializeOneField(printer, f, -1); + GenerateSerializeOneField(p, f, -1); format("break;\n"); format.Outdent(); @@ -4053,7 +3893,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( format("case $1$: {\n", index++); format.Indent(); - GenerateSerializeOneExtensionRange(printer, r); + GenerateSerializeOneExtensionRange(p, r); format("break;\n"); format.Outdent(); @@ -4070,9 +3910,6 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( format.Outdent(); format("}\n"); - std::map<TProtoStringType, TProtoStringType> vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); format.Indent(); if (UseUnknownFieldSet(descriptor_->file(), options_)) { @@ -4106,20 +3943,17 @@ std::vector<arc_ui32> MessageGenerator::RequiredFieldsBitMask() const { return masks; } -void MessageGenerator::GenerateByteSize(io::Printer* printer) { +void MessageGenerator::GenerateByteSize(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. - std::map<TProtoStringType, TProtoStringType> vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); format( - "size_t $classname$::ByteSizeLong() const {\n" + "::size_t $classname$::ByteSizeLong() const {\n" "$annotate_bytesize$" "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" - " size_t total_size = $extensions$.MessageSetByteSize();\n" + " ::size_t total_size = $extensions$.MessageSetByteSize();\n" " if ($have_unknown_fields$) {\n" " total_size += ::_pbi::\n" " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" @@ -4136,20 +3970,18 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { // Emit a function (rarely used, we hope) that handles the required fields // by checking for each one individually. format( - "size_t $classname$::RequiredFieldsByteSizeFallback() const {\n" + "::size_t $classname$::RequiredFieldsByteSizeFallback() const {\n" "// @@protoc_insertion_point(required_fields_byte_size_fallback_start:" "$full_name$)\n"); format.Indent(); - format("size_t total_size = 0;\n"); + format("::size_t total_size = 0;\n"); for (auto field : optimized_order_) { if (field->is_required()) { - format( - "\n" - "if (_internal_has_$1$()) {\n", - FieldName(field)); + format("\n"); + field_generators_.get(field).GenerateIfHasField(p); format.Indent(); PrintFieldComment(format, field); - field_generators_.get(field).GenerateByteSize(printer); + field_generators_.get(field).GenerateByteSize(p); format.Outdent(); format("}\n"); } @@ -4162,12 +3994,12 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { } format( - "size_t $classname$::ByteSizeLong() const {\n" + "::size_t $classname$::ByteSizeLong() const {\n" "$annotate_bytesize$" "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n"); format.Indent(); format( - "size_t total_size = 0;\n" + "::size_t total_size = 0;\n" "\n"); if (descriptor_->extension_range_count() > 0) { @@ -4176,10 +4008,6 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { "\n"); } - std::map<TProtoStringType, TProtoStringType> vars; - SetUnknownFieldsVariable(descriptor_, options_, &vars); - format.AddMap(vars); - // Handle required fields (if any). We expect all of them to be // present, so emit one conditional that checks for that. If they are all // present then the fast path executes; otherwise the slow path executes. @@ -4194,7 +4022,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { for (auto field : optimized_order_) { if (!field->is_required()) continue; PrintFieldComment(format, field); - field_generators_.get(field).GenerateByteSize(printer); + field_generators_.get(field).GenerateByteSize(p); format("\n"); } format.Outdent(); @@ -4207,9 +4035,9 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { for (auto field : optimized_order_) { if (!field->is_required()) continue; PrintFieldComment(format, field); - format("if (_internal_has_$1$()) {\n", FieldName(field)); + field_generators_.get(field).GenerateIfHasField(p); format.Indent(); - field_generators_.get(field).GenerateByteSize(printer); + field_generators_.get(field).GenerateByteSize(p); format.Outdent(); format("}\n"); } @@ -4239,19 +4067,19 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; const bool have_outer_if = chunk.size() > 1 && HasWordIndex(chunk[0]) != kNoHasbit; - cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer); + cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", p); if (have_outer_if) { // Emit an if() that will let us skip the whole chunk if none are set. arc_ui32 chunk_mask = GenChunkMask(chunk, has_bit_indices_); TProtoStringType chunk_mask_str = - StrCat(strings::Hex(chunk_mask, strings::ZERO_PAD_8)); + y_absl::StrCat(y_absl::Hex(chunk_mask, y_absl::kZeroPad8)); // Check (up to) 8 has_bits at a time if we have more than one field in // this chunk. Due to field layout ordering, we may check // _has_bits_[last_chunk * 8 / 32] multiple times. - GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); - GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); + Y_ABSL_DCHECK_LE(2, popcnt(chunk_mask)); + Y_ABSL_DCHECK_GE(8, popcnt(chunk_mask)); if (cached_has_word_index != HasWordIndex(chunk.front())) { cached_has_word_index = HasWordIndex(chunk.front()); @@ -4264,7 +4092,6 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { // Go back and emit checks for each of the fields we processed. for (int j = 0; j < chunk.size(); j++) { const FieldDescriptor* field = chunk[j]; - const FieldGenerator& generator = field_generators_.get(field); bool have_enclosing_if = false; bool need_extra_newline = false; @@ -4274,17 +4101,15 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { // No presence check is required. need_extra_newline = true; } else if (HasHasbit(field)) { - PrintPresenceCheck(format, field, has_bit_indices_, printer, - &cached_has_word_index); + PrintPresenceCheck(field, has_bit_indices_, p, &cached_has_word_index); have_enclosing_if = true; } else { // Without field presence: field is serialized only if it has a // non-default value. - have_enclosing_if = - EmitFieldNonDefaultCondition(printer, "this->", field); + have_enclosing_if = EmitFieldNonDefaultCondition(p, "this->", field); } - generator.GenerateByteSize(printer); + field_generators_.get(field).GenerateByteSize(p); if (have_enclosing_if) { format.Outdent(); @@ -4302,7 +4127,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { format("}\n"); } - if (cold_skipper.OnEndChunk(chunk_index, printer)) { + if (cold_skipper.OnEndChunk(chunk_index, p)) { // Reset here as it may have been updated in just closed if statement. cached_has_word_index = -1; } @@ -4317,9 +4142,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { PrintFieldComment(format, field); format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); - if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateByteSize(printer); - } + field_generators_.get(field).GenerateByteSize(p); format("break;\n"); format.Outdent(); format("}\n"); @@ -4328,7 +4151,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { "case $1$_NOT_SET: {\n" " break;\n" "}\n", - ToUpper(oneof->name())); + y_absl::AsciiStrToUpper(oneof->name())); format.Outdent(); format("}\n"); } @@ -4367,15 +4190,15 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { format("}\n"); } -void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { +void MessageGenerator::GenerateIsInitialized(io::Printer* p) { if (HasSimpleBaseClass(descriptor_, options_)) return; - Formatter format(printer, variables_); + Formatter format(p); format("bool $classname$::IsInitialized() const {\n"); format.Indent(); if (descriptor_->extension_range_count() > 0) { format( - "if (!$extensions$.IsInitialized()) {\n" + "if (!$extensions$.IsInitialized(internal_default_instance())) {\n" " return false;\n" "}\n\n"); } @@ -4388,7 +4211,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { // Now check that all non-oneof embedded messages are initialized. for (auto field : optimized_order_) { - field_generators_.get(field).GenerateIsInitialized(printer); + field_generators_.get(field).GenerateIsInitialized(p); } if (num_weak_fields_) { // For Weak fields. @@ -4416,9 +4239,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { for (auto field : FieldRange(oneof)) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); - if (!IsFieldStripped(field, options_)) { - field_generators_.get(field).GenerateIsInitialized(printer); - } + field_generators_.get(field).GenerateIsInitialized(p); format("break;\n"); format.Outdent(); format("}\n"); @@ -4427,7 +4248,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { "case $1$_NOT_SET: {\n" " break;\n" "}\n", - ToUpper(oneof->name())); + y_absl::AsciiStrToUpper(oneof->name())); format.Outdent(); format("}\n"); } @@ -4443,4 +4264,4 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { } // namespace protobuf } // namespace google -#include <google/protobuf/port_undef.inc> +#include "google/protobuf/port_undef.inc" diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.h index 960bea8e5af..f1dcd65ef20 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.h @@ -36,40 +36,38 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ #include <cstdint> +#include <limits> #include <memory> -#include <set> #include <string> - -#include <google/protobuf/compiler/cpp/field.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/cpp/message_layout_helper.h> -#include <google/protobuf/compiler/cpp/options.h> -#include <google/protobuf/compiler/cpp/parse_function_generator.h> - -namespace google { -namespace protobuf { -namespace io { -class Printer; // printer.h -} -} // namespace protobuf -} // namespace google +#include <utility> +#include <vector> + +#include "y_absl/container/flat_hash_map.h" +#include "google/protobuf/compiler/cpp/enum.h" +#include "google/protobuf/compiler/cpp/extension.h" +#include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/message_layout_helper.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/compiler/cpp/parse_function_generator.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - -class EnumGenerator; // enum.h -class ExtensionGenerator; // extension.h - class MessageGenerator { public: - // See generator.cc for the meaning of dllexport_decl. - MessageGenerator(const Descriptor* descriptor, - const std::map<TProtoStringType, TProtoStringType>& vars, - int index_in_file_messages, const Options& options, - MessageSCCAnalyzer* scc_analyzer); - ~MessageGenerator(); + MessageGenerator( + const Descriptor* descriptor, + const y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>& ignored, + int index_in_file_messages, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + + MessageGenerator(const MessageGenerator&) = delete; + MessageGenerator& operator=(const MessageGenerator&) = delete; + + ~MessageGenerator() = default; // Append the two types of nested generators to the corresponding vector. void AddGenerators( @@ -77,95 +75,94 @@ class MessageGenerator { std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators); // Generate definitions for this class and all its nested types. - void GenerateClassDefinition(io::Printer* printer); + void GenerateClassDefinition(io::Printer* p); // Generate definitions of inline methods (placed at the end of the header // file). - void GenerateInlineMethods(io::Printer* printer); - - // Source file stuff. + void GenerateInlineMethods(io::Printer* p); // Generate all non-inline methods for this class. - void GenerateClassMethods(io::Printer* printer); + void GenerateClassMethods(io::Printer* p); // Generate source file code that should go outside any namespace. - void GenerateSourceInProto2Namespace(io::Printer* printer); + void GenerateSourceInProto2Namespace(io::Printer* p); - private: - // Generate declarations and definitions of accessors for fields. - void GenerateFieldAccessorDeclarations(io::Printer* printer); - void GenerateFieldAccessorDefinitions(io::Printer* printer); + + void GenerateInitDefaultSplitInstance(io::Printer* p); + + // Generate the constexpr constructor for constant initialization of the + // default instance. + void GenerateConstexprConstructor(io::Printer* p); + + void GenerateSchema(io::Printer* p, int offset, int has_offset); // Generate the field offsets array. Returns the a pair of the total number // of entries generated and the index of the first has_bit entry. - std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer); - void GenerateSchema(io::Printer* printer, int offset, int has_offset); + std::pair<size_t, size_t> GenerateOffsets(io::Printer* p); + + const Descriptor* descriptor() const { return descriptor_; } + + private: + // Generate declarations and definitions of accessors for fields. + void GenerateFieldAccessorDeclarations(io::Printer* p); + void GenerateFieldAccessorDefinitions(io::Printer* p); // Generate constructors and destructor. - void GenerateStructors(io::Printer* printer); + void GenerateStructors(io::Printer* p); // The compiler typically generates multiple copies of each constructor and // destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx // Placing common code in a separate method reduces the generated code size. // // Generate the shared constructor code. - void GenerateSharedConstructorCode(io::Printer* printer); + void GenerateSharedConstructorCode(io::Printer* p); // Generate the shared destructor code. - void GenerateSharedDestructorCode(io::Printer* printer); + void GenerateSharedDestructorCode(io::Printer* p); // Generate the arena-specific destructor code. - void GenerateArenaDestructorCode(io::Printer* printer); - - // Generate the constexpr constructor for constant initialization of the - // default instance. - void GenerateConstexprConstructor(io::Printer* printer); - - void GenerateCreateSplitMessage(io::Printer* printer); - void GenerateInitDefaultSplitInstance(io::Printer* printer); + void GenerateArenaDestructorCode(io::Printer* p); // Generate standard Message methods. - void GenerateClear(io::Printer* printer); - void GenerateOneofClear(io::Printer* printer); - void GenerateVerify(io::Printer* printer); - void GenerateSerializeWithCachedSizes(io::Printer* printer); - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer); - void GenerateSerializeWithCachedSizesBody(io::Printer* printer); - void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* printer); - void GenerateByteSize(io::Printer* printer); - void GenerateMergeFrom(io::Printer* printer); - void GenerateClassSpecificMergeImpl(io::Printer* printer); - void GenerateCopyFrom(io::Printer* printer); - void GenerateSwap(io::Printer* printer); - void GenerateIsInitialized(io::Printer* printer); + void GenerateClear(io::Printer* p); + void GenerateOneofClear(io::Printer* p); + void GenerateVerify(io::Printer* p); + void GenerateSerializeWithCachedSizes(io::Printer* p); + void GenerateSerializeWithCachedSizesToArray(io::Printer* p); + void GenerateSerializeWithCachedSizesBody(io::Printer* p); + void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* p); + void GenerateByteSize(io::Printer* p); + void GenerateMergeFrom(io::Printer* p); + void GenerateClassSpecificMergeImpl(io::Printer* p); + void GenerateCopyFrom(io::Printer* p); + void GenerateSwap(io::Printer* p); + void GenerateIsInitialized(io::Printer* p); // Helpers for GenerateSerializeWithCachedSizes(). // // cached_has_bit_index maintains that: // cached_has_bits = _has_bits_[cached_has_bit_index] // for cached_has_bit_index >= 0 - void GenerateSerializeOneField(io::Printer* printer, - const FieldDescriptor* field, + void GenerateSerializeOneField(io::Printer* p, const FieldDescriptor* field, int cached_has_bits_index); // Generate a switch statement to serialize 2+ fields from the same oneof. // Or, if fields.size() == 1, just call GenerateSerializeOneField(). void GenerateSerializeOneofFields( - io::Printer* printer, const std::vector<const FieldDescriptor*>& fields); + io::Printer* p, const std::vector<const FieldDescriptor*>& fields); void GenerateSerializeOneExtensionRange( - io::Printer* printer, const Descriptor::ExtensionRange* range); + io::Printer* p, const Descriptor::ExtensionRange* range); // Generates has_foo() functions and variables for singular field has-bits. void GenerateSingularFieldHasBits(const FieldDescriptor* field, - Formatter format); + io::Printer* p); // Generates has_foo() functions and variables for oneof field has-bits. - void GenerateOneofHasBits(io::Printer* printer); + void GenerateOneofHasBits(io::Printer* p); // Generates has_foo_bar() functions for oneof members. - void GenerateOneofMemberHasBits(const FieldDescriptor* field, - const Formatter& format); + void GenerateOneofMemberHasBits(const FieldDescriptor* field, io::Printer* p); // Generates the clear_foo() method for a field. void GenerateFieldClear(const FieldDescriptor* field, bool is_inline, - Formatter format); + io::Printer* p); // Generates the body of the message's copy constructor. - void GenerateCopyConstructorBody(io::Printer* printer) const; + void GenerateCopyConstructorBody(io::Printer* p) const; // Returns the level that this message needs ArenaDtor. If the message has // a field that is not arena-exclusive, it needs an ArenaDtor @@ -181,17 +178,15 @@ class MessageGenerator { size_t HasBitsSize() const; size_t InlinedStringDonatedSize() const; - int HasBitIndex(const FieldDescriptor* a) const; - int HasByteIndex(const FieldDescriptor* a) const; - int HasWordIndex(const FieldDescriptor* a) const; - bool SameHasByte(const FieldDescriptor* a, const FieldDescriptor* b) const; + int HasBitIndex(const FieldDescriptor* field) const; + int HasByteIndex(const FieldDescriptor* field) const; + int HasWordIndex(const FieldDescriptor* field) const; std::vector<arc_ui32> RequiredFieldsBitMask() const; const Descriptor* descriptor_; int index_in_file_messages_; - TProtoStringType classname_; Options options_; - FieldGeneratorMap field_generators_; + FieldGeneratorTable field_generators_; // optimized_order_ is the order we layout the message's fields in the // class. This is reused to initialize the fields in-order for cache // efficiency. @@ -199,29 +194,27 @@ class MessageGenerator { // optimized_order_ excludes oneof fields and weak fields. std::vector<const FieldDescriptor*> optimized_order_; std::vector<int> has_bit_indices_; - int max_has_bit_index_; + int max_has_bit_index_ = 0; // A map from field index to inlined_string index. For non-inlined-string // fields, the element is -1. If there is no inlined string in the message, // this is empty. std::vector<int> inlined_string_indices_; // The count of inlined_string fields in the message. - int max_inlined_string_index_; + int max_inlined_string_index_ = 0; std::vector<const EnumGenerator*> enum_generators_; std::vector<const ExtensionGenerator*> extension_generators_; - int num_required_fields_; - int num_weak_fields_; + int num_required_fields_ = 0; + int num_weak_fields_ = 0; std::unique_ptr<MessageLayoutHelper> message_layout_helper_; std::unique_ptr<ParseFunctionGenerator> parse_function_generator_; MessageSCCAnalyzer* scc_analyzer_; - std::map<TProtoStringType, TProtoStringType> variables_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> variables_; - friend class FileGenerator; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); }; } // namespace cpp diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.h deleted file mode 100644 index 70c42c0eacc..00000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.h +++ /dev/null @@ -1,148 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: [email protected] (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ - -#include <map> -#include <string> - -#include <google/protobuf/compiler/cpp/field.h> -#include <google/protobuf/compiler/cpp/helpers.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -class MessageFieldGenerator : public FieldGenerator { - public: - MessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options, - MessageSCCAnalyzer* scc_analyzer); - ~MessageFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateNonInlineAccessorDefinitions( - io::Printer* printer) const override; - void GenerateInternalAccessorDeclarations( - io::Printer* printer) const override; - void GenerateInternalAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMessageClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override {} - void GenerateCopyConstructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - void GenerateIsInitialized(io::Printer* printer) const override; - void GenerateConstexprAggregateInitializer( - io::Printer* printer) const override; - void GenerateAggregateInitializer(io::Printer* printer) const override; - void GenerateCopyAggregateInitializer(io::Printer* printer) const override; - - protected: - const bool implicit_weak_field_; - const bool has_required_fields_; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); -}; - -class MessageOneofFieldGenerator : public MessageFieldGenerator { - public: - MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options, - MessageSCCAnalyzer* scc_analyzer); - ~MessageOneofFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateNonInlineAccessorDefinitions( - io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - - // MessageFieldGenerator, from which we inherit, overrides this so we need to - // override it as well. - void GenerateMessageClearingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - void GenerateIsInitialized(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); -}; - -class RepeatedMessageFieldGenerator : public FieldGenerator { - public: - RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options, - MessageSCCAnalyzer* scc_analyzer); - ~RepeatedMessageFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - void GenerateCopyConstructorCode(io::Printer* printer) const override {} - void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - void GenerateIsInitialized(io::Printer* printer) const override; - - private: - const bool implicit_weak_field_; - const bool has_required_fields_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); -}; - -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_layout_helper.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_layout_helper.h index a8813a1f225..7727e674663 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_layout_helper.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_layout_helper.h @@ -35,8 +35,8 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ -#include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/options.h> +#include "google/protobuf/descriptor.h" +#include "google/protobuf/compiler/cpp/options.h" namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/names.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/names.h index 8220f7dde8c..438b27e3d24 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/names.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/names.h @@ -33,8 +33,10 @@ #include <string> +#include "y_absl/strings/string_view.h" + // Must be included last. -#include <google/protobuf/port_def.inc> +#include "google/protobuf/port_def.inc" namespace google { namespace protobuf { @@ -43,10 +45,23 @@ class Descriptor; class EnumDescriptor; class EnumValueDescriptor; class FieldDescriptor; +class FileDescriptor; namespace compiler { namespace cpp { +// Returns the fully qualified C++ namespace. +// +// For example, if you had: +// package foo.bar; +// message Baz { message Moo {} } +// Then the qualified namespace for Moo would be: +// ::foo::bar +PROTOC_EXPORT TProtoStringType Namespace(const FileDescriptor* d); +PROTOC_EXPORT TProtoStringType Namespace(const Descriptor* d); +PROTOC_EXPORT TProtoStringType Namespace(const FieldDescriptor* d); +PROTOC_EXPORT TProtoStringType Namespace(const EnumDescriptor* d); + // Returns the unqualified C++ name. // // For example, if you had: @@ -54,8 +69,8 @@ namespace cpp { // message Baz { message Moo {} } // Then the non-qualified version would be: // Baz_Moo -TProtoStringType ClassName(const Descriptor* descriptor); -TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); +PROTOC_EXPORT TProtoStringType ClassName(const Descriptor* descriptor); +PROTOC_EXPORT TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); // Returns the fully qualified C++ name. // @@ -64,34 +79,35 @@ TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); // message Baz { message Moo {} } // Then the qualified ClassName for Moo would be: // ::foo::bar::Baz_Moo -TProtoStringType QualifiedClassName(const Descriptor* d); -TProtoStringType QualifiedClassName(const EnumDescriptor* d); -TProtoStringType QualifiedExtensionName(const FieldDescriptor* d); +PROTOC_EXPORT TProtoStringType QualifiedClassName(const Descriptor* d); +PROTOC_EXPORT TProtoStringType QualifiedClassName(const EnumDescriptor* d); +PROTOC_EXPORT TProtoStringType QualifiedExtensionName(const FieldDescriptor* d); // Get the (unqualified) name that should be used for this field in C++ code. // The name is coerced to lower-case to emulate proto1 behavior. People // should be using lowercase-with-underscores style for proto field names // anyway, so normally this just returns field->name(). -TProtoStringType FieldName(const FieldDescriptor* field); +PROTOC_EXPORT TProtoStringType FieldName(const FieldDescriptor* field); // Requires that this field is in a oneof. Returns the (unqualified) case // constant for this field. -TProtoStringType OneofCaseConstantName(const FieldDescriptor* field); +PROTOC_EXPORT TProtoStringType OneofCaseConstantName(const FieldDescriptor* field); // Returns the quafilied case constant for this field. -TProtoStringType QualifiedOneofCaseConstantName(const FieldDescriptor* field); +PROTOC_EXPORT TProtoStringType QualifiedOneofCaseConstantName( + const FieldDescriptor* field); // Get the (unqualified) name that should be used for this enum value in C++ // code. -TProtoStringType EnumValueName(const EnumValueDescriptor* enum_value); +PROTOC_EXPORT TProtoStringType EnumValueName(const EnumValueDescriptor* enum_value); // Strips ".proto" or ".protodevel" from the end of a filename. -PROTOC_EXPORT TProtoStringType StripProto(const TProtoStringType& filename); +PROTOC_EXPORT TProtoStringType StripProto(y_absl::string_view filename); } // namespace cpp } // namespace compiler } // namespace protobuf } // namespace google -#include <google/protobuf/port_undef.inc> +#include "google/protobuf/port_undef.inc" #endif // GOOGLE_PROTOBUF_COMPILER_CPP_NAMES_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/options.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/options.h index 14546ca6187..449ed69f5d1 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/options.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/options.h @@ -33,14 +33,17 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ -#include <set> #include <string> + +#include "y_absl/container/flat_hash_set.h" + #include <google/protobuf/stubs/port.h> namespace google { namespace protobuf { namespace compiler { class AccessInfoMap; +class SplitMap; namespace cpp { @@ -53,12 +56,13 @@ enum class EnforceOptimizeMode { struct FieldListenerOptions { bool inject_field_listener_events = false; - std::set<TProtoStringType> forbidden_field_listener_events; + y_absl::flat_hash_set<TProtoStringType> forbidden_field_listener_events; }; // Generator options (see generator.cc for a description of each): struct Options { const AccessInfoMap* access_info_map = nullptr; + const SplitMap* split_map = nullptr; TProtoStringType dllexport_decl; TProtoStringType runtime_include_base; TProtoStringType annotation_pragma_name; @@ -79,12 +83,10 @@ struct Options { bool bootstrap = false; bool opensource_runtime = false; bool annotate_accessor = false; - bool unused_field_stripping = false; bool unverified_lazy_message_sets = false; - bool unverified_lazy = false; bool profile_driven_inline_string = true; - bool message_owned_arena_trial = false; bool force_split = false; + bool profile_driven_split = true; #ifdef PROTOBUF_STABLE_EXPERIMENTS bool force_eagerly_verified_lazy = true; bool force_inline_string = true; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.cc index 20910520d63..5f2bfba18c4 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.cc @@ -28,9 +28,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <google/protobuf/compiler/cpp/padding_optimizer.h> +#include "google/protobuf/compiler/cpp/padding_optimizer.h" -#include <google/protobuf/compiler/cpp/helpers.h> +#include "y_absl/log/absl_log.h" +#include "google/protobuf/compiler/cpp/helpers.h" namespace google { namespace protobuf { @@ -85,41 +86,11 @@ class FieldGroup { } // namespace -// Reorder 'fields' so that if the fields are output into a c++ class in the new -// order, fields of similar family (see below) are together and within each -// family, alignment padding is minimized. -// -// We try to do this while keeping each field as close as possible to its field -// number order so that we don't reduce cache locality much for function that -// access each field in order. Originally, OptimizePadding used declaration -// order for its decisions, but generated code minus the serializer/parsers uses -// the output of OptimizePadding as well (stored in -// MessageGenerator::optimized_order_). Since the serializers use field number -// order, we use that as a tie-breaker. -// -// We classify each field into a particular "family" of fields, that we perform -// the same operation on in our generated functions. -// -// REPEATED is placed first, as the C++ compiler automatically initializes -// these fields in layout order. -// -// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and -// calls ArenaStringPtr::Destroy on each. -// -// LAZY_MESSAGE is grouped next, as it interferes with the ability to memset -// non-repeated fields otherwise. -// -// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls -// delete on each. We initialize these fields with a NULL pointer (see -// MessageFieldGenerator::GenerateConstructorCode), which allows them to be -// memset. -// -// ZERO_INITIALIZABLE is memset in Clear/SharedCtor -// -// OTHER these fields are initialized one-by-one. -void PaddingOptimizer::OptimizeLayout( - std::vector<const FieldDescriptor*>* fields, const Options& options, - MessageSCCAnalyzer* scc_analyzer) { +static void OptimizeLayoutHelper(std::vector<const FieldDescriptor*>* fields, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + if (fields->empty()) return; + // The sorted numeric order of Family determines the declaration order in the // memory layout. enum Family { @@ -151,7 +122,7 @@ void PaddingOptimizer::OptimizeLayout( if (IsLazy(field, options, scc_analyzer)) { f = LAZY_MESSAGE; } - } else if (CanInitializeByZeroing(field)) { + } else if (CanInitializeByZeroing(field, options, scc_analyzer)) { f = ZERO_INITIALIZABLE; } @@ -167,8 +138,9 @@ void PaddingOptimizer::OptimizeLayout( aligned_to_8[f].push_back(FieldGroup(j, field)); break; default: - GOOGLE_LOG(FATAL) << "Unknown alignment size " << EstimateAlignmentSize(field) - << "for a field " << field->full_name() << "."; + Y_ABSL_LOG(FATAL) << "Unknown alignment size " + << EstimateAlignmentSize(field) << "for a field " + << field->full_name() << "."; } } @@ -222,6 +194,61 @@ void PaddingOptimizer::OptimizeLayout( } } +// Reorder 'fields' so that if the fields are output into a c++ class in the new +// order, fields of similar family (see below) are together and within each +// family, alignment padding is minimized. +// +// We try to do this while keeping each field as close as possible to its field +// number order so that we don't reduce cache locality much for function that +// access each field in order. Originally, OptimizePadding used declaration +// order for its decisions, but generated code minus the serializer/parsers uses +// the output of OptimizePadding as well (stored in +// MessageGenerator::optimized_order_). Since the serializers use field number +// order, we use that as a tie-breaker. +// +// We classify each field into a particular "family" of fields, that we perform +// the same operation on in our generated functions. +// +// REPEATED is placed first, as the C++ compiler automatically initializes +// these fields in layout order. +// +// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and +// calls ArenaStringPtr::Destroy on each. +// +// LAZY_MESSAGE is grouped next, as it interferes with the ability to memset +// non-repeated fields otherwise. +// +// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls +// delete on each. We initialize these fields with a NULL pointer (see +// MessageFieldGenerator::GenerateConstructorCode), which allows them to be +// memset. +// +// ZERO_INITIALIZABLE is memset in Clear/SharedCtor +// +// OTHER these fields are initialized one-by-one. +// +// If there are split fields in `fields`, they will be placed at the end. The +// order within split fields follows the same rule, aka classify and order by +// "family". +void PaddingOptimizer::OptimizeLayout( + std::vector<const FieldDescriptor*>* fields, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + std::vector<const FieldDescriptor*> normal; + std::vector<const FieldDescriptor*> split; + for (const auto* field : *fields) { + if (ShouldSplit(field, options)) { + split.push_back(field); + } else { + normal.push_back(field); + } + } + OptimizeLayoutHelper(&normal, options, scc_analyzer); + OptimizeLayoutHelper(&split, options, scc_analyzer); + fields->clear(); + fields->insert(fields->end(), normal.begin(), normal.end()); + fields->insert(fields->end(), split.begin(), split.end()); +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.h index 9c76f38c471..4f55e649a3d 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.h @@ -35,7 +35,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ -#include <google/protobuf/compiler/cpp/message_layout_helper.h> +#include "google/protobuf/compiler/cpp/message_layout_helper.h" namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.cc index 1b97182acd6..74ede841a8f 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -28,15 +28,25 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <google/protobuf/compiler/cpp/parse_function_generator.h> +#include "google/protobuf/compiler/cpp/parse_function_generator.h" #include <algorithm> #include <limits> #include <string> #include <utility> +#include <vector> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/compiler/cpp/helpers.h> +#include "y_absl/container/flat_hash_map.h" +#include "y_absl/log/absl_log.h" +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/generated_message_tctable_gen.h" +#include "google/protobuf/generated_message_tctable_impl.h" +#include "google/protobuf/wire_format.h" + +#include "util/generic/string.h" + +using TProtoStringType = TString; namespace google { namespace protobuf { @@ -44,16 +54,26 @@ namespace compiler { namespace cpp { namespace { +using internal::TailCallTableInfo; +using internal::cpp::Utf8CheckMode; using google::protobuf::internal::WireFormat; using google::protobuf::internal::WireFormatLite; +bool UseDirectTcParserTable(const FieldDescriptor* field, + const Options& options) { + if (field->cpp_type() != field->CPPTYPE_MESSAGE) return false; + auto* m = field->message_type(); + return !m->options().message_set_wire_format() && + m->file()->options().optimize_for() != FileOptions::CODE_SIZE && + !HasSimpleBaseClass(m, options) && !HasTracker(m, options) + ; // NOLINT(whitespace/semicolon) +} + std::vector<const FieldDescriptor*> GetOrderedFields( const Descriptor* descriptor, const Options& options) { std::vector<const FieldDescriptor*> ordered_fields; for (auto field : FieldRange(descriptor)) { - if (!IsFieldStripped(field, options)) { - ordered_fields.push_back(field); - } + ordered_fields.push_back(field); } std::sort(ordered_fields.begin(), ordered_fields.end(), [](const FieldDescriptor* a, const FieldDescriptor* b) { @@ -66,371 +86,33 @@ bool HasInternalAccessors(const FieldOptions::CType ctype) { return ctype == FieldOptions::STRING || ctype == FieldOptions::CORD; } -int TagSize(arc_ui32 field_number) { - if (field_number < 16) return 1; - GOOGLE_CHECK_LT(field_number, (1 << 14)) - << "coded tag for " << field_number << " too big for uint16_t"; - return 2; -} - -TProtoStringType FieldParseFunctionName( - const TailCallTableInfo::FieldEntryInfo& entry, const Options& options); - -bool IsFieldEligibleForFastParsing( - const TailCallTableInfo::FieldEntryInfo& entry, const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - const auto* field = entry.field; - // Map, oneof, weak, and lazy fields are not handled on the fast path. - if (field->is_map() || field->real_containing_oneof() || - field->options().weak() || - IsImplicitWeakField(field, options, scc_analyzer) || - IsLazy(field, options, scc_analyzer)) { - return false; - } - - // We will check for a valid auxiliary index range later. However, we might - // want to change the value we check for inlined string fields. - int aux_idx = entry.aux_idx; - - switch (field->type()) { - case FieldDescriptor::TYPE_ENUM: - // If enum values are not validated at parse time, then this field can be - // handled on the fast path like an int32. - if (HasPreservingUnknownEnumSemantics(field)) { - break; - } - if (field->is_repeated() && field->is_packed()) { - return false; - } - break; - - // Some bytes fields can be handled on fast path. - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - if (field->options().ctype() != FieldOptions::STRING) { - return false; - } - if (IsStringInlined(field, options)) { - GOOGLE_CHECK(!field->is_repeated()); - // For inlined strings, the donation state index is stored in the - // `aux_idx` field of the fast parsing info. We need to check the range - // of that value instead of the auxiliary index. - aux_idx = entry.inlined_string_idx; - } - break; - - default: - break; - } - - if (HasHasbit(field)) { - // The tailcall parser can only update the first 32 hasbits. Fields with - // has-bits beyond the first 32 are handled by mini parsing/fallback. - GOOGLE_CHECK_GE(entry.hasbit_idx, 0) << field->DebugString(); - if (entry.hasbit_idx >= 32) return false; - } - - // If the field needs auxiliary data, then the aux index is needed. This - // must fit in a uint8_t. - if (aux_idx > std::numeric_limits<uint8_t>::max()) { - return false; - } - - // The largest tag that can be read by the tailcall parser is two bytes - // when varint-coded. This allows 14 bits for the numeric tag value: - // byte 0 byte 1 - // 1nnnnttt 0nnnnnnn - // ^^^^^^^ ^^^^^^^ - if (field->number() >= 1 << 11) return false; - - return true; -} - -std::vector<TailCallTableInfo::FastFieldInfo> SplitFastFieldsForSize( - const std::vector<TailCallTableInfo::FieldEntryInfo>& field_entries, - int table_size_log2, const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - std::vector<TailCallTableInfo::FastFieldInfo> result(1 << table_size_log2); - const arc_ui32 idx_mask = result.size() - 1; - - for (const auto& entry : field_entries) { - if (!IsFieldEligibleForFastParsing(entry, options, scc_analyzer)) { - continue; - } - - const auto* field = entry.field; - arc_ui32 tag = WireFormat::MakeTag(field); - - // Construct the varint-coded tag. If it is more than 7 bits, we need to - // shift the high bits and add a continue bit. - if (arc_ui32 hibits = tag & 0xFFFFFF80) { - tag = tag + hibits + 128; // tag = lobits + 2*hibits + 128 - } - - // The field index is determined by the low bits of the field number, where - // the table size determines the width of the mask. The largest table - // supported is 32 entries. The parse loop uses these bits directly, so that - // the dispatch does not require arithmetic: - // byte 0 byte 1 - // tag: 1nnnnttt 0nnnnnnn - // ^^^^^ - // idx (table_size_log2=5) - // This means that any field number that does not fit in the lower 4 bits - // will always have the top bit of its table index asserted. - const arc_ui32 fast_idx = (tag >> 3) & idx_mask; - - TailCallTableInfo::FastFieldInfo& info = result[fast_idx]; - if (info.field != nullptr) { - // This field entry is already filled. - continue; - } - - // Fill in this field's entry: - GOOGLE_CHECK(info.func_name.empty()) << info.func_name; - info.func_name = FieldParseFunctionName(entry, options); - info.field = field; - info.coded_tag = tag; - // If this field does not have presence, then it can set an out-of-bounds - // bit (tailcall parsing uses a arc_ui64 for hasbits, but only stores 32). - info.hasbit_idx = HasHasbit(field) ? entry.hasbit_idx : 63; - if (IsStringInlined(field, options)) { - GOOGLE_CHECK(!field->is_repeated()); - info.aux_idx = static_cast<uint8_t>(entry.inlined_string_idx); - } else { - info.aux_idx = static_cast<uint8_t>(entry.aux_idx); - } - } - return result; -} - -// Filter out fields that will be handled by mini parsing. -std::vector<const FieldDescriptor*> FilterMiniParsedFields( - const std::vector<const FieldDescriptor*>& fields, const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - std::vector<const FieldDescriptor*> generated_fallback_fields; - - for (const auto* field : fields) { - bool handled = false; - switch (field->type()) { - case FieldDescriptor::TYPE_DOUBLE: - case FieldDescriptor::TYPE_FLOAT: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_BOOL: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_INT64: - // These are handled by MiniParse, so we don't need any generated - // fallback code. - handled = true; - break; - - case FieldDescriptor::TYPE_ENUM: - if (field->is_repeated() && !HasPreservingUnknownEnumSemantics(field)) { - // TODO(b/206890171): handle packed repeated closed enums - // Non-packed repeated can be handled using tables, but we still - // need to generate fallback code for all repeated enums in order to - // handle packed encoding. This is because of the lite/full split - // when handling invalid enum values in a packed field. - handled = false; - } else { - handled = true; - } - break; - - case FieldDescriptor::TYPE_BYTES: - case FieldDescriptor::TYPE_STRING: - if (IsStringInlined(field, options)) { - // TODO(b/198211897): support InilnedStringField. - handled = false; - } else { - handled = true; - } - break; - - case FieldDescriptor::TYPE_MESSAGE: - case FieldDescriptor::TYPE_GROUP: - // TODO(b/210762816): support remaining field types. - if (field->is_map() || IsWeak(field, options) || - IsImplicitWeakField(field, options, scc_analyzer) || - IsLazy(field, options, scc_analyzer)) { - handled = false; - } else { - handled = true; - } - break; - - default: - handled = false; - break; - } - if (!handled) generated_fallback_fields.push_back(field); - } - - return generated_fallback_fields; -} - } // namespace -TailCallTableInfo::TailCallTableInfo( - const Descriptor* descriptor, const Options& options, - const std::vector<const FieldDescriptor*>& ordered_fields, - const std::vector<int>& has_bit_indices, - const std::vector<int>& inlined_string_indices, - MessageSCCAnalyzer* scc_analyzer) { - int oneof_count = descriptor->real_oneof_decl_count(); - // If this message has any oneof fields, store the case offset in the first - // auxiliary entry. - if (oneof_count > 0) { - GOOGLE_LOG_IF(DFATAL, ordered_fields.empty()) - << "Invalid message: " << descriptor->full_name() << " has " - << oneof_count << " oneof declarations, but no fields"; - aux_entries.push_back(StrCat("_fl::Offset{offsetof(", - ClassName(descriptor), - ", _impl_._oneof_case_)}")); +class ParseFunctionGenerator::GeneratedOptionProvider final + : public internal::TailCallTableInfo::OptionProvider { + public: + explicit GeneratedOptionProvider(ParseFunctionGenerator* gen) : gen_(gen) {} + TailCallTableInfo::PerFieldOptions GetForField( + const FieldDescriptor* field) const final { + return {IsLazy(field, gen_->options_, gen_->scc_analyzer_), + IsStringInlined(field, gen_->options_), + IsImplicitWeakField(field, gen_->options_, gen_->scc_analyzer_), + UseDirectTcParserTable(field, gen_->options_), + GetOptimizeFor(field->file(), gen_->options_) == + FileOptions::LITE_RUNTIME, + ShouldSplit(field, gen_->options_)}; } - // If this message has any inlined string fields, store the donation state - // offset in the second auxiliary entry. - if (!inlined_string_indices.empty()) { - aux_entries.resize(2); // pad if necessary - aux_entries[1] = - StrCat("_fl::Offset{offsetof(", ClassName(descriptor), - ", _impl_._inlined_string_donated_)}"); - } - - // Fill in mini table entries. - for (const FieldDescriptor* field : ordered_fields) { - field_entries.push_back( - {field, (HasHasbit(field) ? has_bit_indices[field->index()] : -1)}); - auto& entry = field_entries.back(); - - if (field->type() == FieldDescriptor::TYPE_MESSAGE || - field->type() == FieldDescriptor::TYPE_GROUP) { - // Message-typed fields have a FieldAux with the default instance pointer. - if (field->is_map()) { - // TODO(b/205904770): generate aux entries for maps - } else if (IsWeak(field, options)) { - // Don't generate anything for weak fields. They are handled by the - // generated fallback. - } else if (IsImplicitWeakField(field, options, scc_analyzer)) { - // Implicit weak fields don't need to store a default instance pointer. - } else if (IsLazy(field, options, scc_analyzer)) { - // Lazy fields are handled by the generated fallback function. - } else { - field_entries.back().aux_idx = aux_entries.size(); - const Descriptor* field_type = field->message_type(); - aux_entries.push_back(StrCat( - "reinterpret_cast<const ", QualifiedClassName(field_type, options), - "*>(&", QualifiedDefaultInstanceName(field_type, options), ")")); - } - } else if (field->type() == FieldDescriptor::TYPE_ENUM && - !HasPreservingUnknownEnumSemantics(field)) { - // Enum fields which preserve unknown values (proto3 behavior) are - // effectively int32 fields with respect to parsing -- i.e., the value - // does not need to be validated at parse time. - // - // Enum fields which do not preserve unknown values (proto2 behavior) use - // a FieldAux to store validation information. If the enum values are - // sequential (and within a range we can represent), then the FieldAux - // entry represents the range using the minimum value (which must fit in - // an int16_t) and count (a uint16_t). Otherwise, the entry holds a - // pointer to the generated Name_IsValid function. - - entry.aux_idx = aux_entries.size(); - const EnumDescriptor* enum_type = field->enum_type(); - GOOGLE_CHECK_GT(enum_type->value_count(), 0) << enum_type->DebugString(); - - // Check if the enum values are a single, contiguous range. - std::vector<int> enum_values; - for (int i = 0, N = enum_type->value_count(); i < N; ++i) { - enum_values.push_back(enum_type->value(i)->number()); - } - auto values_begin = enum_values.begin(); - auto values_end = enum_values.end(); - std::sort(values_begin, values_end); - enum_values.erase(std::unique(values_begin, values_end), values_end); - - if (enum_values.back() - enum_values[0] == enum_values.size() - 1 && - enum_values[0] >= std::numeric_limits<int16_t>::min() && - enum_values[0] <= std::numeric_limits<int16_t>::max() && - enum_values.size() <= std::numeric_limits<uint16_t>::max()) { - entry.is_enum_range = true; - aux_entries.push_back( - StrCat(enum_values[0], ", ", enum_values.size())); - } else { - entry.is_enum_range = false; - aux_entries.push_back( - StrCat(QualifiedClassName(enum_type, options), "_IsValid")); - } - } else if ((field->type() == FieldDescriptor::TYPE_STRING || - field->type() == FieldDescriptor::TYPE_BYTES) && - IsStringInlined(field, options)) { - GOOGLE_CHECK(!field->is_repeated()); - // Inlined strings have an extra marker to represent their donation state. - int idx = inlined_string_indices[field->index()]; - // For mini parsing, the donation state index is stored as an `offset` - // auxiliary entry. - entry.aux_idx = aux_entries.size(); - aux_entries.push_back(StrCat("_fl::Offset{", idx, "}")); - // For fast table parsing, the donation state index is stored instead of - // the aux_idx (this will limit the range to 8 bits). - entry.inlined_string_idx = idx; - } - } - - // Choose the smallest fast table that covers the maximum number of fields. - table_size_log2 = 0; // fallback value - int num_fast_fields = -1; - for (int try_size_log2 : {0, 1, 2, 3, 4, 5}) { - size_t try_size = 1 << try_size_log2; - auto split_fields = SplitFastFieldsForSize(field_entries, try_size_log2, - options, scc_analyzer); - GOOGLE_CHECK_EQ(split_fields.size(), try_size); - int try_num_fast_fields = 0; - for (const auto& info : split_fields) { - if (info.field != nullptr) ++try_num_fast_fields; - } - // Use this size if (and only if) it covers more fields. - if (try_num_fast_fields > num_fast_fields) { - fast_path_fields = std::move(split_fields); - table_size_log2 = try_size_log2; - num_fast_fields = try_num_fast_fields; - } - // The largest table we allow has the same number of entries as the message - // has fields, rounded up to the next power of 2 (e.g., a message with 5 - // fields can have a fast table of size 8). A larger table *might* cover - // more fields in certain cases, but a larger table in that case would have - // mostly empty entries; so, we cap the size to avoid pathologically sparse - // tables. - if (try_size > ordered_fields.size()) { - break; - } - } - - // Filter out fields that are handled by MiniParse. We don't need to generate - // a fallback for these, which saves code size. - fallback_fields = FilterMiniParsedFields(ordered_fields, options, - scc_analyzer); - - // If there are no fallback fields, and at most one extension range, the - // parser can use a generic fallback function. Otherwise, a message-specific - // fallback routine is needed. - use_generated_fallback = - !fallback_fields.empty() || descriptor->extension_range_count() > 1; -} + private: + ParseFunctionGenerator* gen_; +}; ParseFunctionGenerator::ParseFunctionGenerator( const Descriptor* descriptor, int max_has_bit_index, const std::vector<int>& has_bit_indices, const std::vector<int>& inlined_string_indices, const Options& options, MessageSCCAnalyzer* scc_analyzer, - const std::map<TProtoStringType, TProtoStringType>& vars) + const y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>& vars) : descriptor_(descriptor), scc_analyzer_(scc_analyzer), options_(options), @@ -440,10 +122,9 @@ ParseFunctionGenerator::ParseFunctionGenerator( num_hasbits_(max_has_bit_index) { if (should_generate_tctable()) { tc_table_info_.reset(new TailCallTableInfo( - descriptor_, options_, ordered_fields_, has_bit_indices, - inlined_string_indices, scc_analyzer)); + descriptor_, ordered_fields_, GeneratedOptionProvider(this), + has_bit_indices, inlined_string_indices)); } - SetCommonVars(options_, &variables_); SetCommonMessageDataVariables(descriptor_, &variables_); SetUnknownFieldsVariable(descriptor_, options_, &variables_); variables_["classname"] = ClassName(descriptor, false); @@ -518,11 +199,14 @@ bool ParseFunctionGenerator::should_generate_tctable() const { if (options_.tctable_mode == Options::kTCTableNever) { return false; } + if (HasSimpleBaseClass(descriptor_, options_)) { + return false; + } return true; } void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) { - GOOGLE_CHECK(should_generate_tctable()); + Y_ABSL_CHECK(should_generate_tctable()); // Generate an `_InternalParse` that starts the tail-calling loop. format( @@ -536,20 +220,47 @@ void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) { "}\n\n"); } +static bool NeedsUnknownEnumSupport(const Descriptor* descriptor) { + for (int i = 0; i < descriptor->field_count(); ++i) { + auto* field = descriptor->field(i); + if (field->is_repeated() && field->cpp_type() == field->CPPTYPE_ENUM && + !internal::cpp::HasPreservingUnknownEnumSemantics(field)) { + return true; + } + } + return false; +} + void ParseFunctionGenerator::GenerateTailcallFallbackFunction( Formatter& format) { - GOOGLE_CHECK(should_generate_tctable()); + Y_ABSL_CHECK(should_generate_tctable()); format( "const char* $classname$::Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL) {\n" "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr\n"); format.Indent(); format("auto* typed_msg = static_cast<$classname$*>(msg);\n"); + // If we need a side channel, generate the check to jump to the generic + // handler to deal with the side channel data. + if (NeedsUnknownEnumSupport(descriptor_)) { + format( + "if (PROTOBUF_PREDICT_FALSE(\n" + " _pbi::TcParser::MustFallbackToGeneric(PROTOBUF_TC_PARAM_PASS))) " + "{\n" + " PROTOBUF_MUSTTAIL return " + "::_pbi::TcParser::GenericFallback$1$(PROTOBUF_TC_PARAM_PASS);\n" + "}\n", + GetOptimizeFor(descriptor_->file(), options_) == + FileOptions::LITE_RUNTIME + ? "Lite" + : ""); + } + if (num_hasbits_ > 0) { // Sync hasbits - format("typed_msg->_impl_._has_bits_[0] = hasbits;\n"); + format("typed_msg->_impl_._has_bits_[0] |= hasbits;\n"); } - format("arc_ui32 tag = data.tag();\n"); + format("::arc_ui32 tag = data.tag();\n"); format.Set("msg", "typed_msg->"); format.Set("this", "typed_msg"); @@ -592,6 +303,12 @@ struct NumToEntryTable { static NumToEntryTable MakeNumToEntryTable( const std::vector<const FieldDescriptor*>& field_descriptors); +static int FieldNameDataSize(const std::vector<uint8_t>& data) { + // We add a +1 here to allow for a NUL termination character. It makes the + // codegen nicer. + return data.empty() ? 0 : data.size() + 1; +} + void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { if (!should_generate_tctable()) { return; @@ -604,10 +321,12 @@ void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { } auto field_num_to_entry_table = MakeNumToEntryTable(ordered_fields_); format( + "friend class ::$proto_ns$::internal::TcParser;\n" "static const ::$proto_ns$::internal::" "TcParseTable<$1$, $2$, $3$, $4$, $5$> _table_;\n", tc_table_info_->table_size_log2, ordered_fields_.size(), - tc_table_info_->aux_entries.size(), CalculateFieldNamesSize(), + tc_table_info_->aux_entries.size(), + FieldNameDataSize(tc_table_info_->field_name_data), field_num_to_entry_table.size16()); if (should_generate_guarded_tctable()) { format.Outdent(); @@ -656,7 +375,7 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { format.Indent(); format( - "arc_ui32 tag;\n" + "::arc_ui32 tag;\n" "ptr = ::_pbi::ReadTag(ptr, &tag);\n"); GenerateParseIterationBody(format, descriptor_, ordered_fields_); @@ -706,7 +425,7 @@ static NumToEntryTable MakeNumToEntryTable( for (; field_entry_index != N; ++field_entry_index) { auto* field_descriptor = field_descriptors[field_entry_index]; arc_ui32 fnum = field_descriptor->number(); - GOOGLE_CHECK_GT(fnum, last_skip_entry_start); + Y_ABSL_CHECK_GT(fnum, last_skip_entry_start); if (start_new_block == false) { // If the next field number is within 15 of the last_skip_entry_start, we // continue writing just to that entry. If it's between 16 and 31 more, @@ -739,16 +458,16 @@ static NumToEntryTable MakeNumToEntryTable( } void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { - GOOGLE_CHECK(should_generate_tctable()); + Y_ABSL_CHECK(should_generate_tctable()); // All entries without a fast-path parsing function need a fallback. TProtoStringType fallback; if (tc_table_info_->use_generated_fallback) { - fallback = ClassName(descriptor_) + "::Tct_ParseFallback"; + fallback = y_absl::StrCat(ClassName(descriptor_), "::Tct_ParseFallback"); } else { fallback = "::_pbi::TcParser::GenericFallback"; if (GetOptimizeFor(descriptor_->file(), options_) == FileOptions::LITE_RUNTIME) { - fallback += "Lite"; + y_absl::StrAppend(&fallback, "Lite"); } } @@ -761,12 +480,13 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { // unknown fields and potentially an extension range. auto field_num_to_entry_table = MakeNumToEntryTable(ordered_fields_); format( - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1\n" + "PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1\n" "const ::_pbi::TcParseTable<$1$, $2$, $3$, $4$, $5$> " "$classname$::_table_ = " "{\n", tc_table_info_->table_size_log2, ordered_fields_.size(), - tc_table_info_->aux_entries.size(), CalculateFieldNamesSize(), + tc_table_info_->aux_entries.size(), + FieldNameDataSize(tc_table_info_->field_name_data), field_num_to_entry_table.size16()); { auto table_scope = format.ScopedIndent(); @@ -849,7 +569,7 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { format("65535, 65535\n"); } if (ordered_fields_.empty()) { - GOOGLE_LOG_IF(DFATAL, !tc_table_info_->aux_entries.empty()) + Y_ABSL_DLOG_IF(FATAL, !tc_table_info_->aux_entries.empty()) << "Invalid message: " << descriptor_->full_name() << " has " << tc_table_info_->aux_entries.size() << " auxiliary field entries, but no fields"; @@ -874,19 +594,62 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { { // aux_entries[] auto aux_scope = format.ScopedIndent(); - for (const TProtoStringType& aux_entry : tc_table_info_->aux_entries) { - format("{$1$},\n", aux_entry); + for (const auto& aux_entry : tc_table_info_->aux_entries) { + switch (aux_entry.type) { + case TailCallTableInfo::kNothing: + format("{},\n"); + break; + case TailCallTableInfo::kInlinedStringDonatedOffset: + format( + "{_fl::Offset{offsetof($classname$, " + "_impl_._inlined_string_donated_)}},\n"); + break; + case TailCallTableInfo::kSplitOffset: + format( + "{_fl::Offset{offsetof($classname$, _impl_._split_)}},\n"); + break; + case TailCallTableInfo::kSplitSizeof: + format("{_fl::Offset{sizeof($classname$::Impl_::Split)}},\n"); + break; + case TailCallTableInfo::kSubMessage: + format("{::_pbi::FieldAuxDefaultMessage{}, &$1$},\n", + QualifiedDefaultInstanceName( + aux_entry.field->message_type(), options_)); + break; + case TailCallTableInfo::kSubTable: + format("{::_pbi::TcParser::GetTable<$1$>()},\n", + QualifiedClassName(aux_entry.field->message_type(), + options_)); + break; + case TailCallTableInfo::kSubMessageWeak: + format("{::_pbi::FieldAuxDefaultMessage{}, &$1$},\n", + QualifiedDefaultInstancePtr( + aux_entry.field->message_type(), options_)); + break; + case TailCallTableInfo::kEnumRange: + format("{$1$, $2$},\n", aux_entry.enum_range.start, + aux_entry.enum_range.size); + break; + case TailCallTableInfo::kEnumValidator: + format( + "{$1$_IsValid},\n", + QualifiedClassName(aux_entry.field->enum_type(), options_)); + break; + case TailCallTableInfo::kNumericOffset: + format("{_fl::Offset{$1$}},\n", aux_entry.offset); + break; + } } } format("}}, {{\n"); } } // ordered_fields_.empty() - { - // field_names[] - auto field_name_scope = format.ScopedIndent(); - GenerateFieldNames(format); - } - format("}},\n"); + { + // field_names[] + auto field_name_scope = format.ScopedIndent(); + GenerateFieldNames(format); + } + format("}},\n"); } format("};\n\n"); // _table_ } @@ -898,145 +661,174 @@ void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) { } if (info.func_name.empty()) { format("{::_pbi::TcParser::MiniParse, {}},\n"); + } else if (info.field == nullptr) { + // Fast slot that is not associated with a field. Eg end group tags. + format("{$1$, {$2$, $3$}},\n", info.func_name, info.coded_tag, + info.nonfield_info); } else { - bool cold = ShouldSplit(info.field, options_); + Y_ABSL_CHECK(!ShouldSplit(info.field, options_)); + + TProtoStringType func_name = info.func_name; + if (GetOptimizeFor(info.field->file(), options_) == FileOptions::SPEED) { + // For 1-byte tags we have a more optimized version of the varint parser + // that can hardcode the offset and has bit. + if (y_absl::EndsWith(func_name, "V8S1") || + y_absl::EndsWith(func_name, "V32S1") || + y_absl::EndsWith(func_name, "V64S1")) { + TProtoStringType field_type = y_absl::EndsWith(func_name, "V8S1") ? "bool" + : y_absl::EndsWith(func_name, "V32S1") + ? "::arc_ui32" + : "::arc_ui64"; + func_name = y_absl::StrCat( + "::_pbi::TcParser::SingularVarintNoZag1<", field_type, + ", offsetof(", // + ClassName(info.field->containing_type()), // + ", ", // + FieldMemberName(info.field, /*split=*/false), // + "), ", // + info.hasbit_idx, // + ">()"); + } + } + format( "{$1$,\n" - " {$2$, $3$, $4$, PROTOBUF_FIELD_OFFSET($classname$$5$, $6$)}},\n", - info.func_name, info.coded_tag, info.hasbit_idx, info.aux_idx, - cold ? "::Impl_::Split" : "", - cold ? FieldName(info.field) + "_" - : FieldMemberName(info.field, /*cold=*/false)); + " {$2$, $3$, $4$, PROTOBUF_FIELD_OFFSET($classname$, $5$)}},\n", + func_name, info.coded_tag, info.hasbit_idx, info.aux_idx, + FieldMemberName(info.field, /*split=*/false)); } } } static void FormatFieldKind(Formatter& format, - const TailCallTableInfo::FieldEntryInfo& entry, - const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - const FieldDescriptor* field = entry.field; - // Spell the field kind in proto language declaration order, starting with - // cardinality: - format("(::_fl::kFc"); - if (HasHasbit(field)) { - format("Optional"); - } else if (field->is_repeated()) { - format("Repeated"); - } else if (field->real_containing_oneof()) { - format("Oneof"); - } else { - format("Singular"); - } + const TailCallTableInfo::FieldEntryInfo& entry) { + // In here we convert the runtime value of entry.type_card back into a + // sequence of literal enum labels. We use the mnenonic labels for nicer + // codegen. + namespace fl = internal::field_layout; + const uint16_t type_card = entry.type_card; + const int rep_index = (type_card & fl::kRepMask) >> fl::kRepShift; + const int tv_index = (type_card & fl::kTvMask) >> fl::kTvShift; + + // Use `0|` prefix to eagerly convert the enums to int to avoid enum-enum + // operations. They are deprecated in C++20. + format("(0 | "); + static constexpr const char* kFieldCardNames[] = {"Singular", "Optional", + "Repeated", "Oneof"}; + static_assert((fl::kFcSingular >> fl::kFcShift) == 0, ""); + static_assert((fl::kFcOptional >> fl::kFcShift) == 1, ""); + static_assert((fl::kFcRepeated >> fl::kFcShift) == 2, ""); + static_assert((fl::kFcOneof >> fl::kFcShift) == 3, ""); + + format("::_fl::kFc$1$", + kFieldCardNames[(type_card & fl::kFcMask) >> fl::kFcShift]); + +#define PROTOBUF_INTERNAL_TYPE_CARD_CASE(x) \ + case fl::k##x: \ + format(" | ::_fl::k" #x); \ + break + + switch (type_card & fl::kFkMask) { + case fl::kFkString: { + switch (type_card & ~fl::kFcMask & ~fl::kRepMask & ~fl::kSplitMask) { + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Bytes); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(RawString); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Utf8String); + default: + Y_ABSL_LOG(FATAL) << "Unknown type_card: 0x" << type_card; + } - // The rest of the type uses convenience aliases: - format(" | ::_fl::k"); - if (field->is_repeated() && field->is_packed()) { - format("Packed"); - } - switch (field->type()) { - case FieldDescriptor::TYPE_DOUBLE: - format("Double"); - break; - case FieldDescriptor::TYPE_FLOAT: - format("Float"); - break; - case FieldDescriptor::TYPE_FIXED32: - format("Fixed32"); - break; - case FieldDescriptor::TYPE_SFIXED32: - format("SFixed32"); - break; - case FieldDescriptor::TYPE_FIXED64: - format("Fixed64"); - break; - case FieldDescriptor::TYPE_SFIXED64: - format("SFixed64"); - break; - case FieldDescriptor::TYPE_BOOL: - format("Bool"); + static constexpr const char* kRepNames[] = {"AString", "IString", "Cord", + "SPiece", "SString"}; + static_assert((fl::kRepAString >> fl::kRepShift) == 0, ""); + static_assert((fl::kRepIString >> fl::kRepShift) == 1, ""); + static_assert((fl::kRepCord >> fl::kRepShift) == 2, ""); + static_assert((fl::kRepSPiece >> fl::kRepShift) == 3, ""); + static_assert((fl::kRepSString >> fl::kRepShift) == 4, ""); + + format(" | ::_fl::kRep$1$", kRepNames[rep_index]); break; - case FieldDescriptor::TYPE_ENUM: - if (HasPreservingUnknownEnumSemantics(field)) { - // No validation is required. - format("OpenEnum"); - } else if (entry.is_enum_range) { - // Validation is done by range check (start/length in FieldAux). - format("EnumRange"); - } else { - // Validation uses the generated _IsValid function. - format("Enum"); + } + + case fl::kFkMessage: { + format(" | ::_fl::kMessage"); + + static constexpr const char* kRepNames[] = {nullptr, "Group", "Lazy"}; + static_assert((fl::kRepGroup >> fl::kRepShift) == 1, ""); + static_assert((fl::kRepLazy >> fl::kRepShift) == 2, ""); + + if (auto* rep = kRepNames[rep_index]) { + format(" | ::_fl::kRep$1$", rep); } - break; - case FieldDescriptor::TYPE_UINT32: - format("UInt32"); - break; - case FieldDescriptor::TYPE_SINT32: - format("SInt32"); - break; - case FieldDescriptor::TYPE_INT32: - format("Int32"); - break; - case FieldDescriptor::TYPE_UINT64: - format("UInt64"); - break; - case FieldDescriptor::TYPE_SINT64: - format("SInt64"); - break; - case FieldDescriptor::TYPE_INT64: - format("Int64"); - break; - case FieldDescriptor::TYPE_BYTES: - format("Bytes"); - break; - case FieldDescriptor::TYPE_STRING: { - auto mode = GetUtf8CheckMode(field, options); - switch (mode) { - case Utf8CheckMode::kStrict: - format("Utf8String"); - break; - case Utf8CheckMode::kVerify: - format("RawString"); - break; - case Utf8CheckMode::kNone: - // Treat LITE_RUNTIME strings as bytes. - format("Bytes"); - break; - default: - GOOGLE_LOG(FATAL) << "Invalid Utf8CheckMode (" << static_cast<int>(mode) - << ") for " << field->DebugString(); + static constexpr const char* kXFormNames[] = {nullptr, "Default", "Table", + "WeakPtr"}; + static_assert((fl::kTvDefault >> fl::kTvShift) == 1, ""); + static_assert((fl::kTvTable >> fl::kTvShift) == 2, ""); + static_assert((fl::kTvWeakPtr >> fl::kTvShift) == 3, ""); + + if (auto* xform = kXFormNames[tv_index]) { + format(" | ::_fl::kTv$1$", xform); } break; } - case FieldDescriptor::TYPE_GROUP: - format("Message | ::_fl::kRepGroup"); + case fl::kFkMap: + format(" | ::_fl::kMap"); break; - case FieldDescriptor::TYPE_MESSAGE: - if (field->is_map()) { - format("Map"); - } else { - format("Message"); - if (IsLazy(field, options, scc_analyzer)) { - format(" | ::_fl::kRepLazy"); - } else if (IsImplicitWeakField(field, options, scc_analyzer)) { - format(" | ::_fl::kRepIWeak"); - } - } + + case fl::kFkNone: break; - } - // Fill in extra information about string and bytes field representations. - if (field->type() == FieldDescriptor::TYPE_BYTES || - field->type() == FieldDescriptor::TYPE_STRING) { - if (field->is_repeated()) { - format(" | ::_fl::kRepSString"); - } else { - format(" | ::_fl::kRepAString"); + case fl::kFkVarint: + case fl::kFkPackedVarint: + case fl::kFkFixed: + case fl::kFkPackedFixed: { + switch (type_card & ~fl::kFcMask & ~fl::kSplitMask) { + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Bool); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Fixed32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(UInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(SFixed32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Int32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(SInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Float); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Enum); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(EnumRange); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(OpenEnum); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Fixed64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(UInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(SFixed64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Int64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(SInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Double); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedBool); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFixed32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedUInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSFixed32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFloat); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnum); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnumRange); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedOpenEnum); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFixed64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedUInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSFixed64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedDouble); + default: + Y_ABSL_LOG(FATAL) << "Unknown type_card: 0x" << type_card; + } } } + if (type_card & fl::kSplitMask) { + format(" | ::_fl::kSplitTrue"); + } + +#undef PROTOBUF_INTERNAL_TYPE_CARD_CASE + format(")"); } @@ -1051,91 +843,81 @@ void ParseFunctionGenerator::GenerateFieldEntries(Formatter& format) { format("/* weak */ 0, 0, 0, 0"); } else { const OneofDescriptor* oneof = field->real_containing_oneof(); - bool cold = ShouldSplit(field, options_); - format("PROTOBUF_FIELD_OFFSET($classname$$1$, $2$), $3$, $4$,\n ", - cold ? "::Impl_::Split" : "", - cold ? FieldName(field) + "_" - : FieldMemberName(field, /*cold=*/false), - (oneof ? oneof->index() : entry.hasbit_idx), entry.aux_idx); - FormatFieldKind(format, entry, options_, scc_analyzer_); + bool split = ShouldSplit(field, options_); + if (split) { + format("PROTOBUF_FIELD_OFFSET($classname$::Impl_::Split, $1$), ", + y_absl::StrCat(FieldName(field), "_")); + } else { + format("PROTOBUF_FIELD_OFFSET($classname$, $1$), ", + FieldMemberName(field, /*cold=*/false)); + } + if (oneof) { + format("_Internal::kOneofCaseOffset + $1$, ", 4 * oneof->index()); + } else if (num_hasbits_ > 0 || IsMapEntryMessage(descriptor_)) { + if (entry.hasbit_idx >= 0) { + format("_Internal::kHasBitsOffset + $1$, ", entry.hasbit_idx); + } else { + format("$1$, ", entry.hasbit_idx); + } + } else { + format("0, "); + } + format("$1$,\n ", entry.aux_idx); + FormatFieldKind(format, entry); } format("},\n"); } } -static constexpr int kMaxNameLength = 255; - -int ParseFunctionGenerator::CalculateFieldNamesSize() const { - // The full name of the message appears first. - int size = std::min(static_cast<int>(descriptor_->full_name().size()), - kMaxNameLength); - int lengths_size = 1; - for (const auto& entry : tc_table_info_->field_entries) { - const FieldDescriptor* field = entry.field; - GOOGLE_CHECK_LE(field->name().size(), kMaxNameLength); - size += field->name().size(); - lengths_size += 1; +void ParseFunctionGenerator::GenerateFieldNames(Formatter& format) { + if (tc_table_info_->field_name_data.empty()) { + // No names to output. + return; } - // align to an 8-byte boundary - lengths_size = (lengths_size + 7) & -8; - return size + lengths_size + 1; -} -static void FormatOctal(Formatter& format, int size) { - int octal_size = ((size >> 6) & 3) * 100 + // - ((size >> 3) & 7) * 10 + // - ((size >> 0) & 7); - format("\\$1$", octal_size); -} + // We could just output the bytes directly, but we want it to look better than + // that in the source code. Also, it is more efficient for compilation time to + // have a literal string than an initializer list of chars. -void ParseFunctionGenerator::GenerateFieldNames(Formatter& format) { - // First, we output the size of each string, as an unsigned byte. The first - // string is the message name. - int count = 1; + const int total_sizes = + static_cast<int>(((tc_table_info_->field_entries.size() + 1) + 7) & ~7); + const uint8_t* p = tc_table_info_->field_name_data.data(); + const uint8_t* sizes = p; + const uint8_t* sizes_end = sizes + total_sizes; + + // First print all the sizes as octal format("\""); - FormatOctal(format, - std::min(static_cast<int>(descriptor_->full_name().size()), 255)); - for (const auto& entry : tc_table_info_->field_entries) { - FormatOctal(format, entry.field->name().size()); - ++count; - } - while (count & 7) { // align to an 8-byte boundary - format("\\0"); - ++count; + for (int i = 0; i < total_sizes; ++i) { + int size = *p++; + int octal_size = ((size >> 6) & 3) * 100 + // + ((size >> 3) & 7) * 10 + // + ((size >> 0) & 7); + format("\\$1$", octal_size); } format("\"\n"); - // The message name is stored at the beginning of the string - TProtoStringType message_name = descriptor_->full_name(); - if (message_name.size() > kMaxNameLength) { - static constexpr int kNameHalfLength = (kMaxNameLength - 3) / 2; - message_name = StrCat( - message_name.substr(0, kNameHalfLength), "...", - message_name.substr(message_name.size() - kNameHalfLength)); - } - format("\"$1$\"\n", message_name); - // Then we output the actual field names - for (const auto& entry : tc_table_info_->field_entries) { - const FieldDescriptor* field = entry.field; - format("\"$1$\"\n", field->name()); + + // Then print each name in a line of its own + for (; sizes < sizes_end; p += *sizes++) { + if (*sizes != 0) format("\"$1$\"\n", TProtoStringType((const char*)p, (const char*)p + *sizes)); } } void ParseFunctionGenerator::GenerateArenaString(Formatter& format, const FieldDescriptor* field) { - if (HasHasbit(field)) { + if (internal::cpp::HasHasbit(field)) { format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field)); } format( "if (arena != nullptr) {\n" " ptr = ctx->ReadArenaString(ptr, &$msg$$field$, arena"); if (IsStringInlined(field, options_)) { - GOOGLE_DCHECK(!inlined_string_indices_.empty()); + Y_ABSL_DCHECK(!inlined_string_indices_.empty()); int inlined_string_index = inlined_string_indices_[field->index()]; - GOOGLE_DCHECK_GT(inlined_string_index, 0); + Y_ABSL_DCHECK_GT(inlined_string_index, 0); format(", &$msg$$inlined_string_donated_array$[0], $1$, $this$", inlined_string_index); } else { - GOOGLE_DCHECK(field->default_value_string().empty()); + Y_ABSL_DCHECK(field->default_value_string().empty()); } format( ");\n" @@ -1184,7 +966,9 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format, // to verify UTF8 when we already know parsing failed. format("CHK_(ptr);\n"); if (!check_utf8) return; // return if this is a bytes field - auto level = GetUtf8CheckMode(field, options_); + auto level = internal::cpp::GetUtf8CheckMode( + field, + GetOptimizeFor(field->file(), options_) == FileOptions::LITE_RUNTIME); switch (level) { case Utf8CheckMode::kNone: return; @@ -1198,7 +982,7 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format, TProtoStringType field_name; field_name = "nullptr"; if (HasDescriptorMethods(field->file(), options_)) { - field_name = StrCat("\"", field->full_name(), "\""); + field_name = y_absl::StrCat("\"", field->full_name(), "\""); } format("::_pbi::VerifyUTF8(str, $1$)", field_name); switch (level) { @@ -1219,7 +1003,7 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, const FieldDescriptor* field) { if (field->is_packable()) { if (field->type() == FieldDescriptor::TYPE_ENUM && - !HasPreservingUnknownEnumSemantics(field)) { + !internal::cpp::HasPreservingUnknownEnumSemantics(field)) { TProtoStringType enum_type = QualifiedClassName(field->enum_type(), options_); format( "ptr = " @@ -1246,9 +1030,9 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, case FieldDescriptor::TYPE_MESSAGE: { if (field->is_map()) { const FieldDescriptor* val = field->message_type()->map_value(); - GOOGLE_CHECK(val); + Y_ABSL_CHECK(val); if (val->type() == FieldDescriptor::TYPE_ENUM && - !HasPreservingUnknownEnumSemantics(field)) { + !internal::cpp::HasPreservingUnknownEnumSemantics(field)) { format( "auto object = " "::$proto_ns$::internal::InitEnumParseWrapper<" @@ -1267,13 +1051,13 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, format( "ctx->set_lazy_eager_verify_func($1$);\n", eager_verify - ? StrCat("&", ClassName(field->message_type(), true), + ? y_absl::StrCat("&", ClassName(field->message_type(), true), "::InternalVerify") : "nullptr"); } if (field->real_containing_oneof()) { format( - "if (!$msg$_internal_has_$name$()) {\n" + "if ($msg$$1$_case() != k$2$) {\n" " $msg$clear_$1$();\n" " $msg$$field$ = ::$proto_ns$::Arena::CreateMessage<\n" " ::$proto_ns$::internal::LazyField>(" @@ -1281,8 +1065,9 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, " $msg$set_has_$name$();\n" "}\n" "auto* lazy_field = $msg$$field$;\n", - field->containing_oneof()->name()); - } else if (HasHasbit(field)) { + field->containing_oneof()->name(), + UnderscoresToCamelCase(field->name(), true)); + } else if (internal::cpp::HasHasbit(field)) { format( "_Internal::set_has_$name$(&$has_bits$);\n" "auto* lazy_field = &$msg$$field$;\n"); @@ -1333,8 +1118,8 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, break; } default: - GOOGLE_LOG(FATAL) << "Illegal combination for length delimited wiretype " - << " filed type is " << field->type(); + Y_ABSL_LOG(FATAL) << "Illegal combination for length delimited wiretype " + << " filed type is " << field->type(); } } } @@ -1356,29 +1141,31 @@ void ParseFunctionGenerator::GenerateFieldBody( {{"name", FieldName(field)}, {"primitive_type", PrimitiveTypeName(options_, field->cpp_type())}}); if (field->is_repeated()) { - format.AddMap({{"put_field", StrCat("add_", FieldName(field))}, - {"mutable_field", StrCat("add_", FieldName(field))}}); + format.AddMap({{"put_field", y_absl::StrCat("add_", FieldName(field))}, + {"mutable_field", y_absl::StrCat("add_", FieldName(field))}}); } else { format.AddMap( - {{"put_field", StrCat("set_", FieldName(field))}, - {"mutable_field", StrCat("mutable_", FieldName(field))}}); + {{"put_field", y_absl::StrCat("set_", FieldName(field))}, + {"mutable_field", y_absl::StrCat("mutable_", FieldName(field))}}); } arc_ui32 tag = WireFormatLite::MakeTag(field->number(), wiretype); switch (wiretype) { case WireFormatLite::WIRETYPE_VARINT: { - TProtoStringType type = PrimitiveTypeName(options_, field->cpp_type()); if (field->type() == FieldDescriptor::TYPE_ENUM) { format.Set("enum_type", QualifiedClassName(field->enum_type(), options_)); format( - "$uint64$ val = ::$proto_ns$::internal::ReadVarint64(&ptr);\n" + "$uint32$ val = ::$proto_ns$::internal::ReadVarint32(&ptr);\n" "CHK_(ptr);\n"); - if (!HasPreservingUnknownEnumSemantics(field)) { - format("if (PROTOBUF_PREDICT_TRUE($enum_type$_IsValid(val))) {\n"); + if (!internal::cpp::HasPreservingUnknownEnumSemantics(field)) { + format( + "if " + "(PROTOBUF_PREDICT_TRUE($enum_type$_IsValid(static_cast<int>(val)" + "))) {\n"); format.Indent(); } format("$msg$_internal_$put_field$(static_cast<$enum_type$>(val));\n"); - if (!HasPreservingUnknownEnumSemantics(field)) { + if (!internal::cpp::HasPreservingUnknownEnumSemantics(field)) { format.Outdent(); format( "} else {\n" @@ -1405,7 +1192,7 @@ void ParseFunctionGenerator::GenerateFieldBody( "CHK_(ptr);\n", zigzag, size); } else { - if (HasHasbit(field)) { + if (internal::cpp::HasHasbit(field)) { format("_Internal::set_has_$name$(&$has_bits$);\n"); } format( @@ -1424,7 +1211,7 @@ void ParseFunctionGenerator::GenerateFieldBody( "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr));\n" "ptr += sizeof($primitive_type$);\n"); } else { - if (HasHasbit(field)) { + if (internal::cpp::HasHasbit(field)) { format("_Internal::set_has_$name$(&$has_bits$);\n"); } format( @@ -1446,7 +1233,7 @@ void ParseFunctionGenerator::GenerateFieldBody( break; } case WireFormatLite::WIRETYPE_END_GROUP: { - GOOGLE_LOG(FATAL) << "Can't have end group field\n"; + Y_ABSL_LOG(FATAL) << "Can't have end group field\n"; break; } } // switch (wire_type) @@ -1460,7 +1247,7 @@ static arc_ui32 ExpectedTag(const FieldDescriptor* field, if (field->is_packable()) { auto expected_wiretype = WireFormat::WireTypeForFieldType(field->type()); expected_tag = WireFormatLite::MakeTag(field->number(), expected_wiretype); - GOOGLE_CHECK(expected_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + Y_ABSL_CHECK(expected_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); auto fallback_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED; arc_ui32 fallback_tag = WireFormatLite::MakeTag(field->number(), fallback_wiretype); @@ -1599,8 +1386,9 @@ void ParseFunctionGenerator::GenerateFieldSwitch( format.Outdent(); } format( - "} else\n" + "} else {\n" " goto handle_unusual;\n" + "}\n" "$next_tag$;\n"); format.Outdent(); } // for loop over ordered fields @@ -1612,113 +1400,6 @@ void ParseFunctionGenerator::GenerateFieldSwitch( format("} // switch\n"); } -namespace { - -TProtoStringType FieldParseFunctionName( - const TailCallTableInfo::FieldEntryInfo& entry, const Options& options) { - const FieldDescriptor* field = entry.field; - TProtoStringType name = "::_pbi::TcParser::Fast"; - - switch (field->type()) { - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - case FieldDescriptor::TYPE_FLOAT: - name.append("F32"); - break; - - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_DOUBLE: - name.append("F64"); - break; - - case FieldDescriptor::TYPE_BOOL: - name.append("V8"); - break; - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_UINT32: - name.append("V32"); - break; - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT64: - name.append("V64"); - break; - - case FieldDescriptor::TYPE_ENUM: - if (HasPreservingUnknownEnumSemantics(field)) { - name.append("V32"); - break; - } - if (field->is_repeated() && field->is_packed()) { - GOOGLE_LOG(DFATAL) << "Enum validation not handled: " << field->DebugString(); - return ""; - } - name.append(entry.is_enum_range ? "Er" : "Ev"); - break; - - case FieldDescriptor::TYPE_SINT32: - name.append("Z32"); - break; - case FieldDescriptor::TYPE_SINT64: - name.append("Z64"); - break; - - case FieldDescriptor::TYPE_BYTES: - name.append("B"); - if (IsStringInlined(field, options)) { - name.append("i"); - } - break; - case FieldDescriptor::TYPE_STRING: - switch (GetUtf8CheckMode(field, options)) { - case Utf8CheckMode::kNone: - name.append("B"); - break; - case Utf8CheckMode::kVerify: - name.append("S"); - break; - case Utf8CheckMode::kStrict: - name.append("U"); - break; - default: - GOOGLE_LOG(DFATAL) << "Mode not handled: " - << static_cast<int>(GetUtf8CheckMode(field, options)); - return ""; - } - if (IsStringInlined(field, options)) { - name.append("i"); - } - break; - - case FieldDescriptor::TYPE_MESSAGE: - name.append("M"); - break; - case FieldDescriptor::TYPE_GROUP: - name.append("G"); - break; - - default: - GOOGLE_LOG(DFATAL) << "Type not handled: " << field->DebugString(); - return ""; - } - - // The field implementation functions are prefixed by cardinality: - // `S` for optional or implicit fields. - // `R` for non-packed repeated. - // `P` for packed repeated. - name.append(field->is_packed() ? "P" - : field->is_repeated() ? "R" - : field->real_containing_oneof() ? "O" - : "S"); - - // Append the tag length. Fast parsing only handles 1- or 2-byte tags. - name.append(TagSize(field->number()) == 1 ? "1" : "2"); - - return name; -} - -} // namespace - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.h index 7e2b674852f..c12c2057328 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.h @@ -31,72 +31,32 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__ -#include <map> #include <string> #include <vector> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/wire_format_lite.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/compiler/cpp/options.h> +#include "google/protobuf/descriptor.h" +#include "y_absl/container/flat_hash_map.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/generated_message_tctable_gen.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/wire_format_lite.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { -// Helper class for generating tailcall parsing functions. -struct TailCallTableInfo { - TailCallTableInfo(const Descriptor* descriptor, const Options& options, - const std::vector<const FieldDescriptor*>& ordered_fields, - const std::vector<int>& has_bit_indices, - const std::vector<int>& inlined_string_indices, - MessageSCCAnalyzer* scc_analyzer); - - // Fields parsed by the table fast-path. - struct FastFieldInfo { - TProtoStringType func_name; - const FieldDescriptor* field; - uint16_t coded_tag; - uint8_t hasbit_idx; - uint8_t aux_idx; - }; - std::vector<FastFieldInfo> fast_path_fields; - - // Fields parsed by mini parsing routines. - struct FieldEntryInfo { - const FieldDescriptor* field; - int hasbit_idx; - int inlined_string_idx; - uint16_t aux_idx; - // True for enums entirely covered by the start/length fields of FieldAux: - bool is_enum_range; - }; - std::vector<FieldEntryInfo> field_entries; - std::vector<TProtoStringType> aux_entries; - - // Fields parsed by generated fallback function. - std::vector<const FieldDescriptor*> fallback_fields; - - // Table size. - int table_size_log2; - // Mask for has-bits of required fields. - arc_ui32 has_hasbits_required_mask; - // True if a generated fallback function is required instead of generic. - bool use_generated_fallback; -}; - // ParseFunctionGenerator generates the _InternalParse function for a message // (and any associated supporting members). class ParseFunctionGenerator { public: - ParseFunctionGenerator(const Descriptor* descriptor, int max_has_bit_index, - const std::vector<int>& has_bit_indices, - const std::vector<int>& inlined_string_indices, - const Options& options, - MessageSCCAnalyzer* scc_analyzer, - const std::map<TProtoStringType, TProtoStringType>& vars); + ParseFunctionGenerator( + const Descriptor* descriptor, int max_has_bit_index, + const std::vector<int>& has_bit_indices, + const std::vector<int>& inlined_string_indices, const Options& options, + MessageSCCAnalyzer* scc_analyzer, + const y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>& vars); // Emits class-level method declarations to `printer`: void GenerateMethodDecls(io::Printer* printer); @@ -111,6 +71,8 @@ class ParseFunctionGenerator { void GenerateDataDefinitions(io::Printer* printer); private: + class GeneratedOptionProvider; + // Returns true if tailcall table code should be generated. bool should_generate_tctable() const; @@ -134,7 +96,6 @@ class ParseFunctionGenerator { void GenerateTailCallTable(Formatter& format); void GenerateFastFieldEntries(Formatter& format); void GenerateFieldEntries(Formatter& format); - int CalculateFieldNamesSize() const; void GenerateFieldNames(Formatter& format); // Generates parsing code for an `ArenaString` field. @@ -165,8 +126,8 @@ class ParseFunctionGenerator { const Descriptor* descriptor_; MessageSCCAnalyzer* scc_analyzer_; const Options& options_; - std::map<TProtoStringType, TProtoStringType> variables_; - std::unique_ptr<TailCallTableInfo> tc_table_info_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> variables_; + std::unique_ptr<internal::TailCallTableInfo> tc_table_info_; std::vector<int> inlined_string_indices_; const std::vector<const FieldDescriptor*> ordered_fields_; int num_hasbits_; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.cc deleted file mode 100644 index 9dbf16ae7eb..00000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.cc +++ /dev/null @@ -1,539 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: [email protected] (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <google/protobuf/compiler/cpp/primitive_field.h> - -#include <google/protobuf/io/printer.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/helpers.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -using internal::WireFormatLite; - -namespace { - -// For encodings with fixed sizes, returns that size in bytes. Otherwise -// returns -1. -int FixedSize(FieldDescriptor::Type type) { - switch (type) { - case FieldDescriptor::TYPE_INT32: - return -1; - case FieldDescriptor::TYPE_INT64: - return -1; - case FieldDescriptor::TYPE_UINT32: - return -1; - case FieldDescriptor::TYPE_UINT64: - return -1; - case FieldDescriptor::TYPE_SINT32: - return -1; - case FieldDescriptor::TYPE_SINT64: - return -1; - case FieldDescriptor::TYPE_FIXED32: - return WireFormatLite::kFixed32Size; - case FieldDescriptor::TYPE_FIXED64: - return WireFormatLite::kFixed64Size; - case FieldDescriptor::TYPE_SFIXED32: - return WireFormatLite::kSFixed32Size; - case FieldDescriptor::TYPE_SFIXED64: - return WireFormatLite::kSFixed64Size; - case FieldDescriptor::TYPE_FLOAT: - return WireFormatLite::kFloatSize; - case FieldDescriptor::TYPE_DOUBLE: - return WireFormatLite::kDoubleSize; - - case FieldDescriptor::TYPE_BOOL: - return WireFormatLite::kBoolSize; - case FieldDescriptor::TYPE_ENUM: - return -1; - - case FieldDescriptor::TYPE_STRING: - return -1; - case FieldDescriptor::TYPE_BYTES: - return -1; - case FieldDescriptor::TYPE_GROUP: - return -1; - case FieldDescriptor::TYPE_MESSAGE: - return -1; - - // No default because we want the compiler to complain if any new - // types are added. - } - GOOGLE_LOG(FATAL) << "Can't get here."; - return -1; -} - -void SetPrimitiveVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables, - const Options& options) { - SetCommonFieldVariables(descriptor, variables, options); - (*variables)["type"] = PrimitiveTypeName(options, descriptor->cpp_type()); - (*variables)["default"] = DefaultValue(options, descriptor); - (*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor); - bool cold = ShouldSplit(descriptor, options); - (*variables)["cached_byte_size_field"] = - MakeVarintCachedSizeFieldName(descriptor, cold); - (*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor)); - int fixed_size = FixedSize(descriptor->type()); - if (fixed_size != -1) { - (*variables)["fixed_size"] = StrCat(fixed_size); - } - (*variables)["wire_format_field_type"] = FieldDescriptorProto_Type_Name( - static_cast<FieldDescriptorProto_Type>(descriptor->type())); - (*variables)["full_name"] = descriptor->full_name(); -} - -} // namespace - -// =================================================================== - -PrimitiveFieldGenerator::PrimitiveFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(descriptor, options) { - SetPrimitiveVariables(descriptor, &variables_, options); -} - -PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} - -void PrimitiveFieldGenerator::GeneratePrivateMembers( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$type$ $name$_;\n"); -} - -void PrimitiveFieldGenerator::GenerateAccessorDeclarations( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "$deprecated_attr$$type$ ${1$$name$$}$() const;\n" - "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n" - "private:\n" - "$type$ ${1$_internal_$name$$}$() const;\n" - "void ${1$_internal_set_$name$$}$($type$ value);\n" - "public:\n", - descriptor_); -} - -void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline $type$ $classname$::_internal_$name$() const {\n" - " return $field$;\n" - "}\n" - "inline $type$ $classname$::$name$() const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return _internal_$name$();\n" - "}\n" - "inline void $classname$::_internal_set_$name$($type$ value) {\n" - " $set_hasbit$\n" - " $field$ = value;\n" - "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" - "$maybe_prepare_split_message$" - " _internal_set_$name$(value);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); -} - -void PrimitiveFieldGenerator::GenerateClearingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$ = $default$;\n"); -} - -void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - format("_this->_internal_set_$name$(from._internal_$name$());\n"); -} - -void PrimitiveFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - format("swap($field$, other->$field$);\n"); -} - -void PrimitiveFieldGenerator::GenerateCopyConstructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("_this->$field$ = from.$field$;\n"); -} - -void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "target = stream->EnsureSpace(target);\n" - "target = " - "::_pbi::WireFormatLite::Write$declared_type$ToArray(" - "$number$, this->_internal_$name$(), target);\n"); -} - -void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const { - Formatter format(printer, variables_); - int fixed_size = FixedSize(descriptor_->type()); - if (fixed_size == -1) { - if (internal::WireFormat::TagSize(descriptor_->number(), - descriptor_->type()) == 1) { - // Adding one is very common and it turns out it can be done for - // free inside of WireFormatLite, so we can save an instruction here. - format( - "total_size += ::_pbi::WireFormatLite::" - "$declared_type$SizePlusOne(this->_internal_$name$());\n"); - } else { - format( - "total_size += $tag_size$ +\n" - " ::_pbi::WireFormatLite::$declared_type$Size(\n" - " this->_internal_$name$());\n"); - } - } else { - format("total_size += $tag_size$ + $fixed_size$;\n"); - } -} - -void PrimitiveFieldGenerator::GenerateConstexprAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("/*decltype($field$)*/$default$"); -} - -void PrimitiveFieldGenerator::GenerateAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (ShouldSplit(descriptor_, options_)) { - format("decltype(Impl_::Split::$name$_){$default$}"); - return; - } - format("decltype($field$){$default$}"); -} - -void PrimitiveFieldGenerator::GenerateCopyAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("decltype($field$){}"); -} - -// =================================================================== - -PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) - : PrimitiveFieldGenerator(descriptor, options) { - SetCommonOneofFieldVariables(descriptor, &variables_); -} - -PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} - -void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline $type$ $classname$::_internal_$name$() const {\n" - " if (_internal_has_$name$()) {\n" - " return $field$;\n" - " }\n" - " return $default$;\n" - "}\n" - "inline void $classname$::_internal_set_$name$($type$ value) {\n" - " if (!_internal_has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " }\n" - " $field$ = value;\n" - "}\n" - "inline $type$ $classname$::$name$() const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return _internal_$name$();\n" - "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" - " _internal_set_$name$(value);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); -} - -void PrimitiveOneofFieldGenerator::GenerateClearingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$ = $default$;\n"); -} - -void PrimitiveOneofFieldGenerator::GenerateSwappingCode( - io::Printer* printer) const { - // Don't print any swapping code. Swapping the union will swap this field. -} - -void PrimitiveOneofFieldGenerator::GenerateConstructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n"); -} - -// =================================================================== - -RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(descriptor, options) { - SetPrimitiveVariables(descriptor, &variables_, options); - - if (descriptor->is_packed()) { - variables_["packed_reader"] = "ReadPackedPrimitive"; - variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; - } else { - variables_["packed_reader"] = "ReadPackedPrimitiveNoInline"; - variables_["repeated_reader"] = "ReadRepeatedPrimitive"; - } -} - -RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} - -void RepeatedPrimitiveFieldGenerator::GeneratePrivateMembers( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("::$proto_ns$::RepeatedField< $type$ > $name$_;\n"); - if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && - HasGeneratedMethods(descriptor_->file(), options_)) { - format("mutable std::atomic<int> $cached_byte_size_name$;\n"); - } -} - -void RepeatedPrimitiveFieldGenerator::GenerateAccessorDeclarations( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "private:\n" - "$type$ ${1$_internal_$name$$}$(int index) const;\n" - "const ::$proto_ns$::RepeatedField< $type$ >&\n" - " ${1$_internal_$name$$}$() const;\n" - "void ${1$_internal_add_$name$$}$($type$ value);\n" - "::$proto_ns$::RepeatedField< $type$ >*\n" - " ${1$_internal_mutable_$name$$}$();\n" - "public:\n" - "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n" - "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n" - "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n" - "$deprecated_attr$const ::$proto_ns$::RepeatedField< $type$ >&\n" - " ${1$$name$$}$() const;\n" - "$deprecated_attr$::$proto_ns$::RepeatedField< $type$ >*\n" - " ${1$mutable_$name$$}$();\n", - descriptor_); -} - -void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline $type$ $classname$::_internal_$name$(int index) const {\n" - " return $field$.Get(index);\n" - "}\n" - "inline $type$ $classname$::$name$(int index) const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return _internal_$name$(index);\n" - "}\n" - "inline void $classname$::set_$name$(int index, $type$ value) {\n" - "$annotate_set$" - " $field$.Set(index, value);\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline void $classname$::_internal_add_$name$($type$ value) {\n" - " $field$.Add(value);\n" - "}\n" - "inline void $classname$::add_$name$($type$ value) {\n" - " _internal_add_$name$(value);\n" - "$annotate_add$" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n" - "inline const ::$proto_ns$::RepeatedField< $type$ >&\n" - "$classname$::_internal_$name$() const {\n" - " return $field$;\n" - "}\n" - "inline const ::$proto_ns$::RepeatedField< $type$ >&\n" - "$classname$::$name$() const {\n" - "$annotate_list$" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return _internal_$name$();\n" - "}\n" - "inline ::$proto_ns$::RepeatedField< $type$ >*\n" - "$classname$::_internal_mutable_$name$() {\n" - " return &$field$;\n" - "}\n" - "inline ::$proto_ns$::RepeatedField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" - "$annotate_mutable_list$" - " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return _internal_mutable_$name$();\n" - "}\n"); -} - -void RepeatedPrimitiveFieldGenerator::GenerateClearingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.Clear();\n"); -} - -void RepeatedPrimitiveFieldGenerator::GenerateMergingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("_this->$field$.MergeFrom(from.$field$);\n"); -} - -void RepeatedPrimitiveFieldGenerator::GenerateSwappingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.InternalSwap(&other->$field$);\n"); -} - -void RepeatedPrimitiveFieldGenerator::GenerateDestructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.~RepeatedField();\n"); -} - -void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (descriptor_->is_packed()) { - if (FixedSize(descriptor_->type()) == -1) { - format( - "{\n" - " int byte_size = " - "$cached_byte_size_field$.load(std::memory_order_relaxed);\n" - " if (byte_size > 0) {\n" - " target = stream->Write$declared_type$Packed(\n" - " $number$, _internal_$name$(), byte_size, target);\n" - " }\n" - "}\n"); - } else { - format( - "if (this->_internal_$name$_size() > 0) {\n" - " target = stream->WriteFixedPacked($number$, _internal_$name$(), " - "target);\n" - "}\n"); - } - } else { - format( - "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n" - " target = stream->EnsureSpace(target);\n" - " target = ::_pbi::WireFormatLite::" - "Write$declared_type$ToArray($number$, this->_internal_$name$(i), " - "target);\n" - "}\n"); - } -} - -void RepeatedPrimitiveFieldGenerator::GenerateByteSize( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("{\n"); - format.Indent(); - int fixed_size = FixedSize(descriptor_->type()); - if (fixed_size == -1) { - format( - "size_t data_size = ::_pbi::WireFormatLite::\n" - " $declared_type$Size(this->$field$);\n"); - } else { - format( - "unsigned int count = static_cast<unsigned " - "int>(this->_internal_$name$_size());\n" - "size_t data_size = $fixed_size$UL * count;\n"); - } - - if (descriptor_->is_packed()) { - format( - "if (data_size > 0) {\n" - " total_size += $tag_size$ +\n" - " " - "::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n" - "}\n"); - if (FixedSize(descriptor_->type()) == -1) { - format( - "int cached_size = ::_pbi::ToCachedSize(data_size);\n" - "$cached_byte_size_field$.store(cached_size,\n" - " std::memory_order_relaxed);\n"); - } - format("total_size += data_size;\n"); - } else { - format( - "total_size += $tag_size$ *\n" - " " - "::_pbi::FromIntSize(this->_internal_$name$_size());\n" - "total_size += data_size;\n"); - } - format.Outdent(); - format("}\n"); -} - -void RepeatedPrimitiveFieldGenerator::GenerateConstexprAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("/*decltype($field$)*/{}"); - if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && - HasGeneratedMethods(descriptor_->file(), options_)) { - format("\n, /*decltype($cached_byte_size_field$)*/{0}"); - } -} - -void RepeatedPrimitiveFieldGenerator::GenerateAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("decltype($field$){arena}"); - if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && - HasGeneratedMethods(descriptor_->file(), options_)) { - // std::atomic has no move constructor, which prevents explicit aggregate - // initialization pre-C++17. - format("\n, /*decltype($cached_byte_size_field$)*/{0}"); - } -} - -void RepeatedPrimitiveFieldGenerator::GenerateCopyAggregateInitializer( - io::Printer* printer) const { - - Formatter format(printer, variables_); - format("decltype($field$){from.$field$}"); - if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && - HasGeneratedMethods(descriptor_->file(), options_)) { - // std::atomic has no move constructor. - format("\n, /*decltype($cached_byte_size_field$)*/{0}"); - } -} - -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.h deleted file mode 100644 index bb8a08aa141..00000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.h +++ /dev/null @@ -1,126 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: [email protected] (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ - -#include <map> -#include <string> - -#include <google/protobuf/compiler/cpp/field.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -class PrimitiveFieldGenerator : public FieldGenerator { - public: - PrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); - ~PrimitiveFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override {} - void GenerateCopyConstructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstexprAggregateInitializer( - io::Printer* printer) const override; - void GenerateAggregateInitializer(io::Printer* printer) const override; - void GenerateCopyAggregateInitializer(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); -}; - -class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { - public: - PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); - ~PrimitiveOneofFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator); -}; - -class RepeatedPrimitiveFieldGenerator : public FieldGenerator { - public: - RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); - ~RepeatedPrimitiveFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override {} - void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override { - GOOGLE_CHECK(!ShouldSplit(descriptor_, options_)); - } - void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstexprAggregateInitializer( - io::Printer* printer) const override; - void GenerateAggregateInitializer(io::Printer* printer) const override; - void GenerateCopyAggregateInitializer(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); -}; - -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.cc index fae7128a097..ae1d2b8a2da 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.cc @@ -32,293 +32,279 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/service.h> +#include "google/protobuf/compiler/cpp/service.h" -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/helpers.h> +#include <string> + +#include "y_absl/strings/str_cat.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - -namespace { - -void InitMethodVariables(const MethodDescriptor* method, const Options& options, - Formatter* format) { - format->Set("name", method->name()); - format->Set("input_type", QualifiedClassName(method->input_type(), options)); - format->Set("output_type", - QualifiedClassName(method->output_type(), options)); -} - -} // namespace - -ServiceGenerator::ServiceGenerator( - const ServiceDescriptor* descriptor, - const std::map<TProtoStringType, TProtoStringType>& vars, const Options& options) - : descriptor_(descriptor), vars_(vars), options_(options) { - vars_["classname"] = descriptor_->name(); - vars_["full_name"] = descriptor_->full_name(); -} - -ServiceGenerator::~ServiceGenerator() {} - void ServiceGenerator::GenerateDeclarations(io::Printer* printer) { - Formatter format(printer, vars_); - // Forward-declare the stub type. - format( - "class $classname$_Stub;\n" - "\n"); - - GenerateInterface(printer); - GenerateStubDefinition(printer); -} - -void ServiceGenerator::GenerateInterface(io::Printer* printer) { - Formatter format(printer, vars_); - format( - "class $dllexport_decl $$classname$ : public ::$proto_ns$::Service {\n" - " protected:\n" - " // This class should be treated as an abstract interface.\n" - " inline $classname$() {};\n" - " public:\n" - " virtual ~$classname$();\n"); - printer->Indent(); - - format( - "\n" - "typedef $classname$_Stub Stub;\n" - "\n" - "static const ::$proto_ns$::ServiceDescriptor* descriptor();\n" - "\n"); - - GenerateMethodSignatures(VIRTUAL, printer); - - format( - "\n" - "// implements Service ----------------------------------------------\n" - "\n" - "const ::$proto_ns$::ServiceDescriptor* GetDescriptor();\n" - "void CallMethod(const ::$proto_ns$::MethodDescriptor* method,\n" - " ::$proto_ns$::RpcController* controller,\n" - " const ::$proto_ns$::Message* request,\n" - " ::$proto_ns$::Message* response,\n" - " ::google::protobuf::Closure* done);\n" - "const ::$proto_ns$::Message& GetRequestPrototype(\n" - " const ::$proto_ns$::MethodDescriptor* method) const;\n" - "const ::$proto_ns$::Message& GetResponsePrototype(\n" - " const ::$proto_ns$::MethodDescriptor* method) const;\n"); - - printer->Outdent(); - format( - "\n" - " private:\n" - " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n" - "};\n" - "\n"); -} - -void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) { - Formatter format(printer, vars_); - format( - "class $dllexport_decl $$classname$_Stub : public $classname$ {\n" - " public:\n"); - - printer->Indent(); - - format( - "$classname$_Stub(::$proto_ns$::RpcChannel* channel);\n" - "$classname$_Stub(::$proto_ns$::RpcChannel* channel,\n" - " ::$proto_ns$::Service::ChannelOwnership ownership);\n" - "~$classname$_Stub();\n" - "\n" - "inline ::$proto_ns$::RpcChannel* channel() { return channel_; }\n" - "\n" - "// implements $classname$ ------------------------------------------\n" - "\n"); - - GenerateMethodSignatures(NON_VIRTUAL, printer); - - printer->Outdent(); - format( - " private:\n" - " ::$proto_ns$::RpcChannel* channel_;\n" - " bool owns_channel_;\n" - " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n" - "};\n" - "\n"); + auto vars = printer->WithVars(&vars_); + printer->Emit( + { + {"virts", [&] { GenerateMethodSignatures(kVirtual, printer); }}, + {"impls", [&] { GenerateMethodSignatures(kNonVirtual, printer); }}, + }, + R"cc( + class $classname$_Stub; + class $dllexport_decl $$classname$ : public ::$proto_ns$::Service { + protected: + $classname$() = default; + + public: + using Stub = $classname$_Stub; + + $classname$(const $classname$&) = delete; + $classname$& operator=(const $classname$&) = delete; + virtual ~$classname$() = default; + + static const ::$proto_ns$::ServiceDescriptor* descriptor(); + + $virts$; + + // implements Service ---------------------------------------------- + const ::$proto_ns$::ServiceDescriptor* GetDescriptor() override; + + void CallMethod(const ::$proto_ns$::MethodDescriptor* method, + ::$proto_ns$::RpcController* controller, + const ::$proto_ns$::Message* request, + ::$proto_ns$::Message* response, + ::google::protobuf::Closure* done) override; + + const ::$proto_ns$::Message& GetRequestPrototype( + const ::$proto_ns$::MethodDescriptor* method) const override; + + const ::$proto_ns$::Message& GetResponsePrototype( + const ::$proto_ns$::MethodDescriptor* method) const override; + }; + + class $dllexport_decl $$classname$_Stub final : public $classname$ { + public: + $classname$_Stub(::$proto_ns$::RpcChannel* channel); + $classname$_Stub(::$proto_ns$::RpcChannel* channel, + ::$proto_ns$::Service::ChannelOwnership ownership); + + $classname$_Stub(const $classname$_Stub&) = delete; + $classname$_Stub& operator=(const $classname$_Stub&) = delete; + + ~$classname$_Stub() override; + + inline ::$proto_ns$::RpcChannel* channel() { return channel_; } + + // implements $classname$ ------------------------------------------ + $impls$; + + private: + ::$proto_ns$::RpcChannel* channel_; + bool owns_channel_; + }; + )cc"); } -void ServiceGenerator::GenerateMethodSignatures(VirtualOrNon virtual_or_non, +void ServiceGenerator::GenerateMethodSignatures(VirtualOrNot virtual_or_not, io::Printer* printer) { - for (int i = 0; i < descriptor_->method_count(); i++) { + for (int i = 0; i < descriptor_->method_count(); ++i) { const MethodDescriptor* method = descriptor_->method(i); - Formatter format(printer, vars_); - InitMethodVariables(method, options_, &format); - format.Set("virtual", virtual_or_non == VIRTUAL ? "virtual " : ""); - format( - "$virtual$void $name$(::$proto_ns$::RpcController* controller,\n" - " const $input_type$* request,\n" - " $output_type$* response,\n" - " ::google::protobuf::Closure* done);\n"); + + printer->Emit( + { + {"name", method->name()}, + {"input", QualifiedClassName(method->input_type(), *options_)}, + {"output", QualifiedClassName(method->output_type(), *options_)}, + {"virtual", virtual_or_not == kVirtual ? "virtual" : ""}, + {"override", virtual_or_not != kVirtual ? "override" : ""}, + }, + // No cc, clang-format does not format this string well due to the + // $ override$ substitution. + R"( + $virtual $void $name$(::$proto_ns$::RpcController* controller, + const $input$* request, + $output$* response, + ::google::protobuf::Closure* done)$ override$; + )"); } } // =================================================================== void ServiceGenerator::GenerateImplementation(io::Printer* printer) { - Formatter format(printer, vars_); - format( - "$classname$::~$classname$() {}\n" - "\n" - "const ::$proto_ns$::ServiceDescriptor* $classname$::descriptor() {\n" - " " - "::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n" - " return $file_level_service_descriptors$[$1$];\n" - "}\n" - "\n" - "const ::$proto_ns$::ServiceDescriptor* $classname$::GetDescriptor() {\n" - " return descriptor();\n" - "}\n" - "\n", - index_in_metadata_); - - // Generate methods of the interface. - GenerateNotImplementedMethods(printer); - GenerateCallMethod(printer); - GenerateGetPrototype(REQUEST, printer); - GenerateGetPrototype(RESPONSE, printer); - - // Generate stub implementation. - format( - "$classname$_Stub::$classname$_Stub(::$proto_ns$::RpcChannel* channel)\n" - " : channel_(channel), owns_channel_(false) {}\n" - "$classname$_Stub::$classname$_Stub(\n" - " ::$proto_ns$::RpcChannel* channel,\n" - " ::$proto_ns$::Service::ChannelOwnership ownership)\n" - " : channel_(channel),\n" - " owns_channel_(ownership == " - "::$proto_ns$::Service::STUB_OWNS_CHANNEL) " - "{}\n" - "$classname$_Stub::~$classname$_Stub() {\n" - " if (owns_channel_) delete channel_;\n" - "}\n" - "\n"); - - GenerateStubMethods(printer); + auto vars = printer->WithVars(&vars_); + printer->Emit( + { + {"index", index_in_metadata_}, + {"no_impl_methods", [&] { GenerateNotImplementedMethods(printer); }}, + {"call_method", [&] { GenerateCallMethod(printer); }}, + {"get_request", [&] { GenerateGetPrototype(kRequest, printer); }}, + {"get_response", [&] { GenerateGetPrototype(kResponse, printer); }}, + {"stub_methods", [&] { GenerateStubMethods(printer); }}, + }, + R"cc( + const ::$proto_ns$::ServiceDescriptor* $classname$::descriptor() { + ::$proto_ns$::internal::AssignDescriptors(&$desc_table$); + return $file_level_service_descriptors$[$index$]; + } + + const ::$proto_ns$::ServiceDescriptor* $classname$::GetDescriptor() { + return descriptor(); + } + + $no_impl_methods$; + + $call_method$; + + $get_request$; + + $get_response$; + + $classname$_Stub::$classname$_Stub(::$proto_ns$::RpcChannel* channel) + : channel_(channel), owns_channel_(false) {} + + $classname$_Stub::$classname$_Stub( + ::$proto_ns$::RpcChannel* channel, + ::$proto_ns$::Service::ChannelOwnership ownership) + : channel_(channel), + owns_channel_(ownership == + ::$proto_ns$::Service::STUB_OWNS_CHANNEL) {} + + $classname$_Stub::~$classname$_Stub() { + if (owns_channel_) delete channel_; + } + + $stub_methods$; + )cc"); } void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { - for (int i = 0; i < descriptor_->method_count(); i++) { + for (int i = 0; i < descriptor_->method_count(); ++i) { const MethodDescriptor* method = descriptor_->method(i); - Formatter format(printer, vars_); - InitMethodVariables(method, options_, &format); - format( - "void $classname$::$name$(::$proto_ns$::RpcController* controller,\n" - " const $input_type$*,\n" - " $output_type$*,\n" - " ::google::protobuf::Closure* done) {\n" - " controller->SetFailed(\"Method $name$() not implemented.\");\n" - " done->Run();\n" - "}\n" - "\n"); + + printer->Emit( + { + {"name", method->name()}, + {"input", QualifiedClassName(method->input_type(), *options_)}, + {"output", QualifiedClassName(method->output_type(), *options_)}, + }, + R"cc( + void $classname$::$name$(::$proto_ns$::RpcController* controller, + const $input$*, $output$*, ::google::protobuf::Closure* done) { + controller->SetFailed("Method $name$() not implemented."); + done->Run(); + } + )cc"); } } void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { - Formatter format(printer, vars_); - format( - "void $classname$::CallMethod(const ::$proto_ns$::MethodDescriptor* " - "method,\n" - " ::$proto_ns$::RpcController* controller,\n" - " const ::$proto_ns$::Message* request,\n" - " ::$proto_ns$::Message* response,\n" - " ::google::protobuf::Closure* done) {\n" - " GOOGLE_DCHECK_EQ(method->service(), $file_level_service_descriptors$[$1$]);\n" - " switch(method->index()) {\n", - index_in_metadata_); - - for (int i = 0; i < descriptor_->method_count(); i++) { - const MethodDescriptor* method = descriptor_->method(i); - Formatter format_method(printer, vars_); - InitMethodVariables(method, options_, &format_method); - - // Note: down_cast does not work here because it only works on pointers, - // not references. - format_method( - " case $1$:\n" - " $name$(controller,\n" - " ::$proto_ns$::internal::DownCast<const $input_type$*>(\n" - " request),\n" - " ::$proto_ns$::internal::DownCast<$output_type$*>(\n" - " response),\n" - " done);\n" - " break;\n", - i); - } - - format( - " default:\n" - " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" - " break;\n" - " }\n" - "}\n" - "\n"); + printer->Emit( + { + {"index", y_absl::StrCat(index_in_metadata_)}, + {"cases", [&] { GenerateCallMethodCases(printer); }}, + }, + R"cc( + void $classname$::CallMethod( + const ::$proto_ns$::MethodDescriptor* method, + ::$proto_ns$::RpcController* controller, + const ::$proto_ns$::Message* request, + ::$proto_ns$::Message* response, ::google::protobuf::Closure* done) { + Y_ABSL_DCHECK_EQ(method->service(), $file_level_service_descriptors$[$index$]); + switch (method->index()) { + $cases$; + + default: + Y_ABSL_LOG(FATAL) << "Bad method index; this should never happen."; + break; + } + } + )cc"); } void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, io::Printer* printer) { - Formatter format(printer, vars_); - if (which == REQUEST) { - format("const ::$proto_ns$::Message& $classname$::GetRequestPrototype(\n"); - } else { - format("const ::$proto_ns$::Message& $classname$::GetResponsePrototype(\n"); - } - - format( - " const ::$proto_ns$::MethodDescriptor* method) const {\n" - " GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" - " switch(method->index()) {\n"); + printer->Emit( + { + {"which", which == kRequest ? "Request" : "Response"}, + {"which_type", which == kRequest ? "input" : "output"}, + {"cases", + [&] { + for (int i = 0; i < descriptor_->method_count(); ++i) { + const MethodDescriptor* method = descriptor_->method(i); + const Descriptor* type = which == kRequest + ? method->input_type() + : method->output_type(); + + printer->Emit( + { + {"index", y_absl::StrCat(i)}, + {"type", QualifiedClassName(type, *options_)}, + }, + R"cc( + case $index$: + return $type$::default_instance(); + )cc"); + } + }}, + }, + R"cc( + const ::$proto_ns$::Message& $classname$::Get$which$Prototype( + const ::$proto_ns$::MethodDescriptor* method) const { + Y_ABSL_DCHECK_EQ(method->service(), descriptor()); + switch (method->index()) { + $cases$; + + default: + Y_ABSL_LOG(FATAL) << "Bad method index; this should never happen."; + return *::$proto_ns$::MessageFactory::generated_factory() + ->GetPrototype(method->$which_type$_type()); + } + } + )cc"); +} - for (int i = 0; i < descriptor_->method_count(); i++) { +void ServiceGenerator::GenerateCallMethodCases(io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); ++i) { const MethodDescriptor* method = descriptor_->method(i); - const Descriptor* type = - (which == REQUEST) ? method->input_type() : method->output_type(); - - format( - " case $1$:\n" - " return $2$::default_instance();\n", - i, QualifiedClassName(type, options_)); + printer->Emit( + { + {"name", method->name()}, + {"input", QualifiedClassName(method->input_type(), *options_)}, + {"output", QualifiedClassName(method->output_type(), *options_)}, + {"index", y_absl::StrCat(i)}, + }, + R"cc( + case $index$: + $name$(controller, + ::$proto_ns$::internal::DownCast<const $input$*>(request), + ::$proto_ns$::internal::DownCast<$output$*>(response), done); + break; + )cc"); } - - format( - " default:\n" - " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" - " return *::$proto_ns$::MessageFactory::generated_factory()\n" - " ->GetPrototype(method->$1$_type());\n" - " }\n" - "}\n" - "\n", - which == REQUEST ? "input" : "output"); } void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { - for (int i = 0; i < descriptor_->method_count(); i++) { + for (int i = 0; i < descriptor_->method_count(); ++i) { const MethodDescriptor* method = descriptor_->method(i); - Formatter format(printer, vars_); - InitMethodVariables(method, options_, &format); - format( - "void $classname$_Stub::$name$(::$proto_ns$::RpcController* " - "controller,\n" - " const $input_type$* request,\n" - " $output_type$* response,\n" - " ::google::protobuf::Closure* done) {\n" - " channel_->CallMethod(descriptor()->method($1$),\n" - " controller, request, response, done);\n" - "}\n", - i); + + printer->Emit( + { + {"name", method->name()}, + {"input", QualifiedClassName(method->input_type(), *options_)}, + {"output", QualifiedClassName(method->output_type(), *options_)}, + {"index", y_absl::StrCat(i)}, + }, + R"cc( + void $classname$_Stub::$name$(::$proto_ns$::RpcController* controller, + const $input$* request, + $output$* response, ::google::protobuf::Closure* done) { + channel_->CallMethod(descriptor()->method($index$), controller, + request, response, done); + } + )cc"); } } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.h index 56982cf566b..183a4ecb1c8 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.h @@ -35,63 +35,52 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ -#include <map> #include <string> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/options.h> - -namespace google { -namespace protobuf { -namespace io { -class Printer; // printer.h -} -} // namespace protobuf -} // namespace google +#include "google/protobuf/descriptor.h" +#include "y_absl/container/flat_hash_map.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { - class ServiceGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit ServiceGenerator(const ServiceDescriptor* descriptor, - const std::map<TProtoStringType, TProtoStringType>& vars, - const Options& options); - ~ServiceGenerator(); - - // Header stuff. + ServiceGenerator( + const ServiceDescriptor* descriptor, + const y_absl::flat_hash_map<y_absl::string_view, TProtoStringType>& vars, + const Options& options) + : descriptor_(descriptor), options_(&options), vars_(vars) { + vars_["classname"] = descriptor_->name(); + vars_["full_name"] = descriptor_->full_name(); + } + + ServiceGenerator(const ServiceGenerator&) = delete; + ServiceGenerator& operator=(const ServiceGenerator&) = delete; + ServiceGenerator(ServiceGenerator&&) = delete; + ServiceGenerator& operator=(ServiceGenerator&&) = delete; + + ~ServiceGenerator() = default; // Generate the class definitions for the service's interface and the // stub implementation. void GenerateDeclarations(io::Printer* printer); - // Source file stuff. - // Generate implementations of everything declared by // GenerateDeclarations(). void GenerateImplementation(io::Printer* printer); private: - enum RequestOrResponse { REQUEST, RESPONSE }; - enum VirtualOrNon { VIRTUAL, NON_VIRTUAL }; - - // Header stuff. - - // Generate the service abstract interface. - void GenerateInterface(io::Printer* printer); - - // Generate the stub class definition. - void GenerateStubDefinition(io::Printer* printer); + enum RequestOrResponse { kRequest, kResponse }; + enum VirtualOrNot { kVirtual, kNonVirtual }; // Prints signatures for all methods in the - void GenerateMethodSignatures(VirtualOrNon virtual_or_non, + void GenerateMethodSignatures(VirtualOrNot virtual_or_not, io::Printer* printer); - // Source file stuff. - // Generate the default implementations of the service methods, which // produce a "not implemented" error. void GenerateNotImplementedMethods(io::Printer* printer); @@ -102,19 +91,20 @@ class ServiceGenerator { // Generate the Get{Request,Response}Prototype() methods. void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer); + // Generate the cases in CallMethod(). + void GenerateCallMethodCases(io::Printer* printer); + // Generate the stub's implementations of the service methods. void GenerateStubMethods(io::Printer* printer); const ServiceDescriptor* descriptor_; - std::map<TProtoStringType, TProtoStringType> vars_; - const Options& options_; + const Options* options_; + y_absl::flat_hash_map<y_absl::string_view, TProtoStringType> vars_; int index_in_metadata_; friend class FileGenerator; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); }; - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.cc deleted file mode 100644 index 5f30d3b511e..00000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.cc +++ /dev/null @@ -1,957 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: [email protected] (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <google/protobuf/compiler/cpp/string_field.h> - -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/helpers.h> -#include <google/protobuf/descriptor.pb.h> - - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -namespace { - -void SetStringVariables(const FieldDescriptor* descriptor, - std::map<TProtoStringType, TProtoStringType>* variables, - const Options& options) { - SetCommonFieldVariables(descriptor, variables, options); - - const TProtoStringType kNS = "::" + (*variables)["proto_ns"] + "::internal::"; - const TProtoStringType kArenaStringPtr = kNS + "ArenaStringPtr"; - - (*variables)["default"] = DefaultValue(options, descriptor); - (*variables)["default_length"] = - StrCat(descriptor->default_value_string().length()); - (*variables)["default_variable_name"] = MakeDefaultName(descriptor); - (*variables)["default_variable_field"] = MakeDefaultFieldName(descriptor); - - if (descriptor->default_value_string().empty()) { - (*variables)["default_string"] = kNS + "GetEmptyStringAlreadyInited()"; - (*variables)["default_value"] = "&" + (*variables)["default_string"]; - (*variables)["lazy_variable_args"] = ""; - } else { - (*variables)["lazy_variable"] = - StrCat(QualifiedClassName(descriptor->containing_type(), options), - "::", MakeDefaultFieldName(descriptor)); - - (*variables)["default_string"] = (*variables)["lazy_variable"] + ".get()"; - (*variables)["default_value"] = "nullptr"; - (*variables)["lazy_variable_args"] = (*variables)["lazy_variable"] + ", "; - } - - (*variables)["pointer_type"] = - descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; - (*variables)["setter"] = - descriptor->type() == FieldDescriptor::TYPE_BYTES ? "SetBytes" : "Set"; - (*variables)["null_check"] = (*variables)["DCHK"] + "(value != nullptr);\n"; - // NOTE: Escaped here to unblock proto1->proto2 migration. - // TODO(liujisi): Extend this to apply for other conflicting methods. - (*variables)["release_name"] = - SafeFunctionName(descriptor->containing_type(), descriptor, "release_"); - (*variables)["full_name"] = descriptor->full_name(); - - if (options.opensource_runtime) { - (*variables)["string_piece"] = "TProtoStringType"; - } else { - (*variables)["string_piece"] = "::StringPiece"; - } -} - -} // namespace - -// =================================================================== - -StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : FieldGenerator(descriptor, options), - inlined_(IsStringInlined(descriptor, options)) { - SetStringVariables(descriptor, &variables_, options); -} - -StringFieldGenerator::~StringFieldGenerator() {} - -void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { - Formatter format(printer, variables_); - if (!inlined_) { - format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n"); - } else { - // Skips the automatic destruction; rather calls it explicitly if - // allocating arena is null. This is required to support message-owned - // arena (go/path-to-arenas) where a root proto is destroyed but - // InlinedStringField may have arena-allocated memory. - format("::$proto_ns$::internal::InlinedStringField $name$_;\n"); - } -} - -void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const { - Formatter format(printer, variables_); - if (!descriptor_->default_value_string().empty()) { - format( - "static const ::$proto_ns$::internal::LazyString" - " $default_variable_name$;\n"); - } - if (inlined_) { - // `_init_inline_xxx` is used for initializing default instances. - format("static std::true_type _init_inline_$name$_;\n"); - } -} - -void StringFieldGenerator::GenerateAccessorDeclarations( - io::Printer* printer) const { - Formatter format(printer, variables_); - // If we're using StringFieldGenerator for a field with a ctype, it's - // because that ctype isn't actually implemented. In particular, this is - // true of ctype=CORD and ctype=STRING_PIECE in the open source release. - // We aren't releasing Cord because it has too many Google-specific - // dependencies and we aren't releasing StringPiece because it's hardly - // useful outside of Google and because it would get confusing to have - // multiple instances of the StringPiece class in different libraries (PCRE - // already includes it for their C++ bindings, which came from Google). - // - // In any case, we make all the accessors private while still actually - // using a string to represent the field internally. This way, we can - // guarantee that if we do ever implement the ctype, it won't break any - // existing users who might be -- for whatever reason -- already using .proto - // files that applied the ctype. The field can still be accessed via the - // reflection interface since the reflection interface is independent of - // the string's underlying representation. - - bool unknown_ctype = descriptor_->options().ctype() != - EffectiveStringCType(descriptor_, options_); - - if (unknown_ctype) { - format.Outdent(); - format( - " private:\n" - " // Hidden due to unknown ctype option.\n"); - format.Indent(); - } - - format( - "$deprecated_attr$const TProtoStringType& ${1$$name$$}$() const;\n" - "template <typename ArgT0 = const TProtoStringType&, typename... ArgT>\n" - "$deprecated_attr$void ${1$set_$name$$}$(ArgT0&& arg0, ArgT... args);\n", - descriptor_); - format( - "$deprecated_attr$TProtoStringType* ${1$mutable_$name$$}$();\n" - "PROTOBUF_NODISCARD $deprecated_attr$TProtoStringType* " - "${1$$release_name$$}$();\n" - "$deprecated_attr$void ${1$set_allocated_$name$$}$(TProtoStringType* " - "$name$);\n", - descriptor_); - format( - "private:\n" - "const TProtoStringType& _internal_$name$() const;\n" - "inline PROTOBUF_ALWAYS_INLINE void " - "_internal_set_$name$(const TProtoStringType& value);\n" - "TProtoStringType* _internal_mutable_$name$();\n"); - if (inlined_) { - format( - "inline PROTOBUF_ALWAYS_INLINE bool _internal_$name$_donated() " - "const;\n"); - } - format("public:\n"); - - if (unknown_ctype) { - format.Outdent(); - format(" public:\n"); - format.Indent(); - } -} - -void StringFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline const TProtoStringType& $classname$::$name$() const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n"); - if (!descriptor_->default_value_string().empty()) { - format( - " if ($field$.IsDefault()) return " - "$default_variable_field$.get();\n"); - } - format( - " return _internal_$name$();\n" - "}\n"); - if (!inlined_) { - format( - "template <typename ArgT0, typename... ArgT>\n" - "inline PROTOBUF_ALWAYS_INLINE\n" - "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" - "$maybe_prepare_split_message$" - " $set_hasbit$\n" - " $field$.$setter$(static_cast<ArgT0 &&>(arg0)," - " args..., GetArenaForAllocation());\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); - } else { - format( - "template <typename ArgT0, typename... ArgT>\n" - "inline PROTOBUF_ALWAYS_INLINE\n" - "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" - "$maybe_prepare_split_message$" - " $set_hasbit$\n" - " $field$.$setter$(static_cast<ArgT0 &&>(arg0)," - " args..., GetArenaForAllocation(), _internal_$name$_donated(), " - "&$donating_states_word$, $mask_for_undonate$, this);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline bool $classname$::_internal_$name$_donated() const {\n" - " bool value = $inlined_string_donated$\n" - " return value;\n" - "}\n"); - } - format( - "inline TProtoStringType* $classname$::mutable_$name$() {\n" - "$maybe_prepare_split_message$" - " TProtoStringType* _s = _internal_mutable_$name$();\n" - "$annotate_mutable$" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return _s;\n" - "}\n" - "inline const TProtoStringType& $classname$::_internal_$name$() const {\n" - " return $field$.Get();\n" - "}\n" - "inline void $classname$::_internal_set_$name$(const TProtoStringType& " - "value) {\n" - " $set_hasbit$\n"); - if (!inlined_) { - format( - " $field$.Set(value, GetArenaForAllocation());\n" - "}\n"); - } else { - format( - " $field$.Set(value, GetArenaForAllocation(),\n" - " _internal_$name$_donated(), &$donating_states_word$, " - "$mask_for_undonate$, this);\n" - "}\n"); - } - format( - "inline TProtoStringType* $classname$::_internal_mutable_$name$() {\n" - " $set_hasbit$\n"); - if (!inlined_) { - format( - " return $field$.Mutable($lazy_variable_args$" - "GetArenaForAllocation());\n" - "}\n"); - } else { - format( - " return $field$.Mutable($lazy_variable_args$" - "GetArenaForAllocation(), _internal_$name$_donated(), " - "&$donating_states_word$, $mask_for_undonate$, this);\n" - "}\n"); - } - format( - "inline TProtoStringType* $classname$::$release_name$() {\n" - "$annotate_release$" - "$maybe_prepare_split_message$" - " // @@protoc_insertion_point(field_release:$full_name$)\n"); - - if (HasHasbit(descriptor_)) { - format( - " if (!_internal_has_$name$()) {\n" - " return nullptr;\n" - " }\n" - " $clear_hasbit$\n"); - if (!inlined_) { - format(" auto* p = $field$.Release();\n"); - if (descriptor_->default_value_string().empty()) { - format( - "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" - " if ($field$.IsDefault()) {\n" - " $field$.Set(\"\", GetArenaForAllocation());\n" - " }\n" - "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); - } - format(" return p;\n"); - } else { - format( - " return $field$.Release(GetArenaForAllocation(), " - "_internal_$name$_donated());\n"); - } - } else { - format(" return $field$.Release();\n"); - } - - format( - "}\n" - "inline void $classname$::set_allocated_$name$(TProtoStringType* $name$) {\n" - "$maybe_prepare_split_message$" - " if ($name$ != nullptr) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n"); - if (!inlined_) { - format(" $field$.SetAllocated($name$, GetArenaForAllocation());\n"); - if (descriptor_->default_value_string().empty()) { - format( - "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" - " if ($field$.IsDefault()) {\n" - " $field$.Set(\"\", GetArenaForAllocation());\n" - " }\n" - "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); - } - } else { - // Currently, string fields with default value can't be inlined. - format( - " $field$.SetAllocated(nullptr, $name$, GetArenaForAllocation(), " - "_internal_$name$_donated(), &$donating_states_word$, " - "$mask_for_undonate$, this);\n"); - } - format( - "$annotate_set$" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n"); -} - -void StringFieldGenerator::GenerateNonInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (!descriptor_->default_value_string().empty()) { - format( - "const ::$proto_ns$::internal::LazyString " - "$classname$::$default_variable_field$" - "{{{$default$, $default_length$}}, {nullptr}};\n"); - } -} - -void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - if (descriptor_->default_value_string().empty()) { - format("$field$.ClearToEmpty();\n"); - } else { - GOOGLE_DCHECK(!inlined_); - format( - "$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n"); - } -} - -void StringFieldGenerator::GenerateMessageClearingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - // Two-dimension specialization here: supporting arenas, field presence, or - // not, and default value is the empty string or not. Complexity here ensures - // the minimal number of branches / amount of extraneous code at runtime - // (given that the below methods are inlined one-liners)! - - // If we have a hasbit, then the Clear() method of the protocol buffer - // will have checked that this field is set. If so, we can avoid redundant - // checks against the default variable. - const bool must_be_present = HasHasbit(descriptor_); - - if (inlined_ && must_be_present) { - // Calling mutable_$name$() gives us a string reference and sets the has bit - // for $name$ (in proto2). We may get here when the string field is inlined - // but the string's contents have not been changed by the user, so we cannot - // make an assertion about the contents of the string and could never make - // an assertion about the string instance. - // - // For non-inlined strings, we distinguish from non-default by comparing - // instances, rather than contents. - format("$DCHK$(!$field$.IsDefault());\n"); - } - - if (descriptor_->default_value_string().empty()) { - if (must_be_present) { - format("$field$.ClearNonDefaultToEmpty();\n"); - } else { - format("$field$.ClearToEmpty();\n"); - } - } else { - // Clear to a non-empty default is more involved, as we try to use the - // Arena if one is present and may need to reallocate the string. - format( - "$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n "); - } -} - -void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - // TODO(gpike): improve this - format("_this->_internal_set_$name$(from._internal_$name$());\n"); -} - -void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { - Formatter format(printer, variables_); - if (!inlined_) { - format( - "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n" - " &$field$, lhs_arena,\n" - " &other->$field$, rhs_arena\n" - ");\n"); - } else { - format( - "::$proto_ns$::internal::InlinedStringField::InternalSwap(\n" - " &$field$, lhs_arena, " - "($inlined_string_donated_array$[0] & 0x1u) == 0, this,\n" - " &other->$field$, rhs_arena, " - "(other->$inlined_string_donated_array$[0] & 0x1u) == 0, other);\n"); - } -} - -void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const { - Formatter format(printer, variables_); - if (inlined_ && descriptor_->default_value_string().empty()) { - return; - } - GOOGLE_DCHECK(!inlined_); - format("$field$.InitDefault();\n"); - if (IsString(descriptor_, options_) && - descriptor_->default_value_string().empty()) { - format( - "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" - " $field$.Set(\"\", GetArenaForAllocation());\n" - "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); - } -} - -void StringFieldGenerator::GenerateCreateSplitMessageCode( - io::Printer* printer) const { - GOOGLE_CHECK(ShouldSplit(descriptor_, options_)); - GOOGLE_CHECK(!inlined_); - Formatter format(printer, variables_); - format("ptr->$name$_.InitDefault();\n"); - if (IsString(descriptor_, options_) && - descriptor_->default_value_string().empty()) { - format( - "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" - " ptr->$name$_.Set(\"\", GetArenaForAllocation());\n" - "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); - } -} - -void StringFieldGenerator::GenerateCopyConstructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - GenerateConstructorCode(printer); - if (inlined_) { - format("new (&_this->$field$) ::_pbi::InlinedStringField();\n"); - } - - if (HasHasbit(descriptor_)) { - format("if (from._internal_has_$name$()) {\n"); - } else { - format("if (!from._internal_$name$().empty()) {\n"); - } - - format.Indent(); - - if (!inlined_) { - format( - "_this->$field$.Set(from._internal_$name$(), \n" - " _this->GetArenaForAllocation());\n"); - } else { - format( - "_this->$field$.Set(from._internal_$name$(),\n" - " _this->GetArenaForAllocation(), _this->_internal_$name$_donated(), " - "&_this->$donating_states_word$, $mask_for_undonate$, _this);\n"); - } - - format.Outdent(); - format("}\n"); -} - -void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { - Formatter format(printer, variables_); - if (!inlined_) { - if (ShouldSplit(descriptor_, options_)) { - format("$cached_split_ptr$->$name$_.Destroy();\n"); - return; - } - format("$field$.Destroy();\n"); - return; - } - // Explicitly calls ~InlinedStringField as its automatic call is disabled. - // Destructor has been implicitly skipped as a union, and even the - // message-owned arena is enabled, arena could still be missing for - // Arena::CreateMessage(nullptr). - GOOGLE_DCHECK(!ShouldSplit(descriptor_, options_)); - format("$field$.~InlinedStringField();\n"); -} - -ArenaDtorNeeds StringFieldGenerator::NeedsArenaDestructor() const { - return inlined_ ? ArenaDtorNeeds::kOnDemand : ArenaDtorNeeds::kNone; -} - -void StringFieldGenerator::GenerateArenaDestructorCode( - io::Printer* printer) const { - if (!inlined_) return; - Formatter format(printer, variables_); - // _this is the object being destructed (we are inside a static method here). - format( - "if (!_this->_internal_$name$_donated()) {\n" - " _this->$field$.~InlinedStringField();\n" - "}\n"); -} - -void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - descriptor_, options_, false, - "this->_internal_$name$().data(), " - "static_cast<int>(this->_internal_$name$().length()),\n", - format); - } - format( - "target = stream->Write$declared_type$MaybeAliased(\n" - " $number$, this->_internal_$name$(), target);\n"); -} - -void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "total_size += $tag_size$ +\n" - " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" - " this->_internal_$name$());\n"); -} - -void StringFieldGenerator::GenerateConstexprAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (inlined_) { - format("/*decltype($field$)*/{nullptr, false}"); - return; - } - if (descriptor_->default_value_string().empty()) { - format( - "/*decltype($field$)*/{&::_pbi::fixed_address_empty_string, " - "::_pbi::ConstantInitialized{}}"); - } else { - format("/*decltype($field$)*/{nullptr, ::_pbi::ConstantInitialized{}}"); - } -} - -void StringFieldGenerator::GenerateAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (ShouldSplit(descriptor_, options_)) { - GOOGLE_CHECK(!inlined_); - format("decltype(Impl_::Split::$name$_){}"); - return; - } - if (!inlined_) { - format("decltype($field$){}"); - } else { - format("decltype($field$)(arena)"); - } -} - -void StringFieldGenerator::GenerateCopyAggregateInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("decltype($field$){}"); -} - -// =================================================================== - -StringOneofFieldGenerator::StringOneofFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) - : StringFieldGenerator(descriptor, options) { - SetCommonOneofFieldVariables(descriptor, &variables_); - variables_["field_name"] = UnderscoresToCamelCase(descriptor->name(), true); - variables_["oneof_index"] = - StrCat(descriptor->containing_oneof()->index()); -} - -StringOneofFieldGenerator::~StringOneofFieldGenerator() {} - -void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline const TProtoStringType& $classname$::$name$() const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return _internal_$name$();\n" - "}\n" - "template <typename ArgT0, typename... ArgT>\n" - "inline void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" - " if (!_internal_has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $field$.InitDefault();\n" - " }\n" - " $field$.$setter$(" - " static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline TProtoStringType* $classname$::mutable_$name$() {\n" - " TProtoStringType* _s = _internal_mutable_$name$();\n" - "$annotate_mutable$" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return _s;\n" - "}\n" - "inline const TProtoStringType& $classname$::_internal_$name$() const {\n" - " if (_internal_has_$name$()) {\n" - " return $field$.Get();\n" - " }\n" - " return $default_string$;\n" - "}\n" - "inline void $classname$::_internal_set_$name$(const TProtoStringType& " - "value) {\n" - " if (!_internal_has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $field$.InitDefault();\n" - " }\n" - " $field$.Set(value, GetArenaForAllocation());\n" - "}\n"); - format( - "inline TProtoStringType* $classname$::_internal_mutable_$name$() {\n" - " if (!_internal_has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $field$.InitDefault();\n" - " }\n" - " return $field$.Mutable($lazy_variable_args$" - " GetArenaForAllocation());\n" - "}\n" - "inline TProtoStringType* $classname$::$release_name$() {\n" - "$annotate_release$" - " // @@protoc_insertion_point(field_release:$full_name$)\n" - " if (_internal_has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " return $field$.Release();\n" - " } else {\n" - " return nullptr;\n" - " }\n" - "}\n" - "inline void $classname$::set_allocated_$name$(TProtoStringType* $name$) {\n" - " if (has_$oneof_name$()) {\n" - " clear_$oneof_name$();\n" - " }\n" - " if ($name$ != nullptr) {\n" - " set_has_$name$();\n" - " $field$.InitAllocated($name$, GetArenaForAllocation());\n" - " }\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n"); -} - -void StringOneofFieldGenerator::GenerateClearingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.Destroy();\n"); -} - -void StringOneofFieldGenerator::GenerateMessageClearingCode( - io::Printer* printer) const { - return GenerateClearingCode(printer); -} - -void StringOneofFieldGenerator::GenerateSwappingCode( - io::Printer* printer) const { - // Don't print any swapping code. Swapping the union will swap this field. -} - -void StringOneofFieldGenerator::GenerateConstructorCode( - io::Printer* printer) const { - // Nothing required here. -} - -// =================================================================== - -RepeatedStringFieldGenerator::RepeatedStringFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(descriptor, options) { - SetStringVariables(descriptor, &variables_, options); -} - -RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} - -void RepeatedStringFieldGenerator::GeneratePrivateMembers( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("::$proto_ns$::RepeatedPtrField<TProtoStringType> $name$_;\n"); -} - -void RepeatedStringFieldGenerator::GenerateAccessorDeclarations( - io::Printer* printer) const { - Formatter format(printer, variables_); - // See comment above about unknown ctypes. - bool unknown_ctype = descriptor_->options().ctype() != - EffectiveStringCType(descriptor_, options_); - - if (unknown_ctype) { - format.Outdent(); - format( - " private:\n" - " // Hidden due to unknown ctype option.\n"); - format.Indent(); - } - - format( - "$deprecated_attr$const TProtoStringType& ${1$$name$$}$(int index) const;\n" - "$deprecated_attr$TProtoStringType* ${1$mutable_$name$$}$(int index);\n" - "$deprecated_attr$void ${1$set_$name$$}$(int index, const " - "TProtoStringType& value);\n" - "$deprecated_attr$void ${1$set_$name$$}$(int index, TProtoStringType&& " - "value);\n" - "$deprecated_attr$void ${1$set_$name$$}$(int index, const " - "char* value);\n", - descriptor_); - if (!options_.opensource_runtime) { - format( - "$deprecated_attr$void ${1$set_$name$$}$(int index, " - "StringPiece value);\n", - descriptor_); - } - format( - "$deprecated_attr$void ${1$set_$name$$}$(" - "int index, const $pointer_type$* value, size_t size);\n" - "$deprecated_attr$TProtoStringType* ${1$add_$name$$}$();\n" - "$deprecated_attr$void ${1$add_$name$$}$(const TProtoStringType& value);\n" - "$deprecated_attr$void ${1$add_$name$$}$(TProtoStringType&& value);\n" - "$deprecated_attr$void ${1$add_$name$$}$(const char* value);\n", - descriptor_); - if (!options_.opensource_runtime) { - format( - "$deprecated_attr$void ${1$add_$name$$}$(StringPiece value);\n", - descriptor_); - } - format( - "$deprecated_attr$void ${1$add_$name$$}$(const $pointer_type$* " - "value, size_t size)" - ";\n" - "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField<TProtoStringType>& " - "${1$$name$$}$() " - "const;\n" - "$deprecated_attr$::$proto_ns$::RepeatedPtrField<TProtoStringType>* " - "${1$mutable_$name$$}$()" - ";\n" - "private:\n" - "const TProtoStringType& ${1$_internal_$name$$}$(int index) const;\n" - "TProtoStringType* _internal_add_$name$();\n" - "public:\n", - descriptor_); - - if (unknown_ctype) { - format.Outdent(); - format(" public:\n"); - format.Indent(); - } -} - -void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "inline TProtoStringType* $classname$::add_$name$() {\n" - " TProtoStringType* _s = _internal_add_$name$();\n" - "$annotate_add_mutable$" - " // @@protoc_insertion_point(field_add_mutable:$full_name$)\n" - " return _s;\n" - "}\n"); - if (options_.safe_boundary_check) { - format( - "inline const TProtoStringType& $classname$::_internal_$name$(int index) " - "const {\n" - " return $field$.InternalCheckedGet(\n" - " index, ::$proto_ns$::internal::GetEmptyStringAlreadyInited());\n" - "}\n"); - } else { - format( - "inline const TProtoStringType& $classname$::_internal_$name$(int index) " - "const {\n" - " return $field$.Get(index);\n" - "}\n"); - } - format( - "inline const TProtoStringType& $classname$::$name$(int index) const {\n" - "$annotate_get$" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return _internal_$name$(index);\n" - "}\n" - "inline TProtoStringType* $classname$::mutable_$name$(int index) {\n" - "$annotate_mutable$" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $field$.Mutable(index);\n" - "}\n" - "inline void $classname$::set_$name$(int index, const TProtoStringType& " - "value) " - "{\n" - " $field$.Mutable(index)->assign(value);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline void $classname$::set_$name$(int index, TProtoStringType&& value) {\n" - " $field$.Mutable(index)->assign(std::move(value));\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline void $classname$::set_$name$(int index, const char* value) {\n" - " $null_check$" - " $field$.Mutable(index)->assign(value);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n"); - if (!options_.opensource_runtime) { - format( - "inline void " - "$classname$::set_$name$(int index, StringPiece value) {\n" - " $field$.Mutable(index)->assign(value.data(), value.size());\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n" - "}\n"); - } - format( - "inline void " - "$classname$::set_$name$" - "(int index, const $pointer_type$* value, size_t size) {\n" - " $field$.Mutable(index)->assign(\n" - " reinterpret_cast<const char*>(value), size);\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" - "}\n" - "inline TProtoStringType* $classname$::_internal_add_$name$() {\n" - " return $field$.Add();\n" - "}\n" - "inline void $classname$::add_$name$(const TProtoStringType& value) {\n" - " $field$.Add()->assign(value);\n" - "$annotate_add$" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n" - "inline void $classname$::add_$name$(TProtoStringType&& value) {\n" - " $field$.Add(std::move(value));\n" - "$annotate_add$" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n" - "inline void $classname$::add_$name$(const char* value) {\n" - " $null_check$" - " $field$.Add()->assign(value);\n" - "$annotate_add$" - " // @@protoc_insertion_point(field_add_char:$full_name$)\n" - "}\n"); - if (!options_.opensource_runtime) { - format( - "inline void $classname$::add_$name$(StringPiece value) {\n" - " $field$.Add()->assign(value.data(), value.size());\n" - "$annotate_add$" - " // @@protoc_insertion_point(field_add_string_piece:$full_name$)\n" - "}\n"); - } - format( - "inline void " - "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" - " $field$.Add()->assign(reinterpret_cast<const char*>(value), size);\n" - "$annotate_add$" - " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n" - "}\n" - "inline const ::$proto_ns$::RepeatedPtrField<TProtoStringType>&\n" - "$classname$::$name$() const {\n" - "$annotate_list$" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $field$;\n" - "}\n" - "inline ::$proto_ns$::RepeatedPtrField<TProtoStringType>*\n" - "$classname$::mutable_$name$() {\n" - "$annotate_mutable_list$" - " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$field$;\n" - "}\n"); -} - -void RepeatedStringFieldGenerator::GenerateClearingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.Clear();\n"); -} - -void RepeatedStringFieldGenerator::GenerateMergingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("_this->$field$.MergeFrom(from.$field$);\n"); -} - -void RepeatedStringFieldGenerator::GenerateSwappingCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.InternalSwap(&other->$field$);\n"); -} - -void RepeatedStringFieldGenerator::GenerateDestructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$.~RepeatedPtrField();\n"); -} - -void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n" - " const auto& s = this->_internal_$name$(i);\n"); - // format("for (const TProtoStringType& s : this->$name$()) {\n"); - format.Indent(); - if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString(descriptor_, options_, false, - "s.data(), static_cast<int>(s.length()),\n", - format); - } - format.Outdent(); - format( - " target = stream->Write$declared_type$($number$, s, target);\n" - "}\n"); -} - -void RepeatedStringFieldGenerator::GenerateByteSize( - io::Printer* printer) const { - Formatter format(printer, variables_); - format( - "total_size += $tag_size$ *\n" - " ::$proto_ns$::internal::FromIntSize($field$.size());\n" - "for (int i = 0, n = $field$.size(); i < n; i++) {\n" - " total_size += " - "::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" - " $field$.Get(i));\n" - "}\n"); -} - -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.h deleted file mode 100644 index db5f18bfb7d..00000000000 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.h +++ /dev/null @@ -1,136 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: [email protected] (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ - -#include <map> -#include <string> - -#include <google/protobuf/compiler/cpp/field.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -class StringFieldGenerator : public FieldGenerator { - public: - StringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); - ~StringFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateStaticMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateNonInlineAccessorDefinitions( - io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMessageClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - void GenerateCreateSplitMessageCode(io::Printer* printer) const override; - void GenerateCopyConstructorCode(io::Printer* printer) const override; - void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateArenaDestructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstexprAggregateInitializer( - io::Printer* printer) const override; - void GenerateAggregateInitializer(io::Printer* printer) const override; - void GenerateCopyAggregateInitializer(io::Printer* printer) const override; - bool IsInlined() const override { return inlined_; } - ArenaDtorNeeds NeedsArenaDestructor() const override; - - private: - bool inlined_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); -}; - -class StringOneofFieldGenerator : public StringFieldGenerator { - public: - StringOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); - ~StringOneofFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - - // StringFieldGenerator, from which we inherit, overrides this so we need to - // override it as well. - void GenerateMessageClearingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator); -}; - -class RepeatedStringFieldGenerator : public FieldGenerator { - public: - RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); - ~RepeatedStringFieldGenerator() override; - - // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const override; - void GenerateAccessorDeclarations(io::Printer* printer) const override; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; - void GenerateClearingCode(io::Printer* printer) const override; - void GenerateMergingCode(io::Printer* printer) const override; - void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override {} - void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override { - GOOGLE_CHECK(!ShouldSplit(descriptor_, options_)); - } - void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateSerializeWithCachedSizesToArray( - io::Printer* printer) const override; - void GenerateByteSize(io::Printer* printer) const override; - - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); -}; - -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google - -#endif // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/tracker.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/tracker.cc new file mode 100644 index 00000000000..77c45a8ee54 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/tracker.cc @@ -0,0 +1,339 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2022 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/compiler/cpp/tracker.h" + +#include <string> +#include <utility> +#include <vector> + +#include "google/protobuf/descriptor.h" +#include "y_absl/strings/str_cat.h" +#include "y_absl/strings/str_format.h" +#include "y_absl/strings/string_view.h" +#include "y_absl/strings/substitute.h" +#include "y_absl/types/optional.h" +#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/io/printer.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { +namespace { +using Sub = ::google::protobuf::io::Printer::Sub; + +constexpr y_absl::string_view kTracker = "Impl_::_tracker_"; +constexpr y_absl::string_view kVarPrefix = "annotate_"; +constexpr y_absl::string_view kTypeTraits = "_proto_TypeTraits"; + +struct Call { + Call(y_absl::string_view var, y_absl::string_view call) : var(var), call(call) {} + Call(y_absl::optional<int> field_index, y_absl::string_view var, + y_absl::string_view call) + : var(var), call(call), field_index(field_index) {} + + Call This(y_absl::optional<y_absl::string_view> thiz) && { + this->thiz = thiz; + return std::move(*this); + } + + template <typename... SubArgs> + Call Arg(y_absl::string_view format, const SubArgs&... args) && { + this->args.emplace_back(y_absl::Substitute(format, args...)); + return std::move(*this); + } + + Call Suppressed() && { + suppressed = true; + return std::move(*this); + } + + y_absl::string_view var; + y_absl::string_view call; + y_absl::optional<int> field_index; + y_absl::optional<y_absl::string_view> thiz = "this"; + std::vector<TProtoStringType> args; + bool suppressed = false; +}; + +std::vector<Sub> GenerateTrackerCalls( + const Options& opts, const Descriptor* message, + y_absl::optional<TProtoStringType> alt_annotation, y_absl::Span<const Call> calls) { + bool enable_tracking = HasTracker(message, opts); + const auto& forbidden = + opts.field_listener_options.forbidden_field_listener_events; + + std::vector<Sub> subs; + for (const auto& call : calls) { + TProtoStringType call_str; + if (enable_tracking && !call.suppressed && !forbidden.contains(call.var)) { + y_absl::SubstituteAndAppend(&call_str, "$0.$1", kTracker, call.call); + if (call.field_index.has_value()) { + y_absl::SubstituteAndAppend(&call_str, "<$0>", *call.field_index); + } + y_absl::StrAppend(&call_str, "("); + + y_absl::string_view arg_sep = ""; + if (call.thiz.has_value()) { + y_absl::StrAppend(&call_str, *call.thiz); + arg_sep = ", "; + } + + for (const auto& arg : call.args) { + y_absl::StrAppend(&call_str, arg_sep, arg); + arg_sep = ", "; + } + + y_absl::StrAppend(&call_str, ");"); + } else if (opts.annotate_accessor && alt_annotation.has_value()) { + call_str = *alt_annotation; + } + + if (!call_str.empty()) { + // TODO(b/245791219): Until we migrate all of the C++ backend to use + // Emit(), we need to include a newline here so that the line that follows + // the annotation is on its own line. + call_str.push_back('\n'); + } + + subs.push_back( + Sub(y_absl::StrCat(kVarPrefix, call.var), call_str).WithSuffix(";")); + } + + return subs; +} +} // namespace + +std::vector<Sub> MakeTrackerCalls(const Descriptor* message, + const Options& opts) { + y_absl::string_view extns = + IsMapEntryMessage(message) ? "_extensions_" : "_impl_._extensions_"; + + auto primitive_extn_accessor = [extns](y_absl::string_view var, + y_absl::string_view call) { + return Call(var, call) + .Arg("id.number()") + .Arg("$0::GetPtr(id.number(), $1, id.default_value_ref())", kTypeTraits, + extns); + }; + + auto index_extn_accessor = [extns](y_absl::string_view var, + y_absl::string_view call) { + return Call(var, call) + .Arg("id.number()") + .Arg("$0::GetPtr(id.number(), $1, index)", kTypeTraits, extns); + }; + + auto add_extn_accessor = [extns](y_absl::string_view var, + y_absl::string_view call) { + return Call(var, call) + .Arg("id.number()") + .Arg("$0::GetPtr(id.number(), $1, $1.ExtensionSize(id.number()) - 1)", + kTypeTraits, extns); + }; + + auto list_extn_accessor = [extns](y_absl::string_view var, + y_absl::string_view call) { + return Call(var, call) + .Arg("id.number()") + .Arg("$0::GetRepeatedPtr(id.number(), $1)", kTypeTraits, extns); + }; + + return GenerateTrackerCalls( + opts, message, y_absl::nullopt, + { + Call("serialize", "OnSerialize"), + Call("deserialize", "OnDeserialize"), + // TODO(danilak): Ideally annotate_reflection should not exist and we + // need to annotate all reflective calls on our own, however, as this + // is a cause for side effects, i.e. reading values dynamically, we + // want the users know that dynamic access can happen. + Call("reflection", "OnGetMetadata").This(y_absl::nullopt), + Call("bytesize", "OnByteSize"), + Call("mergefrom", "OnMergeFrom").This("_this").Arg("&from"), + + // "Has" is here as users calling "has" on a repeated field is a + // mistake. + primitive_extn_accessor("extension_has", "OnHasExtension"), + primitive_extn_accessor("extension_get", "OnGetExtension"), + primitive_extn_accessor("extension_mutable", "OnMutableExtension"), + primitive_extn_accessor("extension_set", "OnSetExtension"), + primitive_extn_accessor("extension_release", "OnReleaseExtension"), + + index_extn_accessor("repeated_extension_get", "OnGetExtension"), + index_extn_accessor("repeated_extension_mutable", + "OnMutableExtension"), + index_extn_accessor("repeated_extension_set", "OnSetExtension"), + + add_extn_accessor("repeated_extension_add", "OnAddExtension"), + add_extn_accessor("repeated_extension_add_mutable", + "OnAddMutableExtension"), + + list_extn_accessor("extension_repeated_size", "OnExtensionSize"), + list_extn_accessor("repeated_extension_list", "OnListExtension"), + list_extn_accessor("repeated_extension_list_mutable", + "OnMutableListExtension"), + + // Generic accessors such as "clear". + // TODO(b/190614678): Generalize clear from both repeated and non + // repeated calls, currently their underlying memory interfaces are + // very different. Or think of removing clear callback as no usages + // are needed and no memory exist + Call("extension_clear", "OnClearExtension").Suppressed(), + }); +} + +namespace { +struct Getters { + TProtoStringType base = "nullptr"; + TProtoStringType for_last = "nullptr"; + TProtoStringType for_flat = "nullptr"; +}; + +Getters RepeatedFieldGetters(const FieldDescriptor* field, + const Options& opts) { + TProtoStringType member = FieldMemberName(field, ShouldSplit(field, opts)); + + Getters getters; + if (!field->is_map() && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + getters.base = y_absl::Substitute("&$0.Get(index)", member); + getters.for_last = y_absl::Substitute("&$0.Get($0.size() - 1)", member); + getters.for_flat = y_absl::StrCat("&", member); + } + + return getters; +} + +Getters StringFieldGetters(const FieldDescriptor* field, const Options& opts) { + TProtoStringType member = FieldMemberName(field, ShouldSplit(field, opts)); + bool is_std_string = field->options().ctype() == FieldOptions::STRING; + + Getters getters; + if (is_std_string && !field->default_value_string().empty()) { + getters.base = + y_absl::Substitute("$0.IsDefault() ? &$1.get() : $0.UnsafeGetPointer()", + member, MakeDefaultFieldName(field)); + } else { + getters.base = y_absl::StrCat("&", member); + } + + getters.for_flat = getters.base; + return getters; +} + +Getters StringOneofGetters(const FieldDescriptor* field, + const OneofDescriptor* oneof, const Options& opts) { + Y_ABSL_CHECK(oneof != nullptr); + + TProtoStringType member = FieldMemberName(field, ShouldSplit(field, opts)); + bool is_std_string = field->options().ctype() == FieldOptions::STRING; + + TProtoStringType field_ptr = member; + if (is_std_string) { + field_ptr = y_absl::Substitute("$0.UnsafeGetPointer()", member); + } + + TProtoStringType has = + y_absl::Substitute("$0_case() == k$1", oneof->name(), + UnderscoresToCamelCase(field->name(), true)); + + TProtoStringType default_field = MakeDefaultFieldName(field); + if (is_std_string) { + y_absl::StrAppend(&default_field, ".get()"); + } + + Getters getters; + if (field->default_value_string().empty() || + field->options().ctype() == FieldOptions::STRING_PIECE) { + getters.base = y_absl::Substitute("$0 ? $1 : nullptr", has, field_ptr); + } else { + getters.base = + y_absl::Substitute("$0 ? $1 : &$2", has, field_ptr, default_field); + } + + getters.for_flat = getters.base; + return getters; +} + +Getters SingularFieldGetters(const FieldDescriptor* field, + const Options& opts) { + TProtoStringType member = FieldMemberName(field, ShouldSplit(field, opts)); + + Getters getters; + getters.base = y_absl::StrCat("&", member); + if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + getters.for_flat = y_absl::StrCat("&", member); + } + return getters; +} +} // namespace + +std::vector<Sub> MakeTrackerCalls(const FieldDescriptor* field, + const Options& opts) { + Getters getters; + if (field->is_repeated()) { + getters = RepeatedFieldGetters(field, opts); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + const auto* oneof = field->real_containing_oneof(); + if (oneof != nullptr) { + getters = StringOneofGetters(field, oneof, opts); + } else { + getters = StringFieldGetters(field, opts); + } + } else if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE || + IsExplicitLazy(field)) { + getters = SingularFieldGetters(field, opts); + } + + auto index = field->index(); + return GenerateTrackerCalls( + opts, field->containing_type(), + y_absl::Substitute("$0_AccessedNoStrip = true;", FieldName(field)), + { + Call(index, "get", "OnGet").Arg(getters.base), + Call(index, "set", "OnSet").Arg(getters.base), + Call(index, "has", "OnHas").Arg(getters.base), + Call(index, "mutable", "OnMutable").Arg(getters.base), + Call(index, "release", "OnRelease").Arg(getters.base), + Call(index, "clear", "OnClear").Arg(getters.for_flat), + Call(index, "size", "OnSize").Arg(getters.for_flat), + Call(index, "list", "OnList").Arg(getters.for_flat), + Call(index, "mutable_list", "OnMutableList").Arg(getters.for_flat), + Call(index, "add", "OnAdd").Arg(getters.for_last), + Call(index, "add_mutable", "OnAddMutable").Arg(getters.for_last), + }); +} +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/tracker.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/tracker.h new file mode 100644 index 00000000000..9f00495291e --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/tracker.h @@ -0,0 +1,58 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2022 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_TRACKER_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_TRACKER_H__ + +#include <vector> + +#include "google/protobuf/descriptor.h" +#include "google/protobuf/compiler/cpp/options.h" +#include "google/protobuf/io/printer.h" + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Generates printer substitutions for message-level tracker callbacks. +std::vector<google::protobuf::io::Printer::Sub> MakeTrackerCalls( + const google::protobuf::Descriptor* message, const Options& opts); + +// Generates printer substitutions for field-specific tracker callbacks. +std::vector<google::protobuf::io::Printer::Sub> MakeTrackerCalls( + const google::protobuf::FieldDescriptor* field, const Options& opts); + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_TRACKER_H__ |