aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/protoc/src/google/protobuf/compiler/cpp
diff options
context:
space:
mode:
authorheretic <heretic@yandex-team.ru>2022-06-14 13:29:31 +0300
committerheretic <heretic@yandex-team.ru>2022-06-14 13:29:31 +0300
commit16f8be4f481c275c34795233c18f8d078382fcb3 (patch)
tree2363f1306ce2e17e72c0a48614256acd046990e6 /contrib/libs/protoc/src/google/protobuf/compiler/cpp
parent647dc68b78e469e5ab416e9b62885c9846fd511d (diff)
downloadydb-16f8be4f481c275c34795233c18f8d078382fcb3.tar.gz
Update protobuf to 3.18.1
ref:4846abb21711ea0dc148d4c5df7b5edd3d1bdc69
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/cpp')
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h54
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc17
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h6
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc186
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h9
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc46
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h13
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc52
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc75
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h66
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc817
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h9
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h73
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h10
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc628
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h27
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc17
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h52
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc186
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h64
20 files changed, 1651 insertions, 756 deletions
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h
index 3fa64a8640..793ab2d793 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -50,17 +50,18 @@ class EnumFieldGenerator : public FieldGenerator {
~EnumFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GeneratePrivateMembers(io::Printer* printer) const;
- void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateMergingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
- void GenerateCopyConstructorCode(io::Printer* printer) const;
- void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
- void GenerateByteSize(io::Printer* printer) const;
- void GenerateConstinitInitializer(io::Printer* printer) const;
+ 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 GenerateConstinitInitializer(io::Printer* printer) const override;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
@@ -73,10 +74,10 @@ class EnumOneofFieldGenerator : public EnumFieldGenerator {
~EnumOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
+ 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);
@@ -89,19 +90,20 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
~RepeatedEnumFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GeneratePrivateMembers(io::Printer* printer) const;
- void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateMergingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
- void GenerateCopyConstructorCode(io::Printer* printer) const {}
+ 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 GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const;
- void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
- void GenerateByteSize(io::Printer* printer) const;
- void GenerateConstinitInitializer(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizesToArray(
+ io::Printer* printer) const override;
+ void GenerateByteSize(io::Printer* printer) const override;
+ void GenerateConstinitInitializer(io::Printer* printer) const override;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc
index 9b0fcb02da..23ab1bc0bb 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc
@@ -57,8 +57,9 @@ TProtoStringType ExtendeeClassName(const FieldDescriptor* descriptor) {
} // anonymous namespace
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
- const Options& options)
- : descriptor_(descriptor), options_(options) {
+ const Options& options,
+ MessageSCCAnalyzer* scc_analyzer)
+ : descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) {
// Construct type_traits_.
if (descriptor_->is_repeated()) {
type_traits_ = "Repeated";
@@ -179,6 +180,18 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
" ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n"
" $scoped_name$($constant_name$, $1$);\n",
default_str);
+
+ // Register extension verify function if needed.
+ if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
+ ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_)) {
+ format(
+ "PROTOBUF_ATTRIBUTE_INIT_PRIORITY "
+ "::$proto_ns$::internal::RegisterExtensionVerify< $extendee$,\n"
+ " $1$, $number$> $2$_$name$_register;\n",
+ ClassName(descriptor_->message_type(), true),
+ IsScoped() ? ClassName(descriptor_->extension_scope(), false) : "");
+ }
}
} // namespace cpp
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h
index 88c7dafbc3..5a32e84554 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h
@@ -55,6 +55,8 @@ namespace protobuf {
namespace compiler {
namespace cpp {
+class MessageSCCAnalyzer;
+
// Generates code for an extension, which may be within the scope of some
// message or may be at file scope. This is much simpler than FieldGenerator
// since extensions are just simple identifiers with interesting types.
@@ -62,7 +64,8 @@ class ExtensionGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
explicit ExtensionGenerator(const FieldDescriptor* descriptor,
- const Options& options);
+ const Options& options,
+ MessageSCCAnalyzer* scc_analyzer);
~ExtensionGenerator();
// Header stuff.
@@ -77,6 +80,7 @@ class ExtensionGenerator {
const FieldDescriptor* descriptor_;
TProtoStringType type_traits_;
Options options_;
+ MessageSCCAnalyzer* scc_analyzer_;
std::map<TProtoStringType, TProtoStringType> variables_;
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc
index 09261aaddc..22e2a8a4a6 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -61,37 +61,39 @@ using internal::WireFormat;
namespace {
-TProtoStringType GenerateAnnotation(StringPiece substitute_template_prefix,
- StringPiece prepared_template,
- StringPiece substitute_template_suffix,
- int field_index, StringPiece lambda_args,
- StringPiece access_type) {
- return strings::Substitute(
- StrCat(substitute_template_prefix, prepared_template,
- substitute_template_suffix),
- field_index, access_type, lambda_args);
+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.GetPointer()"
: "$0";
if (descriptor->default_value_string().empty()) {
- return strings::Substitute(
- StrCat("_internal_has_",
- google::protobuf::compiler::cpp::FieldName(descriptor),
- "()? _listener_->ExtractFieldInfo(", field_pointer,
- "): ::", proto_ns, "::FieldAccessListener::AddressInfo()"),
- field_member);
+ return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ",
+ field_pointer, ": nullptr"),
+ field_member);
}
if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING_PIECE) {
- return StrCat("_listener_->ExtractFieldInfo(_internal_",
- google::protobuf::compiler::cpp::FieldName(descriptor), "())");
+ return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ",
+ field_pointer, ": nullptr"),
+ field_member);
}
TProtoStringType default_value_pointer =
@@ -99,26 +101,24 @@ TProtoStringType GenerateTemplateForOneofString(const FieldDescriptor* descripto
? "&$1.get()"
: "&$1";
return strings::Substitute(
- StrCat("_listener_->ExtractFieldInfo(_internal_has_",
- google::protobuf::compiler::cpp::FieldName(descriptor), "()? ",
- field_pointer, " : ", default_value_pointer, ")"),
+ StrCat("_internal_has_", field_name, "() ? ", field_pointer, " : ",
+ default_value_pointer),
field_member, MakeDefaultName(descriptor));
}
TProtoStringType GenerateTemplateForSingleString(const FieldDescriptor* descriptor,
StringPiece field_member) {
if (descriptor->default_value_string().empty()) {
- return strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member);
+ return StrCat("&", field_member);
}
if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) {
return strings::Substitute(
- "_listener_->ExtractFieldInfo($0.IsDefault("
- "nullptr) ? &$1.get() : $0.GetPointer())",
- field_member, MakeDefaultName(descriptor));
+ "$0.IsDefault(nullptr) ? &$1.get() : $0.GetPointer()", field_member,
+ MakeDefaultName(descriptor));
}
- return strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member);
+ return StrCat("&", field_member);
}
} // namespace
@@ -143,7 +143,7 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor,
" ", FieldName(descriptor), "_AccessedNoStrip = true;\n");
}
}
- if (!options.inject_field_listener_events) {
+ if (!options.field_listener_options.inject_field_listener_events) {
return;
}
if (descriptor->file()->options().optimize_for() ==
@@ -157,50 +157,29 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor,
field_member = StrCat(oneof_member->name(), "_.", field_member);
}
const TProtoStringType proto_ns = (*variables)["proto_ns"];
- TProtoStringType lambda_args = "_listener_, this";
- TProtoStringType lambda_flat_args = "_listener_, this";
- const TProtoStringType substitute_template_prefix = StrCat(
- " {\n"
- " auto _listener_ = ::",
- proto_ns,
- "::FieldAccessListener::GetListener();\n"
- " if (_listener_) _listener_->OnFieldAccess([$2] { return ");
- const TProtoStringType substitute_template_suffix = StrCat(
- "; }, "
- "GetDescriptor()->field($0), "
- "::",
- proto_ns,
- "::FieldAccessListener::FieldAccessType::$1);\n"
- " }\n");
+ const TProtoStringType substitute_template_prefix = " _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(jianzhouzh): Fix all forward declared messages and deal with the
- // weak fields.
+ // 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) {
- lambda_args = "_listener_, this, index";
- prepared_template = strings::Substitute(
- "_listener_->ExtractFieldInfo(&$0.Get(index))", field_member);
- prepared_add_template = strings::Substitute(
- "_listener_->ExtractFieldInfo(&$0.Get($0.size() - 1))", field_member);
- } else {
- prepared_template =
- StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()");
+ prepared_template = strings::Substitute("&$0.Get(index)", field_member);
prepared_add_template =
- StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()");
+ strings::Substitute("&$0.Get($0.size() - 1)", field_member);
+ } else {
+ prepared_template = "nullptr";
+ prepared_add_template = "nullptr";
}
} else if (descriptor->is_map()) {
- prepared_template =
- StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()");
+ prepared_template = "nullptr";
} else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
!descriptor->options().lazy()) {
- prepared_template =
- StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()");
+ prepared_template = "nullptr";
} else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
if (oneof_member) {
prepared_template = GenerateTemplateForOneofString(
@@ -210,56 +189,49 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor,
GenerateTemplateForSingleString(descriptor, field_member);
}
} else {
- prepared_template =
- strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member);
+ 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 =
- strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member);
+ prepared_flat_template = StrCat("&", field_member);
} else {
prepared_flat_template = prepared_template;
}
- (*variables)["annotate_get"] = GenerateAnnotation(
- substitute_template_prefix, prepared_template, substitute_template_suffix,
- descriptor->index(), lambda_args, "kGet");
- (*variables)["annotate_set"] = GenerateAnnotation(
- substitute_template_prefix, prepared_template, substitute_template_suffix,
- descriptor->index(), lambda_args, "kSet");
- (*variables)["annotate_has"] = GenerateAnnotation(
- substitute_template_prefix, prepared_template, substitute_template_suffix,
- descriptor->index(), lambda_args, "kHas");
- (*variables)["annotate_mutable"] = GenerateAnnotation(
- substitute_template_prefix, prepared_template, substitute_template_suffix,
- descriptor->index(), lambda_args, "kMutable");
- (*variables)["annotate_release"] = GenerateAnnotation(
- substitute_template_prefix, prepared_template, substitute_template_suffix,
- descriptor->index(), lambda_args, "kRelease");
- (*variables)["annotate_clear"] =
- GenerateAnnotation(substitute_template_prefix, prepared_flat_template,
- substitute_template_suffix, descriptor->index(),
- lambda_flat_args, "kClear");
- (*variables)["annotate_size"] =
- GenerateAnnotation(substitute_template_prefix, prepared_flat_template,
- substitute_template_suffix, descriptor->index(),
- lambda_flat_args, "kSize");
- (*variables)["annotate_list"] =
- GenerateAnnotation(substitute_template_prefix, prepared_flat_template,
- substitute_template_suffix, descriptor->index(),
- lambda_flat_args, "kList");
- (*variables)["annotate_mutable_list"] =
- GenerateAnnotation(substitute_template_prefix, prepared_flat_template,
- substitute_template_suffix, descriptor->index(),
- lambda_flat_args, "kMutableList");
- (*variables)["annotate_add"] =
- GenerateAnnotation(substitute_template_prefix, prepared_add_template,
- substitute_template_suffix, descriptor->index(),
- lambda_flat_args, "kAdd");
- (*variables)["annotate_add_mutable"] =
- GenerateAnnotation(substitute_template_prefix, prepared_add_template,
- substitute_template_suffix, descriptor->index(),
- lambda_flat_args, "kAddMutable");
+
+ 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,
@@ -310,6 +282,22 @@ void FieldGenerator::SetHasBitIndex(int32_t has_bit_index) {
strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;");
}
+void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) {
+ if (!IsStringInlined(descriptor_, options_)) {
+ GOOGLE_CHECK_EQ(inlined_string_index, -1);
+ return;
+ }
+ variables_["inlined_string_donated"] = StrCat(
+ "(_inlined_string_donated_[", inlined_string_index / 32, "] & 0x",
+ strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8),
+ "u) != 0;");
+ variables_["donating_states_word"] =
+ StrCat("_inlined_string_donated_[", inlined_string_index / 32, "]");
+ variables_["mask_for_undonate"] = StrCat(
+ "~0x", strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8),
+ "u");
+}
+
void SetCommonOneofFieldVariables(
const FieldDescriptor* descriptor,
std::map<TProtoStringType, TProtoStringType>* variables) {
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h
index b05f2d93fa..d263b10e70 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -181,7 +181,10 @@ class FieldGenerator {
// are placed in the message's ByteSize() method.
virtual void GenerateByteSize(io::Printer* printer) const = 0;
+ virtual bool IsInlined() const { return false; }
+
void SetHasBitIndex(int32_t has_bit_index);
+ void SetInlinedStringIndex(int32_t inlined_string_index);
protected:
const FieldDescriptor* descriptor_;
@@ -207,6 +210,12 @@ class FieldGeneratorMap {
}
}
+ 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]);
+ }
+ }
+
private:
const Descriptor* descriptor_;
std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc
index c371a55233..6e3f174c5b 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -131,7 +131,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
}
for (int i = 0; i < file->extension_count(); i++) {
extension_generators_.emplace_back(
- new ExtensionGenerator(file->extension(i), options));
+ new ExtensionGenerator(file->extension(i), options, &scc_analyzer_));
}
for (int i = 0; i < file->weak_dependency_count(); ++i) {
weak_deps_.insert(file->weak_dependency(i));
@@ -468,6 +468,19 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
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_PRIORITY std::true_type "
+ "$1$::_init_inline_$2$_ = "
+ "($3$._instance.$2$_.Init(), std::true_type{});\n",
+ ClassName(generator->descriptor_), FieldName(field),
+ DefaultInstanceName(generator->descriptor_, options_));
+ }
+ }
+
if (options_.lite_implicit_weak_fields) {
format("$1$* $2$ = &$3$;\n",
DefaultInstanceType(generator->descriptor_, options_),
@@ -583,6 +596,13 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) {
"// @@protoc_insertion_point(global_scope)\n");
}
+void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) {
+ Formatter format(printer, variables_);
+ GenerateSourceIncludes(printer);
+ NamespaceOpener ns(Namespace(file_, options_), format);
+ extension_generators_[idx]->GenerateDefinition(printer);
+}
+
void FileGenerator::GenerateGlobalSource(io::Printer* printer) {
Formatter format(printer, variables_);
GenerateSourceIncludes(printer);
@@ -603,21 +623,6 @@ void FileGenerator::GenerateGlobalSource(io::Printer* printer) {
for (int i = 0; i < enum_generators_.size(); i++) {
enum_generators_[i]->GenerateMethods(i, printer);
}
-
- // Define extensions.
- for (int i = 0; i < extension_generators_.size(); i++) {
- extension_generators_[i]->GenerateDefinition(printer);
- }
-
- 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);
- }
- }
}
void FileGenerator::GenerateSource(io::Printer* printer) {
@@ -1176,6 +1181,9 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
GOOGLE_CHECK(!options_.opensource_runtime);
IncludeFile("net/proto2/public/lazy_field.h", printer);
}
+ if (ShouldVerify(file_, options_, &scc_analyzer_)) {
+ IncludeFile("net/proto2/public/wire_format_verify.h", printer);
+ }
if (options_.opensource_runtime) {
// Verify the protobuf library header version is compatible with the protoc
@@ -1203,6 +1211,12 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
IncludeFile("net/proto2/io/public/coded_stream.h", printer);
IncludeFile("net/proto2/public/arena.h", printer);
IncludeFile("net/proto2/public/arenastring.h", printer);
+ if (options_.force_inline_string || options_.profile_driven_inline_string) {
+ IncludeFile("net/proto2/public/inlined_string_field.h", printer);
+ }
+ if (HasSimpleBaseClasses(file_, options_)) {
+ IncludeFile("net/proto2/public/generated_message_bases.h", printer);
+ }
IncludeFile("net/proto2/public/generated_message_table_driven.h", printer);
if (HasGeneratedMethods(file_, options_) &&
options_.tctable_mode != Options::kTCTableNever) {
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h
index 41e3907391..984bd26a31 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -82,9 +82,20 @@ class FileGenerator {
void GeneratePBHeader(io::Printer* printer, const TProtoStringType& info_path);
void GenerateSource(io::Printer* printer);
+ // 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
+ // promote better linker stripping of unused code. In particular, we generate
+ // one .cc file per message, one .cc file per extension, and a main pb.cc file
+ // containing everything else.
+
int NumMessages() const { return message_generators_.size(); }
- // Similar to GenerateSource but generates only one message
+ int NumExtensions() const { return extension_generators_.size(); }
+ // Generates the source file for one message.
void GenerateSourceForMessage(int idx, io::Printer* printer);
+ // Generates the source file for one extension.
+ void GenerateSourceForExtension(int idx, io::Printer* printer);
+ // Generates a source file containing everything except messages and
+ // extensions.
void GenerateGlobalSource(io::Printer* printer);
private:
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 1642299f98..7fe7511d0d 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -35,6 +35,7 @@
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <memory>
+#include <string>
#include <utility>
#include <vector>
@@ -53,6 +54,12 @@ namespace cpp {
CppGenerator::CppGenerator() {}
CppGenerator::~CppGenerator() {}
+namespace {
+TProtoStringType NumberedCcFileName(const TProtoStringType& basename, int number) {
+ return StrCat(basename, ".out/", number, ".cc");
+}
+} // namespace
+
bool CppGenerator::Generate(const FileDescriptor* file,
const TProtoStringType& parameter,
GeneratorContext* generator_context,
@@ -107,7 +114,19 @@ bool CppGenerator::Generate(const FileDescriptor* file,
} else if (options[i].first == "annotate_accessor") {
file_options.annotate_accessor = true;
} else if (options[i].first == "inject_field_listener_events") {
- file_options.inject_field_listener_events = true;
+ file_options.field_listener_options.inject_field_listener_events = true;
+ } else if (options[i].first == "forbidden_field_listener_events") {
+ std::size_t pos = 0;
+ do {
+ std::size_t next_pos = options[i].second.find_first_of("+", pos);
+ if (next_pos == TProtoStringType::npos) {
+ next_pos = options[i].second.size();
+ }
+ if (next_pos > pos)
+ file_options.field_listener_options.forbidden_field_listener_events
+ .insert(options[i].second.substr(pos, next_pos - pos));
+ pos = next_pos + 1;
+ } while (pos < options[i].second.size());
} else if (options[i].first == "eagerly_verified_lazy") {
file_options.eagerly_verified_lazy = true;
} else if (options[i].first == "force_eagerly_verified_lazy") {
@@ -206,24 +225,37 @@ bool CppGenerator::Generate(const FileDescriptor* file,
file_generator.GenerateGlobalSource(&printer);
}
- int num_cc_files = file_generator.NumMessages();
+ int num_cc_files =
+ file_generator.NumMessages() + file_generator.NumExtensions();
// If we're using implicit weak fields then we allow the user to
// optionally specify how many files to generate, not counting the global
// 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(file_generator.NumMessages(), file_options.num_cc_files)
- << "There must be at least as many numbered .cc files as messages.";
+ GOOGLE_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;
}
- for (int i = 0; i < num_cc_files; i++) {
- std::unique_ptr<io::ZeroCopyOutputStream> output(
- generator_context->Open(StrCat(basename, ".out/", i, ".cc")));
+ int cc_file_number = 0;
+ for (int i = 0; i < file_generator.NumMessages(); i++) {
+ std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(
+ NumberedCcFileName(basename, cc_file_number++)));
io::Printer printer(output.get(), '$');
- if (i < file_generator.NumMessages()) {
- file_generator.GenerateSourceForMessage(i, &printer);
- }
+ file_generator.GenerateSourceForMessage(i, &printer);
+ }
+ for (int i = 0; i < file_generator.NumExtensions(); i++) {
+ std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open(
+ NumberedCcFileName(basename, cc_file_number++)));
+ io::Printer printer(output.get(), '$');
+ file_generator.GenerateSourceForExtension(i, &printer);
+ }
+ // 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)));
}
} else {
std::unique_ptr<io::ZeroCopyOutputStream> output(
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 0f9660d237..736b73a3ea 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -169,30 +169,6 @@ static std::unordered_set<TProtoStringType>* MakeKeywordsMap() {
static std::unordered_set<TProtoStringType>& kKeywords = *MakeKeywordsMap();
-// Encode [0..63] as 'A'-'Z', 'a'-'z', '0'-'9', '_'
-char Base63Char(int value) {
- GOOGLE_CHECK_GE(value, 0);
- if (value < 26) return 'A' + value;
- value -= 26;
- if (value < 26) return 'a' + value;
- value -= 26;
- if (value < 10) return '0' + value;
- GOOGLE_CHECK_EQ(value, 10);
- return '_';
-}
-
-// Given a c identifier has 63 legal characters we can't implement base64
-// encoding. So we return the k least significant "digits" in base 63.
-template <typename I>
-TProtoStringType Base63(I n, int k) {
- TProtoStringType res;
- while (k-- > 0) {
- res += Base63Char(static_cast<int>(n % 63));
- n /= 63;
- }
- return res;
-}
-
TProtoStringType IntTypeName(const Options& options, const TProtoStringType& type) {
if (options.opensource_runtime) {
return "::PROTOBUF_NAMESPACE_ID::" + type;
@@ -400,7 +376,7 @@ TProtoStringType Namespace(const FileDescriptor* d, const Options& options) {
ret = StringReplace(ret,
"::google::"
"protobuf",
- "PROTOBUF_NAMESPACE_ID", false);
+ "::PROTOBUF_NAMESPACE_ID", false);
}
return ret;
}
@@ -454,9 +430,14 @@ TProtoStringType FileDllExport(const FileDescriptor* file, const Options& option
TProtoStringType SuperClassName(const Descriptor* descriptor,
const Options& options) {
- return "::" + ProtobufNamespace(options) +
- (HasDescriptorMethods(descriptor->file(), options) ? "::Message"
- : "::MessageLite");
+ if (!HasDescriptorMethods(descriptor->file(), options)) {
+ return "::" + ProtobufNamespace(options) + "::MessageLite";
+ }
+ auto simple_base = SimpleBaseClass(descriptor, options);
+ if (simple_base.empty()) {
+ return "::" + ProtobufNamespace(options) + "::Message";
+ }
+ return "::" + ProtobufNamespace(options) + "::internal::" + simple_base;
}
TProtoStringType ResolveKeyword(const TProtoStringType& name) {
@@ -796,6 +777,11 @@ TProtoStringType SafeFunctionName(const Descriptor* descriptor,
return function_name;
}
+bool IsStringInlined(const FieldDescriptor* /* descriptor */,
+ const Options& /* options */) {
+ return false;
+}
+
static bool HasLazyFields(const Descriptor* descriptor, const Options& options,
MessageSCCAnalyzer* scc_analyzer) {
for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) {
@@ -953,6 +939,18 @@ bool HasEnumDefinitions(const FileDescriptor* file) {
return false;
}
+bool ShouldVerify(const Descriptor* /* descriptor */,
+ const Options& /* options */,
+ MessageSCCAnalyzer* /* scc_analyzer */) {
+ return false;
+}
+
+bool ShouldVerify(const FileDescriptor* /* file */,
+ const Options& /* options */,
+ MessageSCCAnalyzer* /* scc_analyzer */) {
+ return false;
+}
+
bool IsStringOrMessage(const FieldDescriptor* field) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
@@ -1099,21 +1097,12 @@ void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
"VerifyUTF8CordNamedField", format);
}
-namespace {
-
-void Flatten(const Descriptor* descriptor,
- std::vector<const Descriptor*>* flatten) {
- for (int i = 0; i < descriptor->nested_type_count(); i++)
- Flatten(descriptor->nested_type(i), flatten);
- flatten->push_back(descriptor);
-}
-
-} // namespace
-
void FlattenMessagesInFile(const FileDescriptor* file,
std::vector<const Descriptor*>* result) {
for (int i = 0; i < file->message_type_count(); i++) {
- Flatten(file->message_type(i), result);
+ ForEachMessage(file->message_type(i), [&](const Descriptor* descriptor) {
+ result->push_back(descriptor);
+ });
}
}
@@ -1154,7 +1143,7 @@ bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
if (analysis_cache_.count(scc)) return analysis_cache_[scc];
- MessageAnalysis result{};
+ MessageAnalysis result;
if (UsingImplicitWeakFields(scc->GetFile(), options_)) {
result.contains_weak = true;
}
@@ -1481,6 +1470,10 @@ FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
return FileOptions::SPEED;
}
+bool EnableMessageOwnedArena(const Descriptor* /* desc */) {
+ return false;
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 1cc9329c86..8923903452 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -315,6 +315,8 @@ inline bool IsWeak(const FieldDescriptor* field, const Options& options) {
return false;
}
+bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options);
+
// For a string field, returns the effective ctype. If the actual ctype is
// not supported, returns the default of STRING.
FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
@@ -325,6 +327,11 @@ inline bool IsCord(const FieldDescriptor* field, const Options& options) {
EffectiveStringCType(field, options) == FieldOptions::CORD;
}
+inline bool IsString(const FieldDescriptor* field, const Options& options) {
+ return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+ EffectiveStringCType(field, options) == FieldOptions::STRING;
+}
+
inline bool IsStringPiece(const FieldDescriptor* field,
const Options& options) {
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
@@ -533,6 +540,19 @@ inline std::vector<const Descriptor*> FlattenMessagesInFile(
return result;
}
+template <typename F>
+void ForEachMessage(const Descriptor* descriptor, F&& func) {
+ for (int i = 0; i < descriptor->nested_type_count(); i++)
+ ForEachMessage(descriptor->nested_type(i), std::forward<F&&>(func));
+ func(descriptor);
+}
+
+template <typename F>
+void ForEachMessage(const FileDescriptor* descriptor, F&& func) {
+ for (int i = 0; i < descriptor->message_type_count(); i++)
+ ForEachMessage(descriptor->message_type(i), std::forward<F&&>(func));
+}
+
bool HasWeakFields(const Descriptor* desc, const Options& options);
bool HasWeakFields(const FileDescriptor* desc, const Options& options);
@@ -545,11 +565,11 @@ inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field,
}
struct MessageAnalysis {
- bool is_recursive;
- bool contains_cord;
- bool contains_extension;
- bool contains_required;
- bool contains_weak; // Implicit weak as well.
+ bool is_recursive = false;
+ bool contains_cord = false;
+ bool contains_extension = false;
+ bool contains_required = false;
+ bool contains_weak = false; // Implicit weak as well.
};
// This class is used in FileGenerator, to ensure linear instead of
@@ -630,6 +650,36 @@ bool UsingImplicitWeakFields(const FileDescriptor* file,
bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options,
MessageSCCAnalyzer* scc_analyzer);
+inline bool HasSimpleBaseClass(const Descriptor* desc, const Options& options) {
+ if (!HasDescriptorMethods(desc->file(), options)) return false;
+ if (desc->extension_range_count() != 0) return false;
+ if (desc->field_count() == 0) return true;
+ // TODO(jorg): Support additional common message types with only one
+ // or two fields
+ return false;
+}
+
+inline bool HasSimpleBaseClasses(const FileDescriptor* file,
+ const Options& options) {
+ bool v = false;
+ ForEachMessage(file, [&v, &options](const Descriptor* desc) {
+ v |= HasSimpleBaseClass(desc, options);
+ });
+ return v;
+}
+
+inline TProtoStringType SimpleBaseClass(const Descriptor* desc,
+ const Options& options) {
+ if (!HasDescriptorMethods(desc->file(), options)) return "";
+ if (desc->extension_range_count() != 0) return "";
+ if (desc->field_count() == 0) {
+ return "ZeroFieldsBase";
+ }
+ // TODO(jorg): Support additional common message types with only one
+ // or two fields
+ return "";
+}
+
// 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
@@ -884,8 +934,12 @@ inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; }
PROTOC_EXPORT TProtoStringType StripProto(const TProtoStringType& filename);
-inline bool EnableMessageOwnedArena(const Descriptor* /* desc */ ) { return false; }
+bool EnableMessageOwnedArena(const Descriptor* desc);
+bool ShouldVerify(const Descriptor* descriptor, const Options& options,
+ MessageSCCAnalyzer* scc_analyzer);
+bool ShouldVerify(const FileDescriptor* file, const Options& options,
+ MessageSCCAnalyzer* scc_analyzer);
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc
index cb890d5156..7d1535f3b9 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -43,6 +43,7 @@
#include <utility>
#include <vector>
+#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/cpp/cpp_enum.h>
#include <google/protobuf/compiler/cpp/cpp_extension.h>
#include <google/protobuf/compiler/cpp/cpp_field.h>
@@ -52,6 +53,7 @@
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/map_entry_lite.h>
@@ -181,6 +183,10 @@ bool CanBeManipulatedAsRawBytes(const FieldDescriptor* field,
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
@@ -295,15 +301,6 @@ bool ShouldMarkClassAsFinal(const Descriptor* descriptor,
return false;
}
-bool ShouldMarkClearAsFinal(const Descriptor* descriptor,
- const Options& options) {
- static std::set<TProtoStringType> exclusions{
- };
-
- const TProtoStringType name = ClassName(descriptor, true);
- return exclusions.find(name) == exclusions.end() ||
- options.opensource_runtime;
-}
// Returns true to make the message serialize in order, decided by the following
// factors in the order of precedence.
@@ -397,6 +394,16 @@ bool IsRequired(const std::vector<const FieldDescriptor*>& v) {
return v.front()->is_required();
}
+bool HasSingularString(const Descriptor* desc, const Options& options) {
+ for (const auto* field : FieldRange(desc)) {
+ if (IsString(field, options) && !IsStringInlined(field, options) &&
+ !field->is_repeated() && !field->real_containing_oneof()) {
+ return true;
+ }
+ }
+ return false;
+}
+
// Collects neighboring fields based on a given criteria (equivalent predicate).
template <typename Predicate>
std::vector<std::vector<const FieldDescriptor*>> CollectFields(
@@ -553,6 +560,88 @@ 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"]);
+}
+
+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"},
+ };
+ for (const auto& annotation : accessor_annotations_to_hooks) {
+ (*variables)[annotation.first] = "";
+ }
+ if (!options.field_listener_options.inject_field_listener_events ||
+ descriptor->file()->options().optimize_for() ==
+ google::protobuf::FileOptions::LITE_RUNTIME) {
+ return;
+ }
+ 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 = "_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
// ===================================================================
@@ -567,6 +656,7 @@ MessageGenerator::MessageGenerator(
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) {
@@ -583,36 +673,31 @@ MessageGenerator::MessageGenerator(
variables_["annotate_deserialize"] = "";
variables_["annotate_reflection"] = "";
variables_["annotate_bytesize"] = "";
+ variables_["annotate_mergefrom"] = "";
- if (options.inject_field_listener_events &&
+ if (options.field_listener_options.inject_field_listener_events &&
descriptor->file()->options().optimize_for() !=
google::protobuf::FileOptions::LITE_RUNTIME) {
- const TProtoStringType injector_template = StrCat(
- " {\n"
- " auto _listener_ = ::",
- variables_["proto_ns"],
- "::FieldAccessListener::GetListener();\n"
- " if (_listener_) ");
-
- StrAppend(&variables_["annotate_serialize"], injector_template,
- "_listener_->OnSerializationAccess(this);\n"
- " }\n");
- StrAppend(&variables_["annotate_deserialize"], injector_template,
- " _listener_->OnDeserializationAccess(this);\n"
- " }\n");
+ const TProtoStringType injector_template = " _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.
- StrAppend(&variables_["annotate_reflection"], injector_template,
- "_listener_->OnReflectionAccess(default_instance()"
- ".GetMetadata().descriptor);\n"
- " }\n");
- StrAppend(&variables_["annotate_bytesize"], injector_template,
- "_listener_->OnByteSizeAccess(this);\n"
- " }\n");
+ 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_);
}
+ GenerateExtensionAnnotations(descriptor_, options_, &variables_);
+
SetUnknownFieldsVariable(descriptor_, options_, &variables_);
// Compute optimized field order to be used for layout and initialization
@@ -640,12 +725,22 @@ MessageGenerator::MessageGenerator(
}
has_bit_indices_[field->index()] = max_has_bit_index_++;
}
+ if (IsStringInlined(field, options_)) {
+ if (inlined_string_indices_.empty()) {
+ inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit);
+ }
+ inlined_string_indices_[field->index()] = max_inlined_string_index_++;
+ }
}
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()) {
@@ -656,8 +751,8 @@ MessageGenerator::MessageGenerator(
table_driven_ =
TableDrivenParsingEnabled(descriptor_, options_, scc_analyzer_);
parse_function_generator_.reset(new ParseFunctionGenerator(
- descriptor_, max_has_bit_index_, has_bit_indices_, options_,
- scc_analyzer_, variables_));
+ descriptor_, max_has_bit_index_, has_bit_indices_,
+ inlined_string_indices_, options_, scc_analyzer_, variables_));
}
MessageGenerator::~MessageGenerator() = default;
@@ -666,6 +761,10 @@ size_t MessageGenerator::HasBitsSize() const {
return (max_has_bit_index_ + 31) / 32;
}
+size_t MessageGenerator::InlinedStringDonatedSize() const {
+ return (max_inlined_string_index_ + 31) / 32;
+}
+
int MessageGenerator::HasBitIndex(const FieldDescriptor* field) const {
return has_bit_indices_.empty() ? kNoHasbit
: has_bit_indices_[field->index()];
@@ -690,8 +789,8 @@ void MessageGenerator::AddGenerators(
enum_generators_.push_back(enum_generators->back().get());
}
for (int i = 0; i < descriptor_->extension_count(); i++) {
- extension_generators->emplace_back(
- new ExtensionGenerator(descriptor_->extension(i), options_));
+ extension_generators->emplace_back(new ExtensionGenerator(
+ descriptor_->extension(i), options_, scc_analyzer_));
extension_generators_.push_back(extension_generators->back().get());
}
}
@@ -777,9 +876,206 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) {
}
if (descriptor_->extension_range_count() > 0) {
- // Generate accessors for extensions. We just call a macro located in
- // extension_set.h since the accessors about 80 lines of static code.
- format("$GOOGLE_PROTOBUF$_EXTENSION_ACCESSORS($classname$)\n");
+ // Generate accessors for extensions.
+ // We use "_proto_TypeTraits" as a type name below because "TypeTraits"
+ // causes problems if the class has a nested message or enum type with that
+ // name and "_TypeTraits" is technically reserved for the C++ library since
+ // it starts with an underscore followed by a capital letter.
+ //
+ // 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());
+}
+
+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,
+ ::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,
+ ::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,
+ ::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,
+ ::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,
+ ::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>
+inline PROTOBUF_MUST_USE_RESULT
+ 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,
+ ::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,
+ ::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,
+ ::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,
+ ::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,
+ ::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,
+ ::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,
+ ::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_);
+}
+
+)");
// Generate MessageSet specific APIs for proto2 MessageSet.
// For testing purposes we don't check for bridge.MessageSet, so
// we don't use IsProto2MessageSet
@@ -1145,8 +1441,10 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
} else {
format("inline $classname$() : $classname$(nullptr) {}\n");
}
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ format("~$classname$() override;\n");
+ }
format(
- "~$classname$() override;\n"
"explicit constexpr "
"$classname$(::$proto_ns$::internal::ConstantInitialized);\n"
"\n"
@@ -1162,7 +1460,11 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
"}\n"
"inline $classname$& operator=($classname$&& from) noexcept {\n"
" if (this == &from) return *this;\n"
- " if (GetOwningArena() == from.GetOwningArena()) {\n"
+ " if (GetOwningArena() == from.GetOwningArena()\n"
+ "#ifdef PROTOBUF_FORCE_COPY_IN_MOVE\n"
+ " && GetOwningArena() != nullptr\n"
+ "#endif // !PROTOBUF_FORCE_COPY_IN_MOVE\n"
+ " ) {\n"
" InternalSwap(&from);\n"
" } else {\n"
" CopyFrom(from);\n"
@@ -1174,7 +1476,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
if (options_.table_driven_serialization) {
format(
"private:\n"
- "const void* InternalGetTable() const;\n"
+ "const void* InternalGetTable() const override;\n"
"public:\n"
"\n");
}
@@ -1213,7 +1515,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
" return default_instance().GetMetadata().descriptor;\n"
"}\n"
"static const ::$proto_ns$::Reflection* GetReflection() {\n"
- "$annotate_reflection$"
" return default_instance().GetMetadata().reflection;\n"
"}\n");
}
@@ -1362,22 +1663,36 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
if (HasGeneratedMethods(descriptor_->file(), options_)) {
if (HasDescriptorMethods(descriptor_->file(), options_)) {
- format(
- // Use Message's built-in MergeFrom and CopyFrom when the passed-in
- // argument is a generic Message instance, and only define the custom
- // MergeFrom and CopyFrom instances when the source of the merge/copy
- // is known to be the same class as the destination.
- // TODO(jorg): Define MergeFrom in terms of MergeImpl, rather than the
- // other way around, to save even more code size.
- "using $superclass$::CopyFrom;\n"
- "void CopyFrom(const $classname$& from);\n"
- ""
- "using $superclass$::MergeFrom;\n"
- "void MergeFrom(const $classname$& from);\n"
- "private:\n"
- "static void MergeImpl(::$proto_ns$::Message*to, const "
- "::$proto_ns$::Message&from);\n"
- "public:\n");
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ format(
+ // Use Message's built-in MergeFrom and CopyFrom when the passed-in
+ // argument is a generic Message instance, and only define the
+ // custom MergeFrom and CopyFrom instances when the source of the
+ // merge/copy is known to be the same class as the destination.
+ // TODO(jorg): Define MergeFrom in terms of MergeImpl, rather than
+ // the other way around, to save even more code size.
+ "using $superclass$::CopyFrom;\n"
+ "void CopyFrom(const $classname$& from);\n"
+ ""
+ "using $superclass$::MergeFrom;\n"
+ "void MergeFrom(const $classname$& from);\n"
+ "private:\n"
+ "static void MergeImpl(::$proto_ns$::Message* to, const "
+ "::$proto_ns$::Message& from);\n"
+ "public:\n");
+ } else {
+ format(
+ "using $superclass$::CopyFrom;\n"
+ "inline void CopyFrom(const $classname$& from) {\n"
+ " $superclass$::CopyImpl(this, from);\n"
+ "}\n"
+ ""
+ "using $superclass$::MergeFrom;\n"
+ "void MergeFrom(const $classname$& from) {\n"
+ " $superclass$::MergeImpl(this, from);\n"
+ "}\n"
+ "public:\n");
+ }
} else {
format(
"void CheckTypeAndMergeFrom(const ::$proto_ns$::MessageLite& from)"
@@ -1386,36 +1701,42 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
"void MergeFrom(const $classname$& from);\n");
}
- format.Set("clear_final",
- ShouldMarkClearAsFinal(descriptor_, options_) ? "final" : "");
-
- format(
- "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear()$ clear_final$;\n"
- "bool IsInitialized() const final;\n"
- "\n"
- "size_t ByteSizeLong() const final;\n");
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ format(
+ "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;\n"
+ "bool IsInitialized() const final;\n"
+ "\n"
+ "size_t ByteSizeLong() const final;\n");
- parse_function_generator_->GenerateMethodDecls(printer);
+ parse_function_generator_->GenerateMethodDecls(printer);
- format(
- "$uint8$* _InternalSerialize(\n"
- " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
- "const final;\n");
-
- // DiscardUnknownFields() is implemented in message.cc using reflections. We
- // need to implement this function in generated code for messages.
- if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
- format("void DiscardUnknownFields()$ full_final$;\n");
+ format(
+ "$uint8$* _InternalSerialize(\n"
+ " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) "
+ "const final;\n");
+
+ // DiscardUnknownFields() is implemented in message.cc using reflections.
+ // We need to implement this function in generated code for messages.
+ if (!UseUnknownFieldSet(descriptor_->file(), options_)) {
+ format("void DiscardUnknownFields()$ full_final$;\n");
+ }
}
}
- format(
- "int GetCachedSize() const final { return _cached_size_.Get(); }"
- "\n\nprivate:\n"
- "void SharedCtor();\n"
- "void SharedDtor();\n"
- "void SetCachedSize(int size) const$ full_final$;\n"
- "void InternalSwap($classname$* other);\n");
+ if (options_.field_listener_options.inject_field_listener_events) {
+ format("static constexpr int _kInternalFieldNumber = $1$;\n",
+ descriptor_->field_count());
+ }
+
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ format(
+ "int GetCachedSize() const final { return _cached_size_.Get(); }"
+ "\n\nprivate:\n"
+ "void SharedCtor();\n"
+ "void SharedDtor();\n"
+ "void SetCachedSize(int size) const$ full_final$;\n"
+ "void InternalSwap($classname$* other);\n");
+ }
format(
// Friend AnyMetadata so that it can call this FullMessageName() method.
@@ -1433,9 +1754,13 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
"protected:\n"
"explicit $classname$(::$proto_ns$::Arena* arena,\n"
" bool is_message_owned = false);\n"
- "private:\n"
- "static void ArenaDtor(void* object);\n"
- "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n");
+ "private:\n");
+
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ format(
+ "static void ArenaDtor(void* object);\n"
+ "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n");
+ }
format(
"public:\n"
@@ -1562,6 +1887,21 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
"\n");
}
+ if (options_.field_listener_options.inject_field_listener_events &&
+ descriptor_->file()->options().optimize_for() !=
+ google::protobuf::FileOptions::LITE_RUNTIME) {
+ format("static ::$proto_ns$::AccessListener<$1$> _tracker_;\n",
+ ClassName(descriptor_));
+ }
+
+ // Generate _inlined_string_donated_ for inlined string type.
+ // TODO(congliu): To avoid affecting the locality of `_has_bits_`, should this
+ // be below or above `_has_bits_`?
+ if (!inlined_string_indices_.empty()) {
+ format("::$proto_ns$::internal::HasBits<$1$> _inlined_string_donated_;\n",
+ InlinedStringDonatedSize());
+ }
+
format(
"template <typename T> friend class "
"::$proto_ns$::Arena::InternalHelper;\n"
@@ -1731,8 +2071,17 @@ void MessageGenerator::GenerateSchema(io::Printer* printer, int offset,
has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)
? offset + has_offset
: -1;
+ int inlined_string_indices_offset;
+ if (inlined_string_indices_.empty()) {
+ inlined_string_indices_offset = -1;
+ } else {
+ GOOGLE_DCHECK_NE(has_offset, -1);
+ GOOGLE_DCHECK(!IsMapEntryMessage(descriptor_));
+ inlined_string_indices_offset = has_offset + has_bit_indices_.size();
+ }
- format("{ $1$, $2$, sizeof($classtype$)},\n", offset, has_offset);
+ format("{ $1$, $2$, $3$, sizeof($classtype$)},\n", offset, has_offset,
+ inlined_string_indices_offset);
}
namespace {
@@ -1746,7 +2095,9 @@ uint32_t CalcFieldNum(const FieldGenerator& generator,
if (type == FieldDescriptor::TYPE_STRING ||
type == FieldDescriptor::TYPE_BYTES) {
// string field
- if (IsCord(field, options)) {
+ if (generator.IsInlined()) {
+ type = internal::FieldMetadata::kInlinedType;
+ } else if (IsCord(field, options)) {
type = internal::FieldMetadata::kCordType;
} else if (IsStringPiece(field, options)) {
type = internal::FieldMetadata::kStringPieceType;
@@ -1956,13 +2307,24 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
" MergeFromInternal(other);\n"
"}\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
- format(
- "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
- " return ::$proto_ns$::internal::AssignDescriptors(\n"
- " &$desc_table$_getter, &$desc_table$_once,\n"
- " $file_level_metadata$[$1$]);\n"
- "}\n",
- index_in_file_messages_);
+ if (!descriptor_->options().map_entry()) {
+ format(
+ "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+ "$annotate_reflection$"
+ " return ::$proto_ns$::internal::AssignDescriptors(\n"
+ " &$desc_table$_getter, &$desc_table$_once,\n"
+ " $file_level_metadata$[$1$]);\n"
+ "}\n",
+ index_in_file_messages_);
+ } else {
+ format(
+ "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+ " return ::$proto_ns$::internal::AssignDescriptors(\n"
+ " &$desc_table$_getter, &$desc_table$_once,\n"
+ " $file_level_metadata$[$1$]);\n"
+ "}\n",
+ index_in_file_messages_);
+ }
}
return;
}
@@ -2059,10 +2421,12 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
GenerateClear(printer);
format("\n");
- parse_function_generator_->GenerateMethodImpls(printer);
- format("\n");
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ parse_function_generator_->GenerateMethodImpls(printer);
+ format("\n");
- parse_function_generator_->GenerateDataDefinitions(printer);
+ parse_function_generator_->GenerateDataDefinitions(printer);
+ }
GenerateSerializeWithCachedSizesToArray(printer);
format("\n");
@@ -2083,6 +2447,8 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
format("\n");
}
+ GenerateVerify(printer);
+
GenerateSwap(printer);
format("\n");
@@ -2095,13 +2461,24 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
index_in_file_messages_);
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
- format(
- "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
- " return ::$proto_ns$::internal::AssignDescriptors(\n"
- " &$desc_table$_getter, &$desc_table$_once,\n"
- " $file_level_metadata$[$1$]);\n"
- "}\n",
- index_in_file_messages_);
+ if (!descriptor_->options().map_entry()) {
+ format(
+ "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+ "$annotate_reflection$"
+ " return ::$proto_ns$::internal::AssignDescriptors(\n"
+ " &$desc_table$_getter, &$desc_table$_once,\n"
+ " $file_level_metadata$[$1$]);\n"
+ "}\n",
+ index_in_file_messages_);
+ } else {
+ format(
+ "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
+ " return ::$proto_ns$::internal::AssignDescriptors(\n"
+ " &$desc_table$_getter, &$desc_table$_once,\n"
+ " $file_level_metadata$[$1$]);\n"
+ "}\n",
+ index_in_file_messages_);
+ }
} else {
format(
"TProtoStringType $classname$::GetTypeName() const {\n"
@@ -2110,6 +2487,14 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
"\n");
}
+ if (options_.field_listener_options.inject_field_listener_events &&
+ descriptor_->file()->options().optimize_for() !=
+ google::protobuf::FileOptions::LITE_RUNTIME) {
+ format(
+ "::$proto_ns$::AccessListener<$classtype$> "
+ "$1$::_tracker_(&FullMessageName);\n",
+ ClassName(descriptor_));
+ }
}
size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
@@ -2148,9 +2533,13 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
}
processing_type = static_cast<unsigned>(field->type());
+ const FieldGenerator& generator = field_generators_.get(field);
if (field->type() == FieldDescriptor::TYPE_STRING) {
switch (EffectiveStringCType(field, options_)) {
case FieldOptions::STRING:
+ if (generator.IsInlined()) {
+ processing_type = internal::TYPE_STRING_INLINED;
+ }
break;
case FieldOptions::CORD:
processing_type = internal::TYPE_STRING_CORD;
@@ -2162,6 +2551,9 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
} else if (field->type() == FieldDescriptor::TYPE_BYTES) {
switch (EffectiveStringCType(field, options_)) {
case FieldOptions::STRING:
+ if (generator.IsInlined()) {
+ processing_type = internal::TYPE_BYTES_INLINED;
+ }
break;
case FieldOptions::CORD:
processing_type = internal::TYPE_BYTES_CORD;
@@ -2326,7 +2718,12 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
} else {
format("~0u, // no _weak_field_map_\n");
}
- const int kNumGenericOffsets = 5; // the number of fixed offsets above
+ if (!inlined_string_indices_.empty()) {
+ format("PROTOBUF_FIELD_OFFSET($classtype$, _inlined_string_donated_),\n");
+ } else {
+ format("~0u, // no _inlined_string_donated_\n");
+ }
+ const int kNumGenericOffsets = 6; // the number of fixed offsets above
const size_t offsets = kNumGenericOffsets + descriptor_->field_count() +
descriptor_->real_oneof_decl_count();
size_t entries = offsets;
@@ -2345,10 +2742,18 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_)", FieldName(field));
}
+ // Some information about a field is in the pdproto profile. The profile is
+ // only available at compile time. So we embed such information in the
+ // offset of the field, so that the information is available when reflective
+ // accessing the field at run time.
+ //
+ // Embed whether the field is used to the MSB of the offset.
if (!IsFieldUsed(field, options_)) {
format(" | 0x80000000u, // unused\n");
} else if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) {
format(" | 0x1u, // eagerly verified lazy\n");
+ } else if (IsStringInlined(field, options_)) {
+ format(" | 0x1u, // inlined\n");
} else {
format(",\n");
}
@@ -2374,11 +2779,21 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
format("$1$,\n", index);
}
}
+ if (!inlined_string_indices_.empty()) {
+ entries += inlined_string_indices_.size();
+ for (int inlined_string_indice : inlined_string_indices_) {
+ const TProtoStringType index = inlined_string_indice >= 0
+ ? StrCat(inlined_string_indice)
+ : "~0u";
+ format("$1$,\n", index);
+ }
+ }
return std::make_pair(entries, offsets);
}
void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
format("void $classname$::SharedCtor() {\n");
@@ -2394,6 +2809,7 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) {
}
void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
format("inline void $classname$::SharedDtor() {\n");
@@ -2424,6 +2840,7 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) {
}
void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
// Generate the ArenaDtor() method. Track whether any fields actually produced
@@ -2593,7 +3010,8 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
bool has_arena_constructor = field->is_repeated();
if (!field->real_containing_oneof() &&
(IsLazy(field, options_, scc_analyzer_) ||
- IsStringPiece(field, options_))) {
+ IsStringPiece(field, options_) ||
+ (IsString(field, options_) && IsStringInlined(field, options_)))) {
has_arena_constructor = true;
}
if (has_arena_constructor) {
@@ -2620,15 +3038,29 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
format(
"$classname$::$classname$(::$proto_ns$::Arena* arena,\n"
" bool is_message_owned)\n"
- " : $1$ {\n"
- " SharedCtor();\n"
- " if (!is_message_owned) {\n"
- " RegisterArenaDtor(arena);\n"
- " }\n"
- " // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
- "}\n",
+ " : $1$ {\n",
initializer_with_arena);
+ if (!inlined_string_indices_.empty()) {
+ // Donate inline string fields.
+ format(" if (arena != nullptr) {\n");
+ for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) {
+ format(" _inlined_string_donated_[$1$] = ~0u;\n", i);
+ }
+ format(" }\n");
+ }
+
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ format(
+ " SharedCtor();\n"
+ " if (!is_message_owned) {\n"
+ " RegisterArenaDtor(arena);\n"
+ " }\n");
+ }
+ format(
+ " // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
+ "}\n");
+
std::map<TProtoStringType, TProtoStringType> vars;
SetUnknownFieldsVariable(descriptor_, options_, &vars);
format.AddMap(vars);
@@ -2652,6 +3084,9 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
format.Indent();
format.Indent();
+ // Do not copy inlined_string_donated_, because this is not an arena
+ // constructor.
+
if (!has_bit_indices_.empty()) {
format(",\n_has_bits_(from._has_bits_)");
}
@@ -2726,14 +3161,22 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
GenerateSharedConstructorCode(printer);
// Generate the destructor.
- format(
- "$classname$::~$classname$() {\n"
- " // @@protoc_insertion_point(destructor:$full_name$)\n"
- " if (GetArenaForAllocation() != nullptr) return;\n"
- " SharedDtor();\n"
- " _internal_metadata_.Delete<$unknown_fields_type$>();\n"
- "}\n"
- "\n");
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ format(
+ "$classname$::~$classname$() {\n"
+ " // @@protoc_insertion_point(destructor:$full_name$)\n"
+ " if (GetArenaForAllocation() != nullptr) return;\n"
+ " SharedDtor();\n"
+ " _internal_metadata_.Delete<$unknown_fields_type$>();\n"
+ "}\n"
+ "\n");
+ } else {
+ // For messages using simple base classes, having no destructor
+ // allows our vtable to share the same destructor as every other
+ // message with a simple base class. This works only as long as
+ // we have no fields needing destruction, of course. (No strings
+ // or extensions)
+ }
// Generate the shared destructor code.
GenerateSharedDestructorCode(printer);
@@ -2741,11 +3184,13 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
// Generate the arena-specific destructor code.
GenerateArenaDestructorCode(printer);
- // Generate SetCachedSize.
- format(
- "void $classname$::SetCachedSize(int size) const {\n"
- " _cached_size_.Set(size);\n"
- "}\n");
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ // Generate SetCachedSize.
+ format(
+ "void $classname$::SetCachedSize(int size) const {\n"
+ " _cached_size_.Set(size);\n"
+ "}\n");
+ }
}
void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) {
@@ -2759,6 +3204,7 @@ void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) {
}
void MessageGenerator::GenerateClear(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
// The maximum number of bytes we will memset to zero without checking their
@@ -2916,6 +3362,8 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
format("_weak_field_map_.ClearAll();\n");
}
+ // We don't clear donated status.
+
if (!has_bit_indices_.empty()) {
// Step 5: Everything else.
format("_has_bits_.Clear();\n");
@@ -2975,6 +3423,7 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) {
}
void MessageGenerator::GenerateSwap(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
format("void $classname$::InternalSwap($classname$* other) {\n");
@@ -2989,6 +3438,11 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) {
std::map<TProtoStringType, TProtoStringType> vars;
SetUnknownFieldsVariable(descriptor_, options_, &vars);
format.AddMap(vars);
+ if (HasSingularString(descriptor_, options_)) {
+ format(
+ "auto* lhs_arena = GetArenaForAllocation();\n"
+ "auto* rhs_arena = other->GetArenaForAllocation();\n");
+ }
format("_internal_metadata_.InternalSwap(&other->_internal_metadata_);\n");
if (!has_bit_indices_.empty()) {
@@ -3056,47 +3510,64 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) {
void MessageGenerator::GenerateMergeFrom(io::Printer* printer) {
Formatter format(printer, variables_);
- if (HasDescriptorMethods(descriptor_->file(), options_)) {
- // We don't override the generalized MergeFrom (aka that which
- // takes in the Message base class as a parameter); instead we just
- // let the base Message::MergeFrom take care of it. The base MergeFrom
- // knows how to quickly confirm the types exactly match, and if so, will
- // use GetClassData() to retrieve the address of MergeImpl, which calls
- // the fast MergeFrom overload. Most callers avoid all this by passing
- // a "from" message that is the same type as the message being merged
- // into, rather than a generic Message.
+ if (!HasSimpleBaseClass(descriptor_, options_)) {
+ if (HasDescriptorMethods(descriptor_->file(), options_)) {
+ // We don't override the generalized MergeFrom (aka that which
+ // takes in the Message base class as a parameter); instead we just
+ // let the base Message::MergeFrom take care of it. The base MergeFrom
+ // knows how to quickly confirm the types exactly match, and if so, will
+ // use GetClassData() to retrieve the address of MergeImpl, which calls
+ // the fast MergeFrom overload. Most callers avoid all this by passing
+ // a "from" message that is the same type as the message being merged
+ // into, rather than a generic Message.
+ format(
+ "const ::$proto_ns$::Message::ClassData "
+ "$classname$::_class_data_ = {\n"
+ " ::$proto_ns$::Message::CopyWithSizeCheck,\n"
+ " $classname$::MergeImpl\n"
+ "};\n"
+ "const ::$proto_ns$::Message::ClassData*"
+ "$classname$::GetClassData() const { return &_class_data_; }\n"
+ "\n"
+ "void $classname$::MergeImpl(::$proto_ns$::Message* to,\n"
+ " const ::$proto_ns$::Message& from) {\n"
+ " static_cast<$classname$ *>(to)->MergeFrom(\n"
+ " static_cast<const $classname$ &>(from));\n"
+ "}\n"
+ "\n");
+ } else {
+ // Generate CheckTypeAndMergeFrom().
+ format(
+ "void $classname$::CheckTypeAndMergeFrom(\n"
+ " const ::$proto_ns$::MessageLite& from) {\n"
+ " MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n"
+ " &from));\n"
+ "}\n");
+ }
+ } else {
+ // In the simple case, we just define ClassData that vectors back to the
+ // simple implementation of Copy and Merge.
format(
"const ::$proto_ns$::Message::ClassData "
"$classname$::_class_data_ = {\n"
- " ::$proto_ns$::Message::CopyWithSizeCheck,\n"
- " $classname$::MergeImpl\n"
+ " $superclass$::CopyImpl,\n"
+ " $superclass$::MergeImpl,\n"
"};\n"
"const ::$proto_ns$::Message::ClassData*"
"$classname$::GetClassData() const { return &_class_data_; }\n"
"\n"
- "void $classname$::MergeImpl(::$proto_ns$::Message*to,\n"
- " const ::$proto_ns$::Message&from) {\n"
- " static_cast<$classname$ *>(to)->MergeFrom(\n"
- " static_cast<const $classname$ &>(from));\n"
- "}\n"
"\n");
- } else {
- // Generate CheckTypeAndMergeFrom().
- format(
- "void $classname$::CheckTypeAndMergeFrom(\n"
- " const ::$proto_ns$::MessageLite& from) {\n"
- " MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n"
- " &from));\n"
- "}\n");
}
}
void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
// Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
Formatter format(printer, variables_);
format(
"void $classname$::MergeFrom(const $classname$& from) {\n"
+ "$annotate_mergefrom$"
"// @@protoc_insertion_point(class_specific_merge_from_start:"
"$full_name$)\n"
" $DCHK$_NE(&from, this);\n");
@@ -3255,6 +3726,7 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) {
}
void MessageGenerator::GenerateCopyFrom(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
if (HasDescriptorMethods(descriptor_->file(), options_)) {
// We don't override the generalized CopyFrom (aka that which
@@ -3301,6 +3773,9 @@ void MessageGenerator::GenerateCopyFrom(io::Printer* printer) {
format("}\n");
}
+void MessageGenerator::GenerateVerify(io::Printer* printer) {
+}
+
void MessageGenerator::GenerateSerializeOneofFields(
io::Printer* printer, const std::vector<const FieldDescriptor*>& fields) {
Formatter format(printer, variables_);
@@ -3376,11 +3851,12 @@ void MessageGenerator::GenerateSerializeOneExtensionRange(
format("// Extension range [$start$, $end$)\n");
format(
"target = _extensions_._InternalSerialize(\n"
- " $start$, $end$, target, stream);\n\n");
+ "internal_default_instance(), $start$, $end$, target, stream);\n\n");
}
void MessageGenerator::GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
@@ -3390,7 +3866,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray(
"const {\n"
"$annotate_serialize$"
" target = _extensions_."
- "InternalSerializeMessageSetWithCachedSizesToArray(target, stream);\n");
+ "InternalSerializeMessageSetWithCachedSizesToArray(\n" //
+ "internal_default_instance(), target, stream);\n");
std::map<TProtoStringType, TProtoStringType> vars;
SetUnknownFieldsVariable(descriptor_, options_, &vars);
format.AddMap(vars);
@@ -3443,6 +3920,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray(
void MessageGenerator::GenerateSerializeWithCachedSizesBody(
io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
// 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
@@ -3759,6 +4237,7 @@ std::vector<uint32_t> MessageGenerator::RequiredFieldsBitMask() const {
}
void MessageGenerator::GenerateByteSize(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
if (descriptor_->options().message_set_wire_format()) {
@@ -3987,37 +4466,37 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) {
format("total_size += _weak_field_map_.ByteSizeLong();\n");
}
- format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
if (UseUnknownFieldSet(descriptor_->file(), options_)) {
// We go out of our way to put the computation of the uncommon path of
// unknown fields in tail position. This allows for better code generation
// of this function for simple protos.
format(
- " return ::$proto_ns$::internal::ComputeUnknownFieldsSize(\n"
- " _internal_metadata_, total_size, &_cached_size_);\n");
+ "return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);\n");
} else {
+ format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n");
format(" total_size += $unknown_fields$.size();\n");
- }
- format("}\n");
+ format("}\n");
- // We update _cached_size_ even though this is a const method. Because
- // const methods might be called concurrently this needs to be atomic
- // operations or the program is undefined. In practice, since any concurrent
- // writes will be writing the exact same value, normal writes will work on
- // all common processors. We use a dedicated wrapper class to abstract away
- // the underlying atomic. This makes it easier on platforms where even relaxed
- // memory order might have perf impact to replace it with ordinary loads and
- // stores.
- format(
- "int cached_size = ::$proto_ns$::internal::ToCachedSize(total_size);\n"
- "SetCachedSize(cached_size);\n"
- "return total_size;\n");
+ // We update _cached_size_ even though this is a const method. Because
+ // const methods might be called concurrently this needs to be atomic
+ // operations or the program is undefined. In practice, since any
+ // concurrent writes will be writing the exact same value, normal writes
+ // will work on all common processors. We use a dedicated wrapper class to
+ // abstract away the underlying atomic. This makes it easier on platforms
+ // where even relaxed memory order might have perf impact to replace it with
+ // ordinary loads and stores.
+ format(
+ "int cached_size = ::$proto_ns$::internal::ToCachedSize(total_size);\n"
+ "SetCachedSize(cached_size);\n"
+ "return total_size;\n");
+ }
format.Outdent();
format("}\n");
}
void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
+ if (HasSimpleBaseClass(descriptor_, options_)) return;
Formatter format(printer, variables_);
format("bool $classname$::IsInitialized() const {\n");
format.Indent();
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h
index 904a98acfe..1e4e942d69 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -134,6 +134,7 @@ class MessageGenerator {
// 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);
@@ -177,6 +178,7 @@ class MessageGenerator {
bool copy_constructor) const;
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;
@@ -196,6 +198,13 @@ class MessageGenerator {
std::vector<const FieldDescriptor*> optimized_order_;
std::vector<int> has_bit_indices_;
int max_has_bit_index_;
+
+ // A map from field index to inlined_string index. For non-inlined-string
+ // fields, the element is -1.
+ std::vector<int> inlined_string_indices_;
+ // The count of inlined_string fields in the message.
+ int max_inlined_string_index_;
+
std::vector<const EnumGenerator*> enum_generators_;
std::vector<const ExtensionGenerator*> extension_generators_;
int num_required_fields_;
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h
index 4b4b8ea59b..712ddbfea1 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -53,22 +53,25 @@ class MessageFieldGenerator : public FieldGenerator {
~MessageFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GeneratePrivateMembers(io::Printer* printer) const;
- void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateInternalAccessorDeclarations(io::Printer* printer) const;
- void GenerateInternalAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateMessageClearingCode(io::Printer* printer) const;
- void GenerateMergingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateDestructorCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
- void GenerateCopyConstructorCode(io::Printer* printer) const;
- void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
- void GenerateByteSize(io::Printer* printer) const;
- void GenerateConstinitInitializer(io::Printer* printer) const;
+ 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 GenerateConstinitInitializer(io::Printer* printer) const override;
protected:
const bool implicit_weak_field_;
@@ -85,16 +88,17 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
~MessageOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
+ 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;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateDestructorCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
+ 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;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
@@ -108,17 +112,18 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
~RepeatedMessageFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GeneratePrivateMembers(io::Printer* printer) const;
- void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateMergingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
- void GenerateCopyConstructorCode(io::Printer* printer) const {}
- void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
- void GenerateByteSize(io::Printer* printer) const;
- void GenerateConstinitInitializer(io::Printer* printer) const;
+ 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 GenerateConstinitInitializer(io::Printer* printer) const override;
private:
const bool implicit_weak_field_;
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h
index ed5cd0b046..bc174c3d6e 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -33,6 +33,7 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
+#include <set>
#include <string>
#include <google/protobuf/stubs/port.h>
@@ -50,6 +51,11 @@ enum class EnforceOptimizeMode {
kLiteRuntime,
};
+struct FieldListenerOptions {
+ bool inject_field_listener_events = false;
+ std::set<TProtoStringType> forbidden_field_listener_events;
+};
+
// Generator options (see generator.cc for a description of each):
struct Options {
TProtoStringType dllexport_decl;
@@ -65,6 +71,8 @@ struct Options {
bool opensource_runtime = false;
bool annotate_accessor = false;
bool unused_field_stripping = false;
+ bool profile_driven_inline_string = false;
+ bool force_inline_string = false;
TProtoStringType runtime_include_base;
int num_cc_files = 0;
TProtoStringType annotation_pragma_name;
@@ -75,7 +83,7 @@ struct Options {
kTCTableGuarded,
kTCTableAlways
} tctable_mode = kTCTableNever;
- bool inject_field_listener_events = false;
+ FieldListenerOptions field_listener_options;
bool eagerly_verified_lazy = false;
bool force_eagerly_verified_lazy = false;
};
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
index ea146f8992..93d44864c3 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc
@@ -30,7 +30,9 @@
#include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h>
+#include <algorithm>
#include <limits>
+#include <string>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/wire_format.h>
@@ -64,16 +66,6 @@ bool HasInternalAccessors(const FieldOptions::CType ctype) {
return ctype == FieldOptions::STRING || ctype == FieldOptions::CORD;
}
-bool IsTcTableEnabled(const Options& options) {
- return options.tctable_mode == Options::kTCTableAlways;
-}
-bool IsTcTableGuarded(const Options& options) {
- return options.tctable_mode == Options::kTCTableGuarded;
-}
-bool IsTcTableDisabled(const Options& options) {
- return options.tctable_mode == Options::kTCTableNever;
-}
-
int TagSize(uint32_t field_number) {
if (field_number < 16) return 1;
GOOGLE_CHECK_LT(field_number, (1 << 14))
@@ -81,22 +73,38 @@ int TagSize(uint32_t field_number) {
return 2;
}
+const char* CodedTagType(int tag_size) {
+ return tag_size == 1 ? "uint8_t" : "uint16_t";
+}
+
const char* TagType(const FieldDescriptor* field) {
return CodedTagType(TagSize(field->number()));
}
-TProtoStringType MessageParseFunctionName(const FieldDescriptor* field,
- const Options& options) {
- TProtoStringType name =
- "::" + ProtobufNamespace(options) + "::internal::TcParserBase::";
- if (field->is_repeated()) {
- name.append("Repeated");
- } else {
- name.append("Singular");
+TProtoStringType TcParserBaseName(const Options& options) {
+ return StrCat("::", ProtobufNamespace(options),
+ "::internal::TcParserBase::");
+}
+
+TProtoStringType MessageTcParseFunctionName(const FieldDescriptor* field,
+ const Options& options) {
+ if (field->message_type()->field_count() == 0 ||
+ !HasGeneratedMethods(field->message_type()->file(), options)) {
+ // For files with `option optimize_for = CODE_SIZE`, or which derive from
+ // `ZeroFieldsBase`, we need to call the `_InternalParse` function, because
+ // there is no generated tailcall function. For tailcall parsing, this is
+ // done by helpers in TcParserBase.
+ return StrCat(TcParserBaseName(options),
+ (field->is_repeated() ? "Repeated" : "Singular"),
+ "ParseMessage<",
+ QualifiedClassName(field->message_type()), //
+ ", ", TagType(field), ">");
}
- name.append("ParseMessage<" + QualifiedClassName(field->message_type()) +
- ", " + TagType(field) + ">");
- return name;
+ // This matches macros in generated_message_tctable_impl.h:
+ return StrCat("PROTOBUF_TC_PARSE_",
+ (field->is_repeated() ? "REPEATED" : "SINGULAR"),
+ TagSize(field->number()), "(",
+ QualifiedClassName(field->message_type()), ")");
}
TProtoStringType FieldParseFunctionName(const FieldDescriptor* field,
@@ -105,10 +113,6 @@ TProtoStringType FieldParseFunctionName(const FieldDescriptor* field,
} // namespace
-const char* CodedTagType(int tag_size) {
- return tag_size == 1 ? "uint8_t" : "uint16_t";
-}
-
TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
const Options& options,
const std::vector<int>& has_bit_indices,
@@ -139,9 +143,9 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
// Anything difficult slow path:
if (field->is_map()) continue;
if (field->real_containing_oneof()) continue;
- if (field->options().lazy()) continue;
if (field->options().weak()) continue;
if (IsImplicitWeakField(field, options, scc_analyzer)) continue;
+ if (IsLazy(field, options, scc_analyzer)) continue;
// 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:
@@ -189,7 +193,7 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
switch (field->type()) {
case FieldDescriptor::TYPE_MESSAGE:
- name = MessageParseFunctionName(field, options);
+ name = MessageTcParseFunctionName(field, options);
break;
case FieldDescriptor::TYPE_FIXED64:
@@ -210,7 +214,8 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
case FieldDescriptor::TYPE_BYTES:
if (field->options().ctype() == FieldOptions::STRING &&
- field->default_value_string().empty()) {
+ field->default_value_string().empty() &&
+ !IsStringInlined(field, options)) {
name = FieldParseFunctionName(field, options, table_size_log2);
}
break;
@@ -230,16 +235,6 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
fast_path_fields[idx].field = field;
}
- // Construct a mask of has-bits for required fields numbered <= 32.
- has_hasbits_required_mask = 0;
- for (auto field : FieldRange(descriptor)) {
- if (field->is_required()) {
- int idx = has_bit_indices[field->index()];
- if (idx >= 32) continue;
- has_hasbits_required_mask |= 1u << idx;
- }
- }
-
// 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.
@@ -249,15 +244,17 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor,
ParseFunctionGenerator::ParseFunctionGenerator(
const Descriptor* descriptor, int max_has_bit_index,
- const std::vector<int>& has_bit_indices, const Options& options,
+ 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)
: descriptor_(descriptor),
scc_analyzer_(scc_analyzer),
options_(options),
variables_(vars),
+ inlined_string_indices_(inlined_string_indices),
num_hasbits_(max_has_bit_index) {
- if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
+ if (should_generate_tctable()) {
tc_table_info_.reset(new TailCallTableInfo(descriptor_, options_,
has_bit_indices, scc_analyzer));
}
@@ -268,28 +265,46 @@ ParseFunctionGenerator::ParseFunctionGenerator(
void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) {
Formatter format(printer, variables_);
- if (IsTcTableGuarded(options_)) {
- format.Outdent();
- format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
- format.Indent();
- }
- if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
+ if (should_generate_tctable()) {
+ auto declare_function = [&format](const char* name,
+ const TProtoStringType& guard) {
+ if (!guard.empty()) {
+ format.Outdent();
+ format("#if $1$\n", guard);
+ format.Indent();
+ }
+ format("static const char* $1$(PROTOBUF_TC_PARAM_DECL);\n", name);
+ if (!guard.empty()) {
+ format.Outdent();
+ format("#endif // $1$\n", guard);
+ format.Indent();
+ }
+ };
+ if (should_generate_guarded_tctable()) {
+ format.Outdent();
+ format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
+ format.Indent();
+ }
+ format("// The Tct_* functions are internal to the protobuf runtime:\n");
+ // These guards are defined in port_def.inc:
+ declare_function("Tct_ParseS1", "PROTOBUF_TC_STATIC_PARSE_SINGULAR1");
+ declare_function("Tct_ParseS2", "PROTOBUF_TC_STATIC_PARSE_SINGULAR2");
+ declare_function("Tct_ParseR1", "PROTOBUF_TC_STATIC_PARSE_REPEATED1");
+ declare_function("Tct_ParseR2", "PROTOBUF_TC_STATIC_PARSE_REPEATED2");
if (tc_table_info_->use_generated_fallback) {
+ format.Outdent();
format(
- "static const char* Tct_ParseFallback(\n"
- " ::$proto_ns$::MessageLite *msg, const char *ptr,\n"
- " ::$proto_ns$::internal::ParseContext *ctx,\n"
- " const ::$proto_ns$::internal::TailCallParseTableBase *table,\n"
- " uint64_t hasbits, ::$proto_ns$::internal::TcFieldData data);\n"
- "inline const char* Tct_FallbackImpl(\n"
- " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx,\n"
- " const void*, $uint64$ hasbits);\n");
+ " private:\n"
+ " ");
+ declare_function("Tct_ParseFallback", "");
+ format(" public:\n");
+ format.Indent();
+ }
+ if (should_generate_guarded_tctable()) {
+ format.Outdent();
+ format("#endif\n");
+ format.Indent();
}
- }
- if (IsTcTableGuarded(options_)) {
- format.Outdent();
- format("#endif\n");
- format.Indent();
}
format(
"const char* _InternalParse(const char* ptr, "
@@ -298,8 +313,10 @@ void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) {
void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) {
Formatter format(printer, variables_);
+ bool need_parse_function = true;
if (descriptor_->options().message_set_wire_format()) {
// Special-case MessageSet.
+ need_parse_function = false;
format(
"const char* $classname$::_InternalParse(const char* ptr,\n"
" ::$proto_ns$::internal::ParseContext* ctx) {\n"
@@ -307,85 +324,157 @@ void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) {
" return _extensions_.ParseMessageSet(ptr, \n"
" internal_default_instance(), &_internal_metadata_, ctx);\n"
"}\n");
+ }
+ if (!should_generate_tctable()) {
+ if (need_parse_function) {
+ GenerateLoopingParseFunction(format);
+ }
return;
}
- if (IsTcTableGuarded(options_)) {
+ if (should_generate_guarded_tctable()) {
format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
}
- if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
- format(
- "const char* $classname$::_InternalParse(\n"
- " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n"
- " return ::$proto_ns$::internal::TcParser<$1$>::ParseLoop(\n"
- " this, ptr, ctx, &_table_.header);\n"
- "}\n"
- "\n",
- tc_table_info_->table_size_log2);
- if (tc_table_info_->use_generated_fallback) {
- GenerateTailcallFallbackFunction(format);
- }
- }
- if (IsTcTableGuarded(options_)) {
- format("\n#else // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
+ if (need_parse_function) {
+ GenerateTailcallParseFunction(format);
}
- if (IsTcTableGuarded(options_) || IsTcTableDisabled(options_)) {
- GenerateLoopingParseFunction(format);
+ if (tc_table_info_->use_generated_fallback) {
+ GenerateTailcallFallbackFunction(format);
}
- if (IsTcTableGuarded(options_)) {
+ GenerateTailcallFieldParseFunctions(format);
+ if (should_generate_guarded_tctable()) {
+ if (need_parse_function) {
+ format("\n#else // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
+ GenerateLoopingParseFunction(format);
+ }
format("\n#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
}
}
-void ParseFunctionGenerator::GenerateTailcallFallbackFunction(
- Formatter& format) {
+bool ParseFunctionGenerator::should_generate_tctable() const {
+ if (options_.tctable_mode == Options::kTCTableNever) {
+ return false;
+ }
+ return true;
+}
+
+void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) {
+ GOOGLE_CHECK(should_generate_tctable());
+
+ // Generate an `_InternalParse` that starts the tail-calling loop.
format(
- "const char* $classname$::Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL) {\n"
- " return static_cast<$classname$*>(msg)->Tct_FallbackImpl(ptr, ctx, "
- "table, hasbits);\n"
+ "const char* $classname$::_InternalParse(\n"
+ " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n"
+ "$annotate_deserialize$"
+ " ptr = ::$proto_ns$::internal::TcParser<$1$>::ParseLoop(\n"
+ " this, ptr, ctx, &_table_.header);\n",
+ tc_table_info_->table_size_log2);
+ format(
+ " return ptr;\n"
"}\n\n");
+}
+void ParseFunctionGenerator::GenerateTailcallFallbackFunction(
+ Formatter& format) {
+ GOOGLE_CHECK(should_generate_tctable());
format(
- "const char* $classname$::Tct_FallbackImpl(const char* ptr, "
- "::$proto_ns$::internal::ParseContext* ctx, const void*, "
- "$uint64$ hasbits) {\n"
+ "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 (num_hasbits_ > 0) {
// Sync hasbits
- format("_has_bits_[0] = hasbits;\n");
+ format("typed_msg->_has_bits_[0] = hasbits;\n");
}
- format.Set("has_bits", "_has_bits_");
- format.Set("continue", "goto success");
+ format.Set("msg", "typed_msg->");
+ format.Set("this", "typed_msg");
+ format.Set("has_bits", "typed_msg->_has_bits_");
+ format.Set("next_tag", "goto next_tag");
GenerateParseIterationBody(format, descriptor_,
tc_table_info_->fallback_fields);
format.Outdent();
- format("success:\n");
- format(" return ptr;\n");
format(
+ "next_tag:\n"
+ "message_done:\n"
+ " return ptr;\n"
"#undef CHK_\n"
"}\n");
}
+void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions(
+ Formatter& format) {
+ GOOGLE_CHECK(should_generate_tctable());
+ // There are four cases where a tailcall target are needed for messages:
+ // {singular, repeated} x {1, 2}-byte tag
+ struct {
+ const char* type;
+ int size;
+ } const kTagLayouts[] = {
+ {"uint8_t", 1},
+ {"uint16_t", 2},
+ };
+ // Singular:
+ for (const auto& layout : kTagLayouts) {
+ // Guard macros are defined in port_def.inc.
+ format(
+ "#if PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n"
+ "const char* $classname$::Tct_ParseS$1$(PROTOBUF_TC_PARAM_DECL) {\n"
+ " if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0))\n"
+ " PROTOBUF_MUSTTAIL "
+ "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
+ " ptr += $1$;\n"
+ " hasbits |= (uint64_t{1} << data.hasbit_idx());\n"
+ " ::$proto_ns$::internal::TcParserBase::SyncHasbits"
+ "(msg, hasbits, table);\n"
+ " auto& field = ::$proto_ns$::internal::TcParserBase::"
+ "RefAt<$classtype$*>(msg, data.offset());\n"
+ " if (field == nullptr)\n"
+ " field = CreateMaybeMessage<$classtype$>(ctx->data().arena);\n"
+ " return ctx->ParseMessage(field, ptr);\n"
+ "}\n"
+ "#endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n",
+ layout.size, layout.type);
+ }
+ // Repeated:
+ for (const auto& layout : kTagLayouts) {
+ // Guard macros are defined in port_def.inc.
+ format(
+ "#if PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n"
+ "const char* $classname$::Tct_ParseR$1$(PROTOBUF_TC_PARAM_DECL) {\n"
+ " if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0)) {\n"
+ " PROTOBUF_MUSTTAIL "
+ "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
+ " }\n"
+ " ptr += $1$;\n"
+ " auto& field = ::$proto_ns$::internal::TcParserBase::RefAt<"
+ "::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n"
+ " ::$proto_ns$::internal::TcParserBase::SyncHasbits"
+ "(msg, hasbits, table);\n"
+ " ptr = ctx->ParseMessage(field.Add(), ptr);\n"
+ " return ptr;\n"
+ "}\n"
+ "#endif // PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n",
+ layout.size, layout.type);
+ }
+}
+
void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) {
- if (descriptor_->options().message_set_wire_format()) {
+ if (!should_generate_tctable()) {
return;
}
Formatter format(printer, variables_);
- if (IsTcTableGuarded(options_)) {
+ if (should_generate_guarded_tctable()) {
format.Outdent();
format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
format.Indent();
}
- if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
- format(
- "static const ::$proto_ns$::internal::TailCallParseTable<$1$>\n"
- " _table_;\n",
- tc_table_info_->table_size_log2);
- }
- if (IsTcTableGuarded(options_)) {
+ format(
+ "static const ::$proto_ns$::internal::TailCallParseTable<$1$>\n"
+ " _table_;\n",
+ tc_table_info_->table_size_log2);
+ if (should_generate_guarded_tctable()) {
format.Outdent();
format("#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
format.Indent();
@@ -393,17 +482,15 @@ void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) {
}
void ParseFunctionGenerator::GenerateDataDefinitions(io::Printer* printer) {
- if (descriptor_->options().message_set_wire_format()) {
+ if (!should_generate_tctable()) {
return;
}
Formatter format(printer, variables_);
- if (IsTcTableGuarded(options_)) {
+ if (should_generate_guarded_tctable()) {
format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
}
- if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) {
- GenerateTailCallTable(format);
- }
- if (IsTcTableGuarded(options_)) {
+ GenerateTailCallTable(format);
+ if (should_generate_guarded_tctable()) {
format("#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
}
}
@@ -415,6 +502,8 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) {
"$annotate_deserialize$"
"#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n");
format.Indent();
+ format.Set("msg", "");
+ format.Set("this", "this");
int hasbits_size = 0;
if (num_hasbits_ > 0) {
hasbits_size = (num_hasbits_ + 31) / 32;
@@ -427,7 +516,7 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) {
} else {
format.Set("has_bits", "_has_bits_");
}
- format.Set("continue", "continue");
+ format.Set("next_tag", "continue");
format("while (!ctx->Done(&ptr)) {\n");
format.Indent();
@@ -438,26 +527,26 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) {
format("} // while\n");
format.Outdent();
- format("success:\n");
+ format("message_done:\n");
if (hasbits_size) format(" _has_bits_.Or(has_bits);\n");
format(
" return ptr;\n"
"failure:\n"
" ptr = nullptr;\n"
- " goto success;\n"
+ " goto message_done;\n"
"#undef CHK_\n"
"}\n");
}
void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) {
+ GOOGLE_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";
} else {
- fallback = "::" + ProtobufNamespace(options_) +
- "::internal::TcParserBase::GenericFallback";
+ fallback = TcParserBaseName(options_) + "GenericFallback";
if (GetOptimizeFor(descriptor_->file(), options_) ==
FileOptions::LITE_RUNTIME) {
fallback += "Lite";
@@ -493,10 +582,8 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) {
format("0, 0, 0, // no _extensions_\n");
}
format(
- "$1$, // has_bits_required_mask\n"
- "&$2$._instance,\n"
- "$3$ // fallback\n",
- tc_table_info_->has_hasbits_required_mask,
+ "&$1$._instance,\n"
+ "$2$ // fallback\n",
DefaultInstanceName(descriptor_, options_), fallback);
format.Outdent();
format("}, {\n");
@@ -536,13 +623,26 @@ void ParseFunctionGenerator::GenerateArenaString(Formatter& format,
"::" + MakeDefaultName(field) + ".get()";
format(
"if (arena != nullptr) {\n"
- " ptr = ctx->ReadArenaString(ptr, &$1$_, arena);\n"
+ " ptr = ctx->ReadArenaString(ptr, &$msg$$name$_, arena");
+ if (IsStringInlined(field, options_)) {
+ GOOGLE_DCHECK(!inlined_string_indices_.empty());
+ int inlined_string_index = inlined_string_indices_[field->index()];
+ GOOGLE_DCHECK_GE(inlined_string_index, 0);
+ format(
+ ", $msg$_internal_$name$_donated()"
+ ", &$msg$_inlined_string_donated_[$1$]"
+ ", ~0x$2$u",
+ inlined_string_index / 32,
+ strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8));
+ }
+ format(
+ ");\n"
"} else {\n"
" ptr = ::$proto_ns$::internal::InlineGreedyStringParser("
- "$1$_.MutableNoArenaNoDefault(&$2$), ptr, ctx);\n"
+ "$msg$$name$_.MutableNoArenaNoDefault(&$1$), ptr, ctx);\n"
"}\n"
- "const TProtoStringType* str = &$1$_.Get(); (void)str;\n",
- FieldName(field), default_string);
+ "const TProtoStringType* str = &$msg$$name$_.Get(); (void)str;\n",
+ default_string);
}
void ParseFunctionGenerator::GenerateStrings(Formatter& format,
@@ -560,24 +660,24 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format,
!field->real_containing_oneof() && ctype == FieldOptions::STRING) {
GenerateArenaString(format, field);
} else {
- TProtoStringType name;
+ TProtoStringType parser_name;
switch (ctype) {
case FieldOptions::STRING:
- name = "GreedyStringParser";
+ parser_name = "GreedyStringParser";
break;
case FieldOptions::CORD:
- name = "CordParser";
+ parser_name = "CordParser";
break;
case FieldOptions::STRING_PIECE:
- name = "StringPieceParser";
+ parser_name = "StringPieceParser";
break;
}
format(
- "auto str = $1$$2$_$3$();\n"
- "ptr = ::$proto_ns$::internal::Inline$4$(str, ptr, ctx);\n",
+ "auto str = $msg$$1$$2$_$name$();\n"
+ "ptr = ::$proto_ns$::internal::Inline$3$(str, ptr, ctx);\n",
HasInternalAccessors(ctype) ? "_internal_" : "",
field->is_repeated() && !field->is_packable() ? "add" : "mutable",
- FieldName(field), name);
+ parser_name);
}
if (!check_utf8) return; // return if this is a bytes field
auto level = GetUtf8CheckMode(field, options_);
@@ -614,24 +714,20 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format,
void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format,
const FieldDescriptor* field) {
if (field->is_packable()) {
- TProtoStringType enum_validator;
if (field->type() == FieldDescriptor::TYPE_ENUM &&
!HasPreservingUnknownEnumSemantics(field)) {
- enum_validator =
- StrCat(", ", QualifiedClassName(field->enum_type(), options_),
- "_IsValid, &_internal_metadata_, ", field->number());
+ TProtoStringType enum_type = QualifiedClassName(field->enum_type(), options_);
format(
"ptr = "
"::$proto_ns$::internal::Packed$1$Parser<$unknown_fields_type$>("
- "_internal_mutable_$2$(), ptr, ctx$3$);\n",
- DeclaredTypeMethodName(field->type()), FieldName(field),
- enum_validator);
+ "$msg$_internal_mutable_$name$(), ptr, ctx, $2$_IsValid, "
+ "&$msg$_internal_metadata_, $3$);\n",
+ DeclaredTypeMethodName(field->type()), enum_type, field->number());
} else {
format(
"ptr = ::$proto_ns$::internal::Packed$1$Parser("
- "_internal_mutable_$2$(), ptr, ctx$3$);\n",
- DeclaredTypeMethodName(field->type()), FieldName(field),
- enum_validator);
+ "$msg$_internal_mutable_$name$(), ptr, ctx);\n",
+ DeclaredTypeMethodName(field->type()));
}
} else {
auto field_type = field->type();
@@ -651,61 +747,59 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format,
!HasPreservingUnknownEnumSemantics(field)) {
format(
"auto object = "
- "::$proto_ns$::internal::InitEnumParseWrapper<$unknown_"
- "fields_type$>("
- "&$1$_, $2$_IsValid, $3$, &_internal_metadata_);\n"
+ "::$proto_ns$::internal::InitEnumParseWrapper<"
+ "$unknown_fields_type$>(&$msg$$name$_, $1$_IsValid, "
+ "$2$, &$msg$_internal_metadata_);\n"
"ptr = ctx->ParseMessage(&object, ptr);\n",
- FieldName(field), QualifiedClassName(val->enum_type()),
+ QualifiedClassName(val->enum_type(), options_),
field->number());
} else {
- format("ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field));
+ format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n");
}
} else if (IsLazy(field, options_, scc_analyzer_)) {
if (field->real_containing_oneof()) {
format(
- "if (!_internal_has_$1$()) {\n"
- " clear_$2$();\n"
- " $2$_.$1$_ = ::$proto_ns$::Arena::CreateMessage<\n"
+ "if (!$msg$_internal_has_$name$()) {\n"
+ " $msg$clear_$1$();\n"
+ " $msg$$1$_.$name$_ = ::$proto_ns$::Arena::CreateMessage<\n"
" ::$proto_ns$::internal::LazyField>("
- "GetArenaForAllocation());\n"
- " set_has_$1$();\n"
+ "$msg$GetArenaForAllocation());\n"
+ " $msg$set_has_$name$();\n"
"}\n"
- "ptr = ctx->ParseMessage($2$_.$1$_, ptr);\n",
- FieldName(field), field->containing_oneof()->name());
+ "ptr = ctx->ParseMessage($msg$$1$_.$name$_, ptr);\n",
+ field->containing_oneof()->name());
} else if (HasHasbit(field)) {
format(
- "_Internal::set_has_$1$(&$has_bits$);\n"
- "ptr = ctx->ParseMessage(&$1$_, ptr);\n",
- FieldName(field));
+ "_Internal::set_has_$name$(&$has_bits$);\n"
+ "ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n");
} else {
- format("ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field));
+ format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n");
}
} else if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
if (!field->is_repeated()) {
format(
- "ptr = ctx->ParseMessage(_Internal::mutable_$1$(this), "
- "ptr);\n",
- FieldName(field));
+ "ptr = ctx->ParseMessage(_Internal::mutable_$name$($this$), "
+ "ptr);\n");
} else {
format(
- "ptr = ctx->ParseMessage($1$_.AddWeak(reinterpret_cast<const "
- "::$proto_ns$::MessageLite*>($2$::_$3$_default_instance_ptr_)"
+ "ptr = ctx->ParseMessage($msg$$name$_.AddWeak("
+ "reinterpret_cast<const ::$proto_ns$::MessageLite*>($1$ptr_)"
"), ptr);\n",
- FieldName(field), Namespace(field->message_type(), options_),
- ClassName(field->message_type()));
+ QualifiedDefaultInstanceName(field->message_type(), options_));
}
} else if (IsWeak(field, options_)) {
format(
"{\n"
" auto* default_ = &reinterpret_cast<const Message&>($1$);\n"
- " ptr = ctx->ParseMessage(_weak_field_map_.MutableMessage($2$,"
- " default_), ptr);\n"
+ " ptr = ctx->ParseMessage($msg$_weak_field_map_.MutableMessage("
+ "$2$, default_), ptr);\n"
"}\n",
QualifiedDefaultInstanceName(field->message_type(), options_),
field->number());
} else {
- format("ptr = ctx->ParseMessage(_internal_$1$_$2$(), ptr);\n",
- field->is_repeated() ? "add" : "mutable", FieldName(field));
+ format(
+ "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), "
+ "ptr);\n");
}
break;
}
@@ -728,29 +822,39 @@ static bool ShouldRepeat(const FieldDescriptor* descriptor,
void ParseFunctionGenerator::GenerateFieldBody(
Formatter& format, WireFormatLite::WireType wiretype,
const FieldDescriptor* field) {
+ Formatter::SaveState formatter_state(&format);
+ format.AddMap(
+ {{"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))}});
+ } else {
+ format.AddMap(
+ {{"put_field", StrCat("set_", FieldName(field))},
+ {"mutable_field", StrCat("mutable_", FieldName(field))}});
+ }
uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype);
switch (wiretype) {
case WireFormatLite::WIRETYPE_VARINT: {
TProtoStringType type = PrimitiveTypeName(options_, field->cpp_type());
- TProtoStringType prefix = field->is_repeated() ? "add" : "set";
if (field->type() == FieldDescriptor::TYPE_ENUM) {
+ format.Set("enum_type",
+ QualifiedClassName(field->enum_type(), options_));
format(
"$uint64$ val = ::$proto_ns$::internal::ReadVarint64(&ptr);\n"
"CHK_(ptr);\n");
if (!HasPreservingUnknownEnumSemantics(field)) {
- format("if (PROTOBUF_PREDICT_TRUE($1$_IsValid(val))) {\n",
- QualifiedClassName(field->enum_type(), options_));
+ format("if (PROTOBUF_PREDICT_TRUE($enum_type$_IsValid(val))) {\n");
format.Indent();
}
- format("_internal_$1$_$2$(static_cast<$3$>(val));\n", prefix,
- FieldName(field),
- QualifiedClassName(field->enum_type(), options_));
+ format("$msg$_internal_$put_field$(static_cast<$enum_type$>(val));\n");
if (!HasPreservingUnknownEnumSemantics(field)) {
format.Outdent();
format(
"} else {\n"
" ::$proto_ns$::internal::WriteVarint("
- "$1$, val, mutable_unknown_fields());\n"
+ "$1$, val, $msg$mutable_unknown_fields());\n"
"}\n",
field->number());
}
@@ -765,42 +869,38 @@ void ParseFunctionGenerator::GenerateFieldBody(
zigzag = "ZigZag";
}
if (field->is_repeated() || field->real_containing_oneof()) {
- TProtoStringType prefix = field->is_repeated() ? "add" : "set";
format(
- "_internal_$1$_$2$("
- "::$proto_ns$::internal::ReadVarint$3$$4$(&ptr));\n"
+ "$msg$_internal_$put_field$("
+ "::$proto_ns$::internal::ReadVarint$1$$2$(&ptr));\n"
"CHK_(ptr);\n",
- prefix, FieldName(field), zigzag, size);
+ zigzag, size);
} else {
if (HasHasbit(field)) {
- format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field));
+ format("_Internal::set_has_$name$(&$has_bits$);\n");
}
format(
- "$1$_ = ::$proto_ns$::internal::ReadVarint$2$$3$(&ptr);\n"
+ "$msg$$name$_ = ::$proto_ns$::internal::ReadVarint$1$$2$(&ptr);\n"
"CHK_(ptr);\n",
- FieldName(field), zigzag, size);
+ zigzag, size);
}
}
break;
}
case WireFormatLite::WIRETYPE_FIXED32:
case WireFormatLite::WIRETYPE_FIXED64: {
- TProtoStringType type = PrimitiveTypeName(options_, field->cpp_type());
if (field->is_repeated() || field->real_containing_oneof()) {
- TProtoStringType prefix = field->is_repeated() ? "add" : "set";
format(
- "_internal_$1$_$2$("
- "::$proto_ns$::internal::UnalignedLoad<$3$>(ptr));\n"
- "ptr += sizeof($3$);\n",
- prefix, FieldName(field), type);
+ "$msg$_internal_$put_field$("
+ "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr));\n"
+ "ptr += sizeof($primitive_type$);\n");
} else {
if (HasHasbit(field)) {
- format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field));
+ format("_Internal::set_has_$name$(&$has_bits$);\n");
}
format(
- "$1$_ = ::$proto_ns$::internal::UnalignedLoad<$2$>(ptr);\n"
- "ptr += sizeof($2$);\n",
- FieldName(field), type);
+ "$msg$$name$_ = "
+ "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr);\n"
+ "ptr += sizeof($primitive_type$);\n");
}
break;
}
@@ -811,9 +911,9 @@ void ParseFunctionGenerator::GenerateFieldBody(
}
case WireFormatLite::WIRETYPE_START_GROUP: {
format(
- "ptr = ctx->ParseGroup(_internal_$1$_$2$(), ptr, $3$);\n"
+ "ptr = ctx->ParseGroup($msg$_internal_$mutable_field$(), ptr, $1$);\n"
"CHK_(ptr);\n",
- field->is_repeated() ? "add" : "mutable", FieldName(field), tag);
+ tag);
break;
}
case WireFormatLite::WIRETYPE_END_GROUP: {
@@ -845,14 +945,90 @@ static uint32_t ExpectedTag(const FieldDescriptor* field,
return expected_tag;
}
+// These variables are used by the generated parse iteration, and must already
+// be defined in the generated code:
+// - `const char* ptr`: the input buffer.
+// - `ParseContext* ctx`: the associated context for `ptr`.
+// - implicit `this`: i.e., we must be in a non-static member function.
+//
+// The macro `CHK_(x)` must be defined. It should return an error condition if
+// the macro parameter is false.
+//
+// Whenever an END_GROUP tag was read, or tag 0 was read, the generated code
+// branches to the label `message_done`.
+//
+// These formatter variables are used:
+// - `next_tag`: a single statement to begin parsing the next tag.
+//
+// At the end of the generated code, the enclosing function should proceed to
+// parse the next tag in the stream.
void ParseFunctionGenerator::GenerateParseIterationBody(
Formatter& format, const Descriptor* descriptor,
const std::vector<const FieldDescriptor*>& ordered_fields) {
format(
"$uint32$ tag;\n"
"ptr = ::$proto_ns$::internal::ReadTag(ptr, &tag);\n");
- if (!ordered_fields.empty()) format("switch (tag >> 3) {\n");
+ if (!ordered_fields.empty()) {
+ GenerateFieldSwitch(format, ordered_fields);
+ // Each field `case` only considers field number. Field numbers that are
+ // not defined in the message, or tags with an incompatible wire type, are
+ // considered "unusual" cases. They will be handled by the logic below.
+ format.Outdent();
+ format("handle_unusual:\n");
+ format.Indent();
+ }
+
+ // Unusual/extension/unknown case:
+ format(
+ "if ((tag == 0) || ((tag & 7) == 4)) {\n"
+ " CHK_(ptr);\n"
+ " ctx->SetLastTag(tag);\n"
+ " goto message_done;\n"
+ "}\n");
+ if (IsMapEntryMessage(descriptor)) {
+ format("$next_tag$;\n");
+ } else {
+ if (descriptor->extension_range_count() > 0) {
+ format("if (");
+ for (int i = 0; i < descriptor->extension_range_count(); i++) {
+ const Descriptor::ExtensionRange* range =
+ descriptor->extension_range(i);
+ if (i > 0) format(" ||\n ");
+
+ uint32_t start_tag = WireFormatLite::MakeTag(
+ range->start, static_cast<WireFormatLite::WireType>(0));
+ uint32_t end_tag = WireFormatLite::MakeTag(
+ range->end, static_cast<WireFormatLite::WireType>(0));
+
+ if (range->end > FieldDescriptor::kMaxNumber) {
+ format("($1$u <= tag)", start_tag);
+ } else {
+ format("($1$u <= tag && tag < $2$u)", start_tag, end_tag);
+ }
+ }
+ format(
+ ") {\n"
+ " ptr = $msg$_extensions_.ParseField(tag, ptr, "
+ "internal_default_instance(), &$msg$_internal_metadata_, ctx);\n"
+ " CHK_(ptr != nullptr);\n"
+ " $next_tag$;\n"
+ "}\n");
+ }
+ format(
+ "ptr = UnknownFieldParse(\n"
+ " tag,\n"
+ " $msg$_internal_metadata_.mutable_unknown_fields<"
+ "$unknown_fields_type$>(),\n"
+ " ptr, ctx);\n"
+ "CHK_(ptr != nullptr);\n");
+ }
+}
+
+void ParseFunctionGenerator::GenerateFieldSwitch(
+ Formatter& format,
+ const std::vector<const FieldDescriptor*>& ordered_fields) {
+ format("switch (tag >> 3) {\n");
format.Indent();
for (const auto* field : ordered_fields) {
@@ -893,61 +1069,18 @@ void ParseFunctionGenerator::GenerateParseIterationBody(
field);
format.Outdent();
}
- format.Outdent();
format(
- " } else goto handle_unusual;\n"
- " $continue$;\n");
+ "} else\n"
+ " goto handle_unusual;\n"
+ "$next_tag$;\n");
+ format.Outdent();
} // for loop over ordered fields
- // Default case
- if (!ordered_fields.empty()) format("default: {\n");
- if (!ordered_fields.empty()) format("handle_unusual:\n");
format(
- " if ((tag == 0) || ((tag & 7) == 4)) {\n"
- " CHK_(ptr);\n"
- " ctx->SetLastTag(tag);\n"
- " goto success;\n"
- " }\n");
- if (IsMapEntryMessage(descriptor)) {
- format(" $continue$;\n");
- } else {
- if (descriptor->extension_range_count() > 0) {
- format("if (");
- for (int i = 0; i < descriptor->extension_range_count(); i++) {
- const Descriptor::ExtensionRange* range =
- descriptor->extension_range(i);
- if (i > 0) format(" ||\n ");
-
- uint32_t start_tag = WireFormatLite::MakeTag(
- range->start, static_cast<WireFormatLite::WireType>(0));
- uint32_t end_tag = WireFormatLite::MakeTag(
- range->end, static_cast<WireFormatLite::WireType>(0));
-
- if (range->end > FieldDescriptor::kMaxNumber) {
- format("($1$u <= tag)", start_tag);
- } else {
- format("($1$u <= tag && tag < $2$u)", start_tag, end_tag);
- }
- }
- format(") {\n");
- format(
- " ptr = _extensions_.ParseField(tag, ptr,\n"
- " internal_default_instance(), &_internal_metadata_, ctx);\n"
- " CHK_(ptr != nullptr);\n"
- " $continue$;\n"
- "}\n");
- }
- format(
- " ptr = UnknownFieldParse(tag,\n"
- " _internal_metadata_.mutable_unknown_fields<$unknown_"
- "fields_type$>(),\n"
- " ptr, ctx);\n"
- " CHK_(ptr != nullptr);\n"
- " $continue$;\n");
- }
- if (!ordered_fields.empty()) format("}\n"); // default case
+ "default:\n"
+ " goto handle_unusual;\n");
format.Outdent();
- if (!ordered_fields.empty()) format("} // switch\n");
+ format("} // switch\n");
}
namespace {
@@ -1137,31 +1270,30 @@ TProtoStringType GetTailCallFieldHandlerName(ParseCardinality card,
name.append(CodedTagType(tag_length_bytes));
- TProtoStringType tcpb =
- StrCat(ProtobufNamespace(options), "::internal::TcParserBase");
-
switch (type_format) {
case TypeFormat::kVar64:
case TypeFormat::kVar32:
case TypeFormat::kBool:
- name.append(StrCat(", ::", tcpb, "::kNoConversion"));
+ name.append(
+ StrCat(", ", TcParserBaseName(options), "kNoConversion"));
break;
case TypeFormat::kSInt64:
case TypeFormat::kSInt32:
- name.append(StrCat(", ::", tcpb, "::kZigZag"));
+ name.append(StrCat(", ", TcParserBaseName(options), "kZigZag"));
break;
case TypeFormat::kBytes:
- name.append(StrCat(", ::", tcpb, "::kNoUtf8"));
+ name.append(StrCat(", ", TcParserBaseName(options), "kNoUtf8"));
break;
case TypeFormat::kString:
- name.append(StrCat(", ::", tcpb, "::kUtf8"));
+ name.append(StrCat(", ", TcParserBaseName(options), "kUtf8"));
break;
case TypeFormat::kStringValidateOnly:
- name.append(StrCat(", ::", tcpb, "::kUtf8ValidateOnly"));
+ name.append(
+ StrCat(", ", TcParserBaseName(options), "kUtf8ValidateOnly"));
break;
default:
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
index b992bb38c8..34c8fc488b 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h
@@ -76,6 +76,7 @@ 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);
@@ -93,9 +94,25 @@ class ParseFunctionGenerator {
void GenerateDataDefinitions(io::Printer* printer);
private:
+ // Returns true if tailcall table code should be generated.
+ bool should_generate_tctable() const;
+
+ // Returns true if tailcall table code should be generated, but inside an
+ // #ifdef guard.
+ bool should_generate_guarded_tctable() const {
+ return should_generate_tctable() &&
+ options_.tctable_mode == Options::kTCTableGuarded;
+ }
+
+ // Generates a tail-calling `_InternalParse` function.
+ void GenerateTailcallParseFunction(Formatter& format);
+
// Generates a fallback function for tailcall table-based parsing.
void GenerateTailcallFallbackFunction(Formatter& format);
+ // Generates functions for parsing this message as a field.
+ void GenerateTailcallFieldParseFunctions(Formatter& format);
+
// Generates a looping `_InternalParse` function.
void GenerateLoopingParseFunction(Formatter& format);
@@ -123,18 +140,20 @@ class ParseFunctionGenerator {
Formatter& format, const Descriptor* descriptor,
const std::vector<const FieldDescriptor*>& ordered_fields);
+ // Generates a `switch` statement to parse each of `ordered_fields`.
+ void GenerateFieldSwitch(
+ Formatter& format,
+ const std::vector<const FieldDescriptor*>& ordered_fields);
+
const Descriptor* descriptor_;
MessageSCCAnalyzer* scc_analyzer_;
const Options& options_;
std::map<TProtoStringType, TProtoStringType> variables_;
std::unique_ptr<TailCallTableInfo> tc_table_info_;
+ std::vector<int> inlined_string_indices_;
int num_hasbits_;
};
-// Returns the integer type that holds a tag of the given length (in bytes) when
-// wire-encoded.
-const char* CodedTagType(int tag_size);
-
enum class ParseCardinality {
kSingular,
kOneof,
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index da229ce3c4..8b37b866ae 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -209,10 +209,19 @@ void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const {
Formatter format(printer, variables_);
int fixed_size = FixedSize(descriptor_->type());
if (fixed_size == -1) {
- format(
- "total_size += $tag_size$ +\n"
- " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
- " this->_internal_$name$());\n");
+ 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 += ::$proto_ns$::internal::WireFormatLite::"
+ "$declared_type$SizePlusOne(this->_internal_$name$());\n");
+ } else {
+ format(
+ "total_size += $tag_size$ +\n"
+ " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
+ " this->_internal_$name$());\n");
+ }
} else {
format("total_size += $tag_size$ + $fixed_size$;\n");
}
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
index 394b304770..ce0f97d930 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -51,17 +51,17 @@ class PrimitiveFieldGenerator : public FieldGenerator {
~PrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GeneratePrivateMembers(io::Printer* printer) const;
- void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateMergingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
- void GenerateCopyConstructorCode(io::Printer* printer) const;
- void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
- void GenerateByteSize(io::Printer* printer) const;
- void GenerateConstinitInitializer(io::Printer* printer) const;
+ 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 GenerateConstinitInitializer(io::Printer* printer) const override;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
@@ -74,10 +74,10 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator {
~PrimitiveOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
+ 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);
@@ -90,17 +90,17 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
~RepeatedPrimitiveFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GeneratePrivateMembers(io::Printer* printer) const;
- void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateMergingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
- void GenerateCopyConstructorCode(io::Printer* printer) const;
- void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
- void GenerateByteSize(io::Printer* printer) const;
- void GenerateConstinitInitializer(io::Printer* printer) const;
+ 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 GenerateConstinitInitializer(io::Printer* printer) const override;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 12faeaf7a0..0adde4e777 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -104,7 +104,8 @@ void SetStringVariables(const FieldDescriptor* descriptor,
StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
- : FieldGenerator(descriptor, options) {
+ : FieldGenerator(descriptor, options),
+ inlined_(IsStringInlined(descriptor, options)) {
SetStringVariables(descriptor, &variables_, options);
}
@@ -112,7 +113,14 @@ StringFieldGenerator::~StringFieldGenerator() {}
void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
Formatter format(printer, variables_);
- format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
+ if (!inlined_) {
+ format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
+ } else {
+ // `_init_inline_xxx` is used for initializing default instances.
+ format(
+ "::$proto_ns$::internal::InlinedStringField $name$_;\n"
+ "static std::true_type _init_inline_$name$_;\n");
+ }
}
void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const {
@@ -172,8 +180,13 @@ void StringFieldGenerator::GenerateAccessorDeclarations(
"const TProtoStringType& _internal_$name$() const;\n"
"inline PROTOBUF_ALWAYS_INLINE void "
"_internal_set_$name$(const TProtoStringType& value);\n"
- "TProtoStringType* _internal_mutable_$name$();\n"
- "public:\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();
@@ -196,16 +209,36 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
}
format(
" return _internal_$name$();\n"
- "}\n"
- "template <typename ArgT0, typename... ArgT>\n"
- "inline PROTOBUF_ALWAYS_INLINE\n"
- "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
- " $set_hasbit$\n"
- " $name$_.$setter$($default_value_tag$, static_cast<ArgT0 &&>(arg0),"
- " args..., GetArenaForAllocation());\n"
- "$annotate_set$"
- " // @@protoc_insertion_point(field_set:$full_name$)\n"
- "}\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"
+ " $set_hasbit$\n"
+ " $name$_.$setter$($default_value_tag$, 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"
+ " $set_hasbit$\n"
+ " $name$_.$setter$(nullptr, static_cast<ArgT0 &&>(arg0),"
+ " args..., GetArenaForAllocation(), _internal_$name$_donated(), "
+ "&$donating_states_word$, $mask_for_undonate$);\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"
" TProtoStringType* _s = _internal_mutable_$name$();\n"
"$annotate_mutable$"
@@ -217,15 +250,34 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
"}\n"
"inline void $classname$::_internal_set_$name$(const TProtoStringType& "
"value) {\n"
- " $set_hasbit$\n"
- " $name$_.Set($default_value_tag$, value, GetArenaForAllocation());\n"
- "}\n");
+ " $set_hasbit$\n");
+ if (!inlined_) {
+ format(
+ " $name$_.Set($default_value_tag$, value, GetArenaForAllocation());\n"
+ "}\n");
+ } else {
+ format(
+ " $name$_.Set(nullptr, value, GetArenaForAllocation(),\n"
+ " _internal_$name$_donated(), &$donating_states_word$, "
+ "$mask_for_undonate$);\n"
+ "}\n");
+ }
format(
"inline TProtoStringType* $classname$::_internal_mutable_$name$() {\n"
- " $set_hasbit$\n"
- " return $name$_.Mutable($default_variable_or_tag$, "
- "GetArenaForAllocation());\n"
- "}\n"
+ " $set_hasbit$\n");
+ if (!inlined_) {
+ format(
+ " return $name$_.Mutable($default_variable_or_tag$, "
+ "GetArenaForAllocation());\n"
+ "}\n");
+ } else {
+ format(
+ " return $name$_.Mutable($default_variable_or_tag$, "
+ "GetArenaForAllocation(), _internal_$name$_donated(), "
+ "&$donating_states_word$, $mask_for_undonate$);\n"
+ "}\n");
+ }
+ format(
"inline TProtoStringType* $classname$::$release_name$() {\n"
"$annotate_release$"
" // @@protoc_insertion_point(field_release:$full_name$)\n");
@@ -235,9 +287,16 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
" if (!_internal_has_$name$()) {\n"
" return nullptr;\n"
" }\n"
- " $clear_hasbit$\n"
- " return $name$_.ReleaseNonDefault($init_value$, "
- "GetArenaForAllocation());\n");
+ " $clear_hasbit$\n");
+ if (!inlined_) {
+ format(
+ " return $name$_.ReleaseNonDefault($init_value$, "
+ "GetArenaForAllocation());\n");
+ } else {
+ format(
+ " return $name$_.Release(nullptr, GetArenaForAllocation(), "
+ "_internal_$name$_donated());\n");
+ }
} else {
format(
" return $name$_.Release($init_value$, GetArenaForAllocation());\n");
@@ -250,9 +309,19 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
" $set_hasbit$\n"
" } else {\n"
" $clear_hasbit$\n"
- " }\n"
- " $name$_.SetAllocated($init_value$, $name$,\n"
- " GetArenaForAllocation());\n"
+ " }\n");
+ if (!inlined_) {
+ format(
+ " $name$_.SetAllocated($init_value$, $name$,\n"
+ " GetArenaForAllocation());\n");
+ } else {
+ // Currently, string fields with default value can't be inlined.
+ format(
+ " $name$_.SetAllocated(nullptr, $name$, GetArenaForAllocation(), "
+ "_internal_$name$_donated(), &$donating_states_word$, "
+ "$mask_for_undonate$);\n");
+ }
+ format(
"$annotate_set$"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n");
@@ -274,6 +343,7 @@ void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
if (descriptor_->default_value_string().empty()) {
format("$name$_.ClearToEmpty();\n");
} else {
+ GOOGLE_DCHECK(!inlined_);
format(
"$name$_.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n");
}
@@ -292,6 +362,18 @@ void StringFieldGenerator::GenerateMessageClearingCode(
// 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$(!$name$_.IsDefault(nullptr));\n");
+ }
+
if (descriptor_->default_value_string().empty()) {
if (must_be_present) {
format("$name$_.ClearNonDefaultToEmpty();\n");
@@ -314,16 +396,31 @@ void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
Formatter format(printer, variables_);
- format(
- "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n"
- " $init_value$,\n"
- " &$name$_, GetArenaForAllocation(),\n"
- " &other->$name$_, other->GetArenaForAllocation()\n"
- ");\n");
+ if (!inlined_) {
+ format(
+ "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n"
+ " $init_value$,\n"
+ " &$name$_, lhs_arena,\n"
+ " &other->$name$_, rhs_arena\n"
+ ");\n");
+ } else {
+ // At this point, it's guaranteed that the two fields being swapped are on
+ // the same arena.
+ format(
+ "$name$_.Swap(&other->$name$_, nullptr, GetArenaForAllocation(), "
+ "_internal_$name$_donated(), other->_internal_$name$_donated(), "
+ "&$donating_states_word$, &(other->$donating_states_word$), "
+ "$mask_for_undonate$);\n");
+ }
}
void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
Formatter format(printer, variables_);
+ if (inlined_ && descriptor_->default_value_string().empty()) {
+ // Automatic initialization will construct the string.
+ return;
+ }
+ GOOGLE_DCHECK(!inlined_);
format("$name$_.UnsafeSetDefault($init_value$);\n");
}
@@ -340,10 +437,16 @@ void StringFieldGenerator::GenerateCopyConstructorCode(
format.Indent();
- // TODO(gpike): improve this
- format(
- "$name$_.Set($default_value_tag$, from._internal_$name$(), \n"
- " GetArenaForAllocation());\n");
+ if (!inlined_) {
+ format(
+ "$name$_.Set($default_value_tag$, from._internal_$name$(), \n"
+ " GetArenaForAllocation());\n");
+ } else {
+ format(
+ "$name$_.Set(nullptr, from._internal_$name$(),\n"
+ " GetArenaForAllocation(), _internal_$name$_donated(), "
+ "&$donating_states_word$, $mask_for_undonate$);\n");
+ }
format.Outdent();
format("}\n");
@@ -351,6 +454,11 @@ void StringFieldGenerator::GenerateCopyConstructorCode(
void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
Formatter format(printer, variables_);
+ if (inlined_) {
+ // The destructor is automatically invoked.
+ return;
+ }
+
format("$name$_.DestroyNoArena($init_value$);\n");
}
@@ -380,6 +488,10 @@ void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const {
void StringFieldGenerator::GenerateConstinitInitializer(
io::Printer* printer) const {
Formatter format(printer, variables_);
+ if (inlined_) {
+ format("$name$_(nullptr, false)");
+ return;
+ }
if (descriptor_->default_value_string().empty()) {
format("$name$_(&::$proto_ns$::internal::fixed_address_empty_string)");
} else {
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h
index 213f13465d..85689bbec8 100644
--- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -51,23 +51,25 @@ class StringFieldGenerator : public FieldGenerator {
~StringFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GeneratePrivateMembers(io::Printer* printer) const;
- void GenerateStaticMembers(io::Printer* printer) const;
- void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateMessageClearingCode(io::Printer* printer) const;
- void GenerateMergingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
- void GenerateCopyConstructorCode(io::Printer* printer) const;
- void GenerateDestructorCode(io::Printer* printer) const;
- void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
- void GenerateByteSize(io::Printer* printer) const;
- void GenerateConstinitInitializer(io::Printer* printer) const;
+ 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 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 GenerateConstinitInitializer(io::Printer* printer) const override;
+ bool IsInlined() const override { return inlined_; }
private:
+ bool inlined_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
};
@@ -78,14 +80,14 @@ class StringOneofFieldGenerator : public StringFieldGenerator {
~StringOneofFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
+ 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;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
+ 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);
@@ -98,17 +100,17 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
~RepeatedStringFieldGenerator();
// implements FieldGenerator ---------------------------------------
- void GeneratePrivateMembers(io::Printer* printer) const;
- void GenerateAccessorDeclarations(io::Printer* printer) const;
- void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
- void GenerateClearingCode(io::Printer* printer) const;
- void GenerateMergingCode(io::Printer* printer) const;
- void GenerateSwappingCode(io::Printer* printer) const;
- void GenerateConstructorCode(io::Printer* printer) const;
- void GenerateCopyConstructorCode(io::Printer* printer) const;
- void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
- void GenerateByteSize(io::Printer* printer) const;
- void GenerateConstinitInitializer(io::Printer* printer) const;
+ 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 GenerateConstinitInitializer(io::Printer* printer) const override;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator);