Formatting beautifications.

Put the emission of braces and indentation into MayEmitIfNonDefaultCheck, this
allows for a slight beautification in the emitted code and reduces verbosity at
the call site.

Also this technically fixes the indent in some cases (specifically when
serializing some repeated fields) so that the opening braces are emitted "at
the right level".
(Previous implementations sometimes emit an extra space character.)

Compare:
 {
  // code ...
}

vs.
{
  // code ...
}

PiperOrigin-RevId: 660236451
pull/17723/head
Tony Liao 4 months ago committed by Copybara-Service
parent 2f8472adc1
commit 9277baa4cd
  1. 129
      src/google/protobuf/compiler/cpp/message.cc
  2. 6
      src/google/protobuf/compiler/cpp/message.h

@ -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<void()> 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<void()> 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();
}
MayEmitIfNonDefaultCheck(p, "from.", field, /*emit_body=*/[&]() {
generator.GenerateMergingCode(p);
if (emitted_check) {
p->Outdent();
p->Emit("}\n");
}
});
} 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();
}

@ -14,7 +14,6 @@
#include <cstddef>
#include <cstdint>
#include <limits>
#include <memory>
#include <string>
#include <utility>
@ -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<uint32_t> 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;

Loading…
Cancel
Save