Remove dedicated fast path for required fields in ByteSizeLong.

Formerly, they had their own fast path.  Now they share the chunked processing of all fields.  This makes chunked processing more effective as an optimization and also eliminates replicated code for repeated fields.

PiperOrigin-RevId: 532224517
pull/12803/head
Matt Kulukundis 2 years ago committed by Copybara-Service
parent cfb702a078
commit 098f21e8e6
  1. 80
      src/google/protobuf/compiler/cpp/message.cc
  2. 40
      src/google/protobuf/descriptor.pb.cc
  3. 3
      src/google/protobuf/descriptor.pb.h

@ -320,10 +320,6 @@ bool IsCrossFileMaybeMap(const FieldDescriptor* field) {
return IsCrossFileMessage(field);
}
bool IsRequired(const std::vector<const FieldDescriptor*>& v) {
return v.front()->is_required();
}
bool HasNonSplitOptionalString(const Descriptor* desc, const Options& options) {
for (const auto* field : FieldRange(desc)) {
if (IsString(field, options) && !field->is_repeated() &&
@ -1690,14 +1686,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) {
oneof->name());
}
if (HasGeneratedMethods(descriptor_->file(), options_) &&
!descriptor_->options().message_set_wire_format() &&
num_required_fields_ > 1) {
format(
"// helper for ByteSizeLong()\n"
"::size_t RequiredFieldsByteSizeFallback() const;\n\n");
}
if (HasGeneratedMethods(descriptor_->file(), options_)) {
parse_function_generator_->GenerateDataDecls(p);
}
@ -4075,34 +4063,6 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) {
}
Formatter format(p);
if (num_required_fields_ > 1) {
// Emit a function (rarely used, we hope) that handles the required fields
// by checking for each one individually.
format(
"::size_t $classname$::RequiredFieldsByteSizeFallback() const {\n"
"// @@protoc_insertion_point(required_fields_byte_size_fallback_start:"
"$full_name$)\n");
format.Indent();
format("::size_t total_size = 0;\n");
for (auto field : optimized_order_) {
if (field->is_required()) {
format("\n");
auto v = p->WithVars(HasBitVars(field));
format("if (($has_bits$[$has_array_index$] & $has_mask$) != 0) {\n");
format.Indent();
PrintFieldComment(format, field);
field_generators_.get(field).GenerateByteSize(p);
format.Outdent();
format("}\n");
}
}
format(
"\n"
"return total_size;\n");
format.Outdent();
format("}\n");
}
format(
"::size_t $classname$::ByteSizeLong() const {\n"
"$annotate_bytesize$"
@ -4118,42 +4078,6 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) {
"\n");
}
// Handle required fields (if any). We expect all of them to be
// present, so emit one conditional that checks for that. If they are all
// present then the fast path executes; otherwise the slow path executes.
if (num_required_fields_ > 1) {
// The fast path works if all required fields are present.
const std::vector<uint32_t> masks_for_has_bits = RequiredFieldsBitMask();
format("if ($1$) { // All required fields are present.\n",
ConditionalToCheckBitmasks(masks_for_has_bits));
format.Indent();
// Oneof fields cannot be required, so optimized_order_ contains all of the
// fields that we need to potentially emit.
for (auto field : optimized_order_) {
if (!field->is_required()) continue;
PrintFieldComment(format, field);
field_generators_.get(field).GenerateByteSize(p);
format("\n");
}
format.Outdent();
format(
"} else {\n" // the slow path
" total_size += RequiredFieldsByteSizeFallback();\n"
"}\n");
} else {
// num_required_fields_ <= 1: no need to be tricky
for (auto field : optimized_order_) {
if (!field->is_required()) continue;
PrintFieldComment(format, field);
auto v = p->WithVars(HasBitVars(field));
format("if (($has_bits$[$has_array_index$] & $has_mask$) != 0) {\n");
format.Indent();
field_generators_.get(field).GenerateByteSize(p);
format.Outdent();
format("}\n");
}
}
std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields(
optimized_order_,
[&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool {
@ -4161,10 +4085,6 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) {
ShouldSplit(a, options_) == ShouldSplit(b, options_);
});
// Remove chunks with required fields.
chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired),
chunks.end());
ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_,
kColdRatio);
int cached_has_word_index = -1;

@ -10079,42 +10079,28 @@ constexpr ::_pbi::TcParseTable<1, 2, 0, 62, 2> UninterpretedOption_NamePart::_ta
return target;
}
::size_t UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const {
// @@protoc_insertion_point(required_fields_byte_size_fallback_start:google.protobuf.UninterpretedOption.NamePart)
::size_t total_size = 0;
if ((_impl_._has_bits_[0] & 0x00000001u) != 0) {
// required string name_part = 1;
total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize(
this->_internal_name_part());
}
if ((_impl_._has_bits_[0] & 0x00000002u) != 0) {
// required bool is_extension = 2;
total_size += 2;
}
return total_size;
}
::size_t UninterpretedOption_NamePart::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption.NamePart)
::size_t total_size = 0;
if (((_impl_._has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) { // All required fields are present.
::uint32_t cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
cached_has_bits = _impl_._has_bits_[0];
if (cached_has_bits & 0x00000003u) {
// required string name_part = 1;
total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize(
this->_internal_name_part());
if (cached_has_bits & 0x00000001u) {
total_size += 1 + ::google::protobuf::internal::WireFormatLite::StringSize(
this->_internal_name_part());
}
// required bool is_extension = 2;
total_size += 2;
if (cached_has_bits & 0x00000002u) {
total_size += 2;
}
} else {
total_size += RequiredFieldsByteSizeFallback();
}
::uint32_t cached_has_bits = 0;
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
}

@ -7502,9 +7502,6 @@ class PROTOBUF_EXPORT UninterpretedOption_NamePart final :
private:
class _Internal;
// helper for ByteSizeLong()
::size_t RequiredFieldsByteSizeFallback() const;
friend class ::google::protobuf::internal::TcParser;
static const ::google::protobuf::internal::TcParseTable<1, 2, 0, 62, 2> _table_;
template <typename T> friend class ::google::protobuf::Arena::InternalHelper;

Loading…
Cancel
Save