Refactor map_field.cc to use Emit().

PiperOrigin-RevId: 528634293
pull/12630/head
Matt Kulukundis 2 years ago committed by Copybara-Service
parent 874e291c00
commit 80b0609666
  1. 473
      src/google/protobuf/compiler/cpp/field_generators/map_field.cc

@ -30,317 +30,270 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <tuple> #include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
#include "absl/strings/ascii.h" #include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/field_generators/generators.h" #include "absl/strings/substitute.h"
#include "google/protobuf/compiler/cpp/field.h"
#include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/wire_format.h" #include "google/protobuf/compiler/cpp/options.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/printer.h"
namespace google { namespace google {
namespace protobuf { namespace protobuf {
namespace compiler { namespace compiler {
namespace cpp { namespace cpp {
namespace { namespace {
void SetMessageVariables( using Sub = ::google::protobuf::io::Printer::Sub;
const FieldDescriptor* descriptor,
absl::flat_hash_map<absl::string_view, std::string>* variables, std::vector<Sub> Vars(const FieldDescriptor* field, const Options& opts,
const Options& options) { bool lite) {
(*variables)["type"] = ClassName(descriptor->message_type(), false); const auto* key = field->message_type()->map_key();
(*variables)["full_name"] = descriptor->full_name(); const auto* val = field->message_type()->map_value();
const FieldDescriptor* key = descriptor->message_type()->map_key(); std::string key_type = PrimitiveTypeName(opts, key->cpp_type());
const FieldDescriptor* val = descriptor->message_type()->map_value(); std::string val_type;
(*variables)["key_cpp"] = PrimitiveTypeName(options, key->cpp_type());
switch (val->cpp_type()) { switch (val->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE: case FieldDescriptor::CPPTYPE_MESSAGE:
(*variables)["val_cpp"] = FieldMessageTypeName(val, options); val_type = FieldMessageTypeName(val, opts);
break; break;
case FieldDescriptor::CPPTYPE_ENUM: case FieldDescriptor::CPPTYPE_ENUM:
(*variables)["val_cpp"] = ClassName(val->enum_type(), true); val_type = ClassName(val->enum_type(), true);
break; break;
default: default:
(*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type()); val_type = PrimitiveTypeName(opts, val->cpp_type());
} break;
(*variables)["key_wire_type"] = absl::StrCat(
"TYPE_", absl::AsciiStrToUpper(DeclaredTypeMethodName(key->type())));
(*variables)["val_wire_type"] = absl::StrCat(
"TYPE_", absl::AsciiStrToUpper(DeclaredTypeMethodName(val->type())));
(*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
(*variables)["number"] = absl::StrCat(descriptor->number());
(*variables)["tag"] = absl::StrCat(internal::WireFormat::MakeTag(descriptor));
if (HasDescriptorMethods(descriptor->file(), options)) {
(*variables)["lite"] = "";
} else {
(*variables)["lite"] = "Lite";
} }
return {
{"Map", absl::Substitute("::PROTOBUF_NAMESPACE_ID::Map<$0, $1>", key_type,
val_type)},
{"Entry", ClassName(field->message_type(), false)},
{"Key", PrimitiveTypeName(opts, key->cpp_type())},
{"Val", val_type},
{"MapField", lite ? "MapFieldLite" : "MapField"},
};
} }
class MapFieldGenerator : public FieldGeneratorBase { class Map : public FieldGeneratorBase {
public: public:
MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options, Map(const FieldDescriptor* field, const Options& opts,
MessageSCCAnalyzer* scc_analyzer); MessageSCCAnalyzer* scc)
~MapFieldGenerator() override = default; : FieldGeneratorBase(field, opts),
field_(field),
// implements FieldGeneratorBase --------------------------------------- key_(field->message_type()->map_key()),
void GeneratePrivateMembers(io::Printer* printer) const override; val_(field->message_type()->map_value()),
void GenerateAccessorDeclarations(io::Printer* printer) const override; opts_(&opts),
void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; has_required_(scc->HasRequiredFields(field->message_type())),
void GenerateClearingCode(io::Printer* printer) const override; lite_(!HasDescriptorMethods(field->file(), opts)) {}
void GenerateMergingCode(io::Printer* printer) const override; ~Map() override = default;
void GenerateSwappingCode(io::Printer* printer) const override;
void GenerateConstructorCode(io::Printer* printer) const override {}
void GenerateCopyConstructorCode(io::Printer* printer) const override;
void GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const override;
void GenerateByteSize(io::Printer* printer) const override;
void GenerateIsInitialized(io::Printer* printer) const override;
void GenerateConstexprAggregateInitializer(
io::Printer* printer) const override;
void GenerateCopyAggregateInitializer(io::Printer* printer) const override;
void GenerateAggregateInitializer(io::Printer* printer) const override;
void GenerateDestructorCode(io::Printer* printer) const override;
private: std::vector<Sub> MakeVars() const override {
bool has_required_fields_; return Vars(field_, *opts_, lite_);
}; }
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, void GenerateClearingCode(io::Printer* p) const override {
const Options& options, p->Emit(R"cc(
MessageSCCAnalyzer* scc_analyzer) $field_$.Clear();
: FieldGeneratorBase(descriptor, options), )cc");
has_required_fields_(
scc_analyzer->HasRequiredFields(descriptor->message_type())) {
SetMessageVariables(descriptor, &variables_, options);
}
void MapFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
Formatter format(printer, variables_);
format(
"::$proto_ns$::internal::MapField$lite$<\n"
" $map_classname$,\n"
" $key_cpp$, $val_cpp$,\n"
" ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n"
" ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> "
"$name$_;\n");
}
void MapFieldGenerator::GenerateAccessorDeclarations(
io::Printer* printer) const {
Formatter format(printer, variables_);
format(
"private:\n"
"const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
" ${1$_internal_$name$$}$() const;\n"
"::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
" ${1$_internal_mutable_$name$$}$();\n"
"public:\n"
"$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
" ${1$$name$$}$() const;\n",
descriptor_);
format(
"$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
" ${1$mutable_$name$$}$();\n",
std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::ALIAS));
}
void MapFieldGenerator::GenerateInlineAccessorDefinitions(
io::Printer* printer) const {
Formatter format(printer, variables_);
format(
"inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
"$classname$::_internal_$name$() const {\n"
" return $field$.GetMap();\n"
"}\n"
"inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
"$classname$::$name$() const {\n"
"$annotate_get$"
" // @@protoc_insertion_point(field_map:$full_name$)\n"
" return _internal_$name$();\n"
"}\n"
"inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
"$classname$::_internal_mutable_$name$() {\n"
"$PrepareSplitMessageForWrite$"
" return $field$.MutableMap();\n"
"}\n"
"inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
"$classname$::mutable_$name$() {\n"
"$annotate_mutable$"
" // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
" return _internal_mutable_$name$();\n"
"}\n");
}
void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
Formatter format(printer, variables_);
format("$field$.Clear();\n");
}
void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
Formatter format(printer, variables_);
format("_this->$field$.MergeFrom(from.$field$);\n");
}
void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
Formatter format(printer, variables_);
format("$field$.InternalSwap(&other->$field$);\n");
}
void MapFieldGenerator::GenerateCopyConstructorCode(
io::Printer* printer) const {
GenerateConstructorCode(printer);
GenerateMergingCode(printer);
}
static void GenerateSerializationLoop(Formatter& format, bool string_key,
bool string_value,
bool is_deterministic) {
if (is_deterministic) {
format(
"for (const auto& entry : "
"::_pbi::MapSorter$1$<MapType>(map_field)) {\n",
(string_key ? "Ptr" : "Flat"));
} else {
format("for (const auto& entry : map_field) {\n");
} }
{
auto loop_scope = format.ScopedIndent(); void GenerateMergingCode(io::Printer* p) const override {
format( p->Emit(R"cc(
"target = WireHelper::InternalSerialize($number$, " _this->$field_$.MergeFrom(from.$field_$);
"entry.first, entry.second, target, stream);\n"); )cc");
if (string_key || string_value) {
format("check_utf8(entry);\n");
}
}
format("}\n");
}
void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const {
Formatter format(printer, variables_);
format("if (!this->_internal_$name$().empty()) {\n");
format.Indent();
const FieldDescriptor* key_field = descriptor_->message_type()->map_key();
const FieldDescriptor* value_field = descriptor_->message_type()->map_value();
const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
format(
"using MapType = ::_pb::Map<$key_cpp$, $val_cpp$>;\n"
"using WireHelper = $map_classname$::Funcs;\n"
"const auto& map_field = this->_internal_$name$();\n");
bool utf8_check = string_key || string_value;
if (utf8_check) {
format("auto check_utf8 = [](const MapType::value_type& entry) {\n");
{
auto check_scope = format.ScopedIndent();
// p may be unused when GetUtf8CheckMode evaluates to kNone,
// thus disabling the validation.
format("(void)entry;\n");
if (string_key) {
GenerateUtf8CheckCodeForString(
key_field, options_, false,
"entry.first.data(), static_cast<int>(entry.first.length()),\n",
format);
} }
if (string_value) {
GenerateUtf8CheckCodeForString( void GenerateSwappingCode(io::Printer* p) const override {
value_field, options_, false, p->Emit(R"cc(
"entry.second.data(), static_cast<int>(entry.second.length()),\n", $field_$.InternalSwap(&other->$field_$);
format); )cc");
}
void GenerateCopyConstructorCode(io::Printer* p) const override {
GenerateConstructorCode(p);
GenerateMergingCode(p);
} }
void GenerateIsInitialized(io::Printer* p) const override {
if (!has_required_) return;
p->Emit(R"cc(
if (!$pbi$::AllAreInitialized($field_$)) {
return false;
} }
format("};\n"); )cc");
} }
format( void GenerateConstexprAggregateInitializer(io::Printer* p) const override {
"\n" p->Emit(R"cc(/* decltype($field_$) */ {})cc");
"if (stream->IsSerializationDeterministic() && "
"map_field.size() > 1) {\n");
{
auto deterministic_scope = format.ScopedIndent();
GenerateSerializationLoop(format, string_key, string_value, true);
} }
format("} else {\n");
{ void GenerateCopyAggregateInitializer(io::Printer* p) const override {
auto map_order_scope = format.ScopedIndent(); // MapField has no move constructor, which prevents explicit aggregate
GenerateSerializationLoop(format, string_key, string_value, false); // initialization pre-C++17.
p->Emit(R"cc(/* decltype($field_$) */ {})cc");
} }
format("}\n");
format.Outdent(); void GenerateAggregateInitializer(io::Printer* p) const override {
format("}\n"); if (ShouldSplit(field_, *opts_)) {
p->Emit(R"cc(
/* decltype($Msg$::Split::$name$_) */ {
$pbi$::ArenaInitialized(), arena
}
)cc");
return;
} }
void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const { p->Emit(R"cc(
Formatter format(printer, variables_); /* decltype($field_$) */ { $pbi$::ArenaInitialized(), arena }
format( )cc");
"total_size += $tag_size$ *\n"
" "
"::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n"
"for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
" it = this->_internal_$name$().begin();\n"
" it != this->_internal_$name$().end(); ++it) {\n"
" total_size += $map_classname$::Funcs::ByteSizeLong(it->first, "
"it->second);\n"
"}\n");
} }
void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { void GenerateConstructorCode(io::Printer* p) const override {}
if (!has_required_fields_) return;
Formatter format(printer, variables_); void GenerateDestructorCode(io::Printer* p) const override {
format( if (ShouldSplit(field_, *opts_)) {
"if (!::$proto_ns$::internal::AllAreInitialized($field$)) return " p->Emit(R"cc(
"false;\n"); $cached_split_ptr$->$name$_.~$MapField$();
)cc");
return;
} }
void MapFieldGenerator::GenerateConstexprAggregateInitializer( p->Emit(R"cc(
io::Printer* printer) const { $field_$.~$MapField$();
Formatter format(printer, variables_); )cc");
format("/*decltype($field$)*/{}");
} }
void MapFieldGenerator::GenerateCopyAggregateInitializer( void GeneratePrivateMembers(io::Printer* p) const override;
io::Printer* printer) const { void GenerateAccessorDeclarations(io::Printer* p) const override;
Formatter format(printer, variables_); void GenerateInlineAccessorDefinitions(io::Printer* p) const override;
// MapField has no move constructor, which prevents explicit aggregate void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override;
// initialization pre-C++17. void GenerateByteSize(io::Printer* p) const override;
format("/*decltype($field$)*/{}");
private:
const FieldDescriptor* field_;
const FieldDescriptor* key_;
const FieldDescriptor* val_;
const Options* opts_;
bool has_required_;
bool lite_;
};
void Map::GeneratePrivateMembers(io::Printer* p) const {
p->Emit({{"kKeyType",
absl::AsciiStrToUpper(DeclaredTypeMethodName(key_->type()))},
{"kValType",
absl::AsciiStrToUpper(DeclaredTypeMethodName(val_->type()))}},
R"cc(
$pbi$::$MapField$<$Entry$, $Key$, $Val$,
$pbi$::WireFormatLite::TYPE_$kKeyType$,
$pbi$::WireFormatLite::TYPE_$kValType$>
$name$_;
)cc");
} }
void MapFieldGenerator::GenerateAggregateInitializer( void Map::GenerateAccessorDeclarations(io::Printer* p) const {
io::Printer* printer) const { auto v1 = p->WithVars(
Formatter format(printer, variables_); AnnotatedAccessors(field_, {"", "_internal_", "_internal_mutable_"}));
if (ShouldSplit(descriptor_, options_)) { auto v2 = p->WithVars(AnnotatedAccessors(field_, {"mutable_"},
format( io::AnnotationCollector::kAlias));
"/*decltype($classname$::Split::$name$_)*/" p->Emit(R"cc(
"{::_pbi::ArenaInitialized(), arena}"); $DEPRECATED$ const $Map$& $name$() const;
return; $DEPRECATED$ $Map$* $mutable_name$();
private:
const $Map$& $_internal_name$() const;
$Map$* $_internal_mutable_name$();
public:
)cc");
}
void Map::GenerateInlineAccessorDefinitions(io::Printer* p) const {
p->Emit(R"cc(
inline const $Map$& $Msg$::_internal_$name$() const {
return $field_$.GetMap();
}
inline const $Map$& $Msg$::$name$() const {
$annotate_get$;
// @@protoc_insertion_point(field_map:$pkg.Msg.field$)
return _internal_$name$();
}
inline $Map$* $Msg$::_internal_mutable_$name$() {
$PrepareSplitMessageForWrite$;
return $field_$.MutableMap();
}
inline $Map$* $Msg$::mutable_$name$() {
$annotate_mutable$;
// @@protoc_insertion_point(field_mutable_map:$pkg.Msg.field$)
return _internal_mutable_$name$();
} }
// MapField has no move constructor. )cc");
format("/*decltype($field$)*/{::_pbi::ArenaInitialized(), arena}");
} }
void MapFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { void Map::GenerateSerializeWithCachedSizesToArray(io::Printer* p) const {
Formatter format(printer, variables_); bool string_key = key_->type() == FieldDescriptor::TYPE_STRING;
if (ShouldSplit(descriptor_, options_)) { bool string_val = val_->type() == FieldDescriptor::TYPE_STRING;
format("$cached_split_ptr$->$name$_.~MapField$lite$();\n");
return; p->Emit(
{
{"Sorter", string_key ? "MapSorterPtr" : "MapSorterFlat"},
{"CheckUtf8",
[&] {
if (string_key) {
GenerateUtf8CheckCodeForString(
p, key_, *opts_, /*for_parse=*/false,
"entry.first.data(), "
"static_cast<int>(entry.first.length()),\n");
} }
format("$field$.~MapField$lite$();\n"); if (string_val) {
GenerateUtf8CheckCodeForString(
p, val_, *opts_, /*for_parse=*/false,
"entry.second.data(), "
"static_cast<int>(entry.second.length()),\n");
} }
}},
},
R"cc(
if (!_internal_$name$().empty()) {
using MapType = $Map$;
using WireHelper = $Entry$::Funcs;
const auto& field = _internal_$name$();
if (stream->IsSerializationDeterministic() && field.size() > 1) {
for (const auto& entry : $pbi$::$Sorter$<MapType>(field)) {
target = WireHelper::InternalSerialize(
$number$, entry.first, entry.second, target, stream);
$CheckUtf8$;
}
} else {
for (const auto& entry : field) {
target = WireHelper::InternalSerialize(
$number$, entry.first, entry.second, target, stream);
$CheckUtf8$;
}
}
}
)cc");
}
void Map::GenerateByteSize(io::Printer* p) const {
p->Emit(R"cc(
total_size += $kTagBytes$ * $pbi$::FromIntSize(_internal_$name$_size());
for (const auto& entry : _internal_$name$()) {
total_size += $Entry$::Funcs::ByteSizeLong(entry.first, entry.second);
}
)cc");
}
} // namespace } // namespace
std::unique_ptr<FieldGeneratorBase> MakeMapGenerator( std::unique_ptr<FieldGeneratorBase> MakeMapGenerator(
const FieldDescriptor* desc, const Options& options, const FieldDescriptor* desc, const Options& options,
MessageSCCAnalyzer* scc) { MessageSCCAnalyzer* scc) {
return std::make_unique<MapFieldGenerator>(desc, options, scc); return std::make_unique<Map>(desc, options, scc);
} }
} // namespace cpp } // namespace cpp

Loading…
Cancel
Save