diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc index 8384a5c70e..98459e47d8 100644 --- a/src/google/protobuf/compiler/cpp/message.cc +++ b/src/google/protobuf/compiler/cpp/message.cc @@ -25,6 +25,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" +#include "absl/functional/any_invocable.h" #include "absl/log/absl_check.h" #include "absl/log/absl_log.h" #include "absl/strings/ascii.h" @@ -222,22 +223,42 @@ bool ShouldEmitNonDefaultCheck(const FieldDescriptor* field) { // considered non-default (will be sent over the wire), for message types // without true field presence. Should only be called if // !HasHasbit(field). -bool MayEmitIfNonDefaultCheck(io::Printer* p, const std::string& prefix, - const FieldDescriptor* field) { +void MayEmitIfNonDefaultCheck(io::Printer* p, const std::string& prefix, + const FieldDescriptor* field, + absl::AnyInvocable emit_body) { ABSL_CHECK(!HasHasbit(field)); - if (!ShouldEmitNonDefaultCheck(field)) return false; - // SUBTLE: |format| must be a raw string without newline. - // io::Printer::Emit treats the format string as a "raw string" if it doesn't - // contain multiple lines. Note that a string of the form "\n($condition$)\n" - // (i.e. newline characters are present; there is only one non-empty line) - // will still be treated as a multi-line string. - // - // io::Printer::Emit will print a newline if the input is a multi-line string. - // In this case, we prefer to let the caller handle if-statement braces. - p->Emit({{"condition", [&] { EmitNonDefaultCheck(p, prefix, field); }}}, - /*format=*/"if ($condition$)"); - return true; + if (ShouldEmitNonDefaultCheck(field)) { + p->Emit( + { + {"condition", [&] { EmitNonDefaultCheck(p, prefix, field); }}, + {"emit_body", [&] { emit_body(); }}, + }, + R"cc( + if ($condition$) { + $emit_body$; + } + )cc"); + } else { + // In repeated fields, the same variable name may be emitted multiple + // times, hence the need for emitting braces even when the if condition is + // not necessary, so that the code looks like: + // { + // int tmpvar = ...; + // total += tmpvar; + // } + // { + // int tmpvar = ...; + // total += tmpvar; + // } + p->Emit({{"emit_body", [&] { emit_body(); }}}, + R"cc( + { + //~ Force newline. + $emit_body$; + } + )cc"); + } } bool HasInternalHasMethod(const FieldDescriptor* field) { @@ -1213,13 +1234,42 @@ class AccessorVerifier { } // namespace +void MessageGenerator::EmitCheckAndUpdateByteSizeForField( + const FieldDescriptor* field, io::Printer* p) const { + absl::AnyInvocable emit_body = [&] { + field_generators_.get(field).GenerateByteSize(p); + }; + + if (!HasHasbit(field)) { + MayEmitIfNonDefaultCheck(p, "this_.", field, std::move(emit_body)); + return; + } + if (field->options().weak()) { + p->Emit({{"emit_body", [&] { emit_body(); }}}, + R"cc( + if (has_$name$()) { + $emit_body$; + } + )cc"); + return; + } + + int has_bit_index = has_bit_indices_[field->index()]; + p->Emit({{"mask", + absl::StrFormat("0x%08xu", uint32_t{1} << (has_bit_index % 32))}, + {"emit_body", [&] { emit_body(); }}}, + R"cc( + if (cached_has_bits & $mask$) { + $emit_body$; + } + )cc"); +} + void MessageGenerator::EmitUpdateByteSizeForField( const FieldDescriptor* field, io::Printer* p, int& cached_has_word_index) const { p->Emit( {{"comment", [&] { PrintFieldComment(Formatter{p}, field, options_); }}, - {"update_byte_size_for_field", - [&] { field_generators_.get(field).GenerateByteSize(p); }}, {"update_cached_has_bits", [&] { if (!HasHasbit(field) || field->options().weak()) return; @@ -1234,31 +1284,12 @@ void MessageGenerator::EmitUpdateByteSizeForField( cached_has_bits = this_.$has_bits$[$index$]; )cc"); }}, - {"check_if_field_present", - [&] { - if (!HasHasbit(field)) { - MayEmitIfNonDefaultCheck(p, "this_.", field); - return; - } - - if (field->options().weak()) { - p->Emit("if (has_$name$())"); - return; - } - - int has_bit_index = has_bit_indices_[field->index()]; - p->Emit( - {{"mask", absl::StrFormat("0x%08xu", - uint32_t{1} << (has_bit_index % 32))}}, - "if (cached_has_bits & $mask$)"); - }}}, + {"check_and_update_byte_size_for_field", + [&]() { EmitCheckAndUpdateByteSizeForField(field, p); }}}, R"cc( $comment$; $update_cached_has_bits$; - $check_if_field_present$ { - //~ Force newline. - $update_byte_size_for_field$; - } + $check_and_update_byte_size_for_field$; )cc"); } @@ -4007,16 +4038,9 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* p) { } else if (field->is_optional() && !HasHasbit(field)) { // Merge semantics without true field presence: primitive fields are // merged only if non-zero (numeric) or non-empty (string). - bool emitted_check = MayEmitIfNonDefaultCheck(p, "from.", field); - if (emitted_check) { - p->Emit(" {\n"); - p->Indent(); - } - generator.GenerateMergingCode(p); - if (emitted_check) { - p->Outdent(); - p->Emit("}\n"); - } + MayEmitIfNonDefaultCheck(p, "from.", field, /*emit_body=*/[&]() { + generator.GenerateMergingCode(p); + }); } else if (field->options().weak() || cached_has_word_index != HasWordIndex(field)) { // Check hasbit, not using cached bits. @@ -4283,16 +4307,7 @@ void MessageGenerator::GenerateSerializeOneField(io::Printer* p, } )cc"); } else if (field->is_optional()) { - bool emitted_check = MayEmitIfNonDefaultCheck(p, "this_.", field); - if (emitted_check) { - p->Emit(" {\n"); - p->Indent(); - } - emit_body(); - if (emitted_check) { - p->Outdent(); - p->Emit("}\n"); - } + MayEmitIfNonDefaultCheck(p, "this_.", field, std::move(emit_body)); } else { emit_body(); } diff --git a/src/google/protobuf/compiler/cpp/message.h b/src/google/protobuf/compiler/cpp/message.h index 11db273a08..46bade9db7 100644 --- a/src/google/protobuf/compiler/cpp/message.h +++ b/src/google/protobuf/compiler/cpp/message.h @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include "google/protobuf/compiler/cpp/message_layout_helper.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/compiler/cpp/parse_function_generator.h" +#include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" namespace google { @@ -186,7 +186,9 @@ class MessageGenerator { int HasWordIndex(const FieldDescriptor* field) const; std::vector RequiredFieldsBitMask() const; - // Helper function to reduce nesting levels of deep Emit calls. + // Helper functions to reduce nesting levels of deep Emit calls. + void EmitCheckAndUpdateByteSizeForField(const FieldDescriptor* field, + io::Printer* p) const; void EmitUpdateByteSizeForField(const FieldDescriptor* field, io::Printer* p, int& cached_has_word_index) const; diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index 655faac555..95c78cd993 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -929,7 +929,7 @@ PROTOBUF_NOINLINE void CodeGeneratorRequest::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated string file_to_generate = 1; - { + { total_size += 1 * ::google::protobuf::internal::FromIntSize(this_._internal_file_to_generate().size()); for (int i = 0, n = this_._internal_file_to_generate().size(); i < n; ++i) { @@ -938,14 +938,14 @@ PROTOBUF_NOINLINE void CodeGeneratorRequest::Clear() { } } // repeated .google.protobuf.FileDescriptorProto proto_file = 15; - { + { total_size += 1UL * this_._internal_proto_file_size(); for (const auto& msg : this_._internal_proto_file()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.FileDescriptorProto source_file_descriptors = 17; - { + { total_size += 2UL * this_._internal_source_file_descriptors_size(); for (const auto& msg : this_._internal_source_file_descriptors()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -1653,7 +1653,7 @@ PROTOBUF_NOINLINE void CodeGeneratorResponse::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; - { + { total_size += 1UL * this_._internal_file_size(); for (const auto& msg : this_._internal_file()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 63caf08785..d999dc5eb5 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -2779,7 +2779,7 @@ PROTOBUF_NOINLINE void FileDescriptorSet::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.FileDescriptorProto file = 1; - { + { total_size += 1UL * this_._internal_file_size(); for (const auto& msg : this_._internal_file()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -3265,7 +3265,7 @@ PROTOBUF_NOINLINE void FileDescriptorProto::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated string dependency = 3; - { + { total_size += 1 * ::google::protobuf::internal::FromIntSize(this_._internal_dependency().size()); for (int i = 0, n = this_._internal_dependency().size(); i < n; ++i) { @@ -3274,35 +3274,35 @@ PROTOBUF_NOINLINE void FileDescriptorProto::Clear() { } } // repeated .google.protobuf.DescriptorProto message_type = 4; - { + { total_size += 1UL * this_._internal_message_type_size(); for (const auto& msg : this_._internal_message_type()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; - { + { total_size += 1UL * this_._internal_enum_type_size(); for (const auto& msg : this_._internal_enum_type()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.ServiceDescriptorProto service = 6; - { + { total_size += 1UL * this_._internal_service_size(); for (const auto& msg : this_._internal_service()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.FieldDescriptorProto extension = 7; - { + { total_size += 1UL * this_._internal_extension_size(); for (const auto& msg : this_._internal_extension()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated int32 public_dependency = 10; - { + { std::size_t data_size = ::_pbi::WireFormatLite::Int32Size( this_._internal_public_dependency()); std::size_t tag_size = std::size_t{1} * @@ -3310,7 +3310,7 @@ PROTOBUF_NOINLINE void FileDescriptorProto::Clear() { total_size += tag_size + data_size; } // repeated int32 weak_dependency = 11; - { + { std::size_t data_size = ::_pbi::WireFormatLite::Int32Size( this_._internal_weak_dependency()); std::size_t tag_size = std::size_t{1} * @@ -4414,56 +4414,56 @@ PROTOBUF_NOINLINE void DescriptorProto::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.FieldDescriptorProto field = 2; - { + { total_size += 1UL * this_._internal_field_size(); for (const auto& msg : this_._internal_field()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.DescriptorProto nested_type = 3; - { + { total_size += 1UL * this_._internal_nested_type_size(); for (const auto& msg : this_._internal_nested_type()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; - { + { total_size += 1UL * this_._internal_enum_type_size(); for (const auto& msg : this_._internal_enum_type()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; - { + { total_size += 1UL * this_._internal_extension_range_size(); for (const auto& msg : this_._internal_extension_range()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.FieldDescriptorProto extension = 6; - { + { total_size += 1UL * this_._internal_extension_size(); for (const auto& msg : this_._internal_extension()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8; - { + { total_size += 1UL * this_._internal_oneof_decl_size(); for (const auto& msg : this_._internal_oneof_decl()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9; - { + { total_size += 1UL * this_._internal_reserved_range_size(); for (const auto& msg : this_._internal_reserved_range()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated string reserved_name = 10; - { + { total_size += 1 * ::google::protobuf::internal::FromIntSize(this_._internal_reserved_name().size()); for (int i = 0, n = this_._internal_reserved_name().size(); i < n; ++i) { @@ -5205,14 +5205,14 @@ PROTOBUF_NOINLINE void ExtensionRangeOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.ExtensionRangeOptions.Declaration declaration = 2 [retention = RETENTION_SOURCE]; - { + { total_size += 1UL * this_._internal_declaration_size(); for (const auto& msg : this_._internal_declaration()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -6673,21 +6673,21 @@ PROTOBUF_NOINLINE void EnumDescriptorProto::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.EnumValueDescriptorProto value = 2; - { + { total_size += 1UL * this_._internal_value_size(); for (const auto& msg : this_._internal_value()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4; - { + { total_size += 1UL * this_._internal_reserved_range_size(); for (const auto& msg : this_._internal_reserved_range()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated string reserved_name = 5; - { + { total_size += 1 * ::google::protobuf::internal::FromIntSize(this_._internal_reserved_name().size()); for (int i = 0, n = this_._internal_reserved_name().size(); i < n; ++i) { @@ -7340,7 +7340,7 @@ PROTOBUF_NOINLINE void ServiceDescriptorProto::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.MethodDescriptorProto method = 2; - { + { total_size += 1UL * this_._internal_method_size(); for (const auto& msg : this_._internal_method()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -8422,7 +8422,7 @@ PROTOBUF_NOINLINE void FileOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -8973,7 +8973,7 @@ PROTOBUF_NOINLINE void MessageOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -10107,7 +10107,7 @@ PROTOBUF_NOINLINE void FieldOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.FieldOptions.OptionTargetType targets = 19; - { + { std::size_t data_size = ::_pbi::WireFormatLite::EnumSize(this_._internal_targets()); std::size_t tag_size = std::size_t{2} * @@ -10115,14 +10115,14 @@ PROTOBUF_NOINLINE void FieldOptions::Clear() { total_size += data_size + tag_size; } // repeated .google.protobuf.FieldOptions.EditionDefault edition_defaults = 20; - { + { total_size += 2UL * this_._internal_edition_defaults_size(); for (const auto& msg : this_._internal_edition_defaults()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); } } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -10521,7 +10521,7 @@ PROTOBUF_NOINLINE void OneofOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -10877,7 +10877,7 @@ PROTOBUF_NOINLINE void EnumOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -11274,7 +11274,7 @@ PROTOBUF_NOINLINE void EnumValueOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -11632,7 +11632,7 @@ PROTOBUF_NOINLINE void ServiceOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -11996,7 +11996,7 @@ PROTOBUF_NOINLINE void MethodOptions::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - { + { total_size += 2UL * this_._internal_uninterpreted_option_size(); for (const auto& msg : this_._internal_uninterpreted_option()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -12681,7 +12681,7 @@ PROTOBUF_NOINLINE void UninterpretedOption::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; - { + { total_size += 1UL * this_._internal_name_size(); for (const auto& msg : this_._internal_name()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -13735,7 +13735,7 @@ PROTOBUF_NOINLINE void FeatureSetDefaults::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault defaults = 1; - { + { total_size += 1UL * this_._internal_defaults_size(); for (const auto& msg : this_._internal_defaults()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -14088,21 +14088,21 @@ PROTOBUF_NOINLINE void SourceCodeInfo_Location::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated int32 path = 1 [packed = true]; - { + { total_size += ::_pbi::WireFormatLite::Int32SizeWithPackedTagSize( this_._internal_path(), 1, this_._impl_._path_cached_byte_size_); } // repeated int32 span = 2 [packed = true]; - { + { total_size += ::_pbi::WireFormatLite::Int32SizeWithPackedTagSize( this_._internal_span(), 1, this_._impl_._span_cached_byte_size_); } // repeated string leading_detached_comments = 6; - { + { total_size += 1 * ::google::protobuf::internal::FromIntSize(this_._internal_leading_detached_comments().size()); for (int i = 0, n = this_._internal_leading_detached_comments().size(); i < n; ++i) { @@ -14356,7 +14356,7 @@ PROTOBUF_NOINLINE void SourceCodeInfo::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.SourceCodeInfo.Location location = 1; - { + { total_size += 1UL * this_._internal_location_size(); for (const auto& msg : this_._internal_location()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg); @@ -14668,7 +14668,7 @@ PROTOBUF_NOINLINE void GeneratedCodeInfo_Annotation::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated int32 path = 1 [packed = true]; - { + { total_size += ::_pbi::WireFormatLite::Int32SizeWithPackedTagSize( this_._internal_path(), 1, @@ -14937,7 +14937,7 @@ PROTOBUF_NOINLINE void GeneratedCodeInfo::Clear() { ::_pbi::Prefetch5LinesFrom7Lines(&this_); { // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; - { + { total_size += 1UL * this_._internal_annotation_size(); for (const auto& msg : this_._internal_annotation()) { total_size += ::google::protobuf::internal::WireFormatLite::MessageSize(msg);