diff options
author | Feng Xiao <xfxyjwf@gmail.com> | 2018-08-08 17:00:41 -0700 |
---|---|---|
committer | Feng Xiao <xfxyjwf@gmail.com> | 2018-08-08 17:00:41 -0700 |
commit | 6bbe197e9c1b6fc38cbdc45e3bf83fa7ced792a3 (patch) | |
tree | e575738adf52d24b883cca5e8928a5ded31caba1 /src/google/protobuf/compiler/cpp | |
parent | e7746f487cb9cca685ffb1b3d7dccc5554b618a4 (diff) | |
download | protobuf-6bbe197e9c1b6fc38cbdc45e3bf83fa7ced792a3.tar.gz protobuf-6bbe197e9c1b6fc38cbdc45e3bf83fa7ced792a3.tar.bz2 protobuf-6bbe197e9c1b6fc38cbdc45e3bf83fa7ced792a3.zip |
Down-integrate from google3.
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
36 files changed, 6508 insertions, 5187 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index 24f1fe45..4c135649 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -32,7 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // -// This test insures that google/protobuf/descriptor.pb.{h,cc} match exactly +// This test insures that net/proto2/proto/descriptor.pb.{h,cc} match exactly // what would be generated by the protocol compiler. These files are not // generated automatically at build time because they are compiled into the // protocol compiler itself. So, if they were auto-generated, you'd have a @@ -47,6 +47,7 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <google/protobuf/compiler/importer.h> +#include <google/protobuf/test_util2.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/stubs/substitute.h> @@ -83,9 +84,7 @@ class MockErrorCollector : public MultiFileErrorCollector { class MockGeneratorContext : public GeneratorContext { public: MockGeneratorContext() {} - ~MockGeneratorContext() { - STLDeleteValues(&files_); - } + ~MockGeneratorContext() { STLDeleteValues(&files_); } void ExpectFileMatches(const string& virtual_filename, const string& physical_filename) { @@ -95,9 +94,11 @@ class MockGeneratorContext : public GeneratorContext { string actual_contents; GOOGLE_CHECK_OK( - File::GetContentsAsText(TestSourceDir() + "/" + physical_filename, - &actual_contents, true)); - EXPECT_TRUE(actual_contents == *expected_contents) + File::GetContents(TestUtil::TestSourceDir() + "/" + physical_filename, + &actual_contents, true)) + << physical_filename; + CleanStringLineEndings(&actual_contents, false); + EXPECT_EQ(*expected_contents, actual_contents) << physical_filename << " needs to be regenerated. Please run " "generate_descriptor_proto.sh. " @@ -136,11 +137,11 @@ TEST(BootstrapTest, GeneratedFilesMatch) { "net/proto2/z_generated_example/test_messages_proto2"; rpath_map["third_party/protobuf/src/google/protobuf/test_messages_proto3"] = "net/proto2/z_generated_example/test_messages_proto3"; - rpath_map["google/protobuf/proto2_weak"] = + rpath_map["net/proto2/internal/proto2_weak"] = "net/proto2/z_generated_example/proto2_weak"; DiskSourceTree source_tree; - source_tree.MapPath("", TestSourceDir()); + source_tree.MapPath("", TestUtil::TestSourceDir()); for (auto file_parameter : test_protos) { MockErrorCollector error_collector; diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 0d6a9e24..39fe9e68 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -46,7 +46,7 @@ namespace cpp { namespace { // The GOOGLE_ARRAYSIZE constant is the max enum value plus 1. If the max enum value -// is ::google::protobuf::kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the +// is kint32max, GOOGLE_ARRAYSIZE will overflow. In such cases we should omit the // generation of the GOOGLE_ARRAYSIZE constant. bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) { int32 max_value = descriptor->value(0)->number(); @@ -55,61 +55,53 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) { max_value = descriptor->value(i)->number(); } } - return max_value != ::google::protobuf::kint32max; + return max_value != kint32max; } } // namespace EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, + const std::map<string, string>& vars, const Options& options) - : descriptor_(descriptor), - classname_(ClassName(descriptor, false)), - options_(options), - generate_array_size_(ShouldGenerateArraySize(descriptor)) { + : descriptor_(descriptor), + classname_(ClassName(descriptor, false)), + options_(options), + generate_array_size_(ShouldGenerateArraySize(descriptor)), + variables_(vars) { + variables_["classname"] = classname_; + variables_["classtype"] = QualifiedClassName(descriptor_); + variables_["short_name"] = descriptor_->name(); + variables_["enumbase"] = options_.proto_h ? " : int" : ""; + variables_["nested_name"] = descriptor_->name(); + variables_["constexpr"] = options_.proto_h ? "constexpr" : ""; + variables_["prefix"] = + (descriptor_->containing_type() == NULL) ? "" : classname_ + "_"; } EnumGenerator::~EnumGenerator() {} -void EnumGenerator::FillForwardDeclaration( - std::map<string, const EnumDescriptor*>* enum_names) { - if (!options_.proto_h) { - return; - } - (*enum_names)[classname_] = descriptor_; -} - void EnumGenerator::GenerateDefinition(io::Printer* printer) { - std::map<string, string> vars; - vars["classname"] = classname_; - vars["short_name"] = descriptor_->name(); - vars["enumbase"] = options_.proto_h ? " : int" : ""; - // These variables are placeholders to pick out the beginning and ends of - // identifiers for annotations (when doing so with existing variables would - // be ambiguous or impossible). They should never be set to anything but the - // empty string. - vars["{"] = ""; - vars["}"] = ""; - - printer->Print(vars, "enum $classname$$enumbase$ {\n"); - printer->Annotate("classname", descriptor_); - printer->Indent(); + Formatter format(printer, variables_); + format("enum ${1$$classname$$}$$enumbase$ {\n", descriptor_); + format.Indent(); const EnumValueDescriptor* min_value = descriptor_->value(0); const EnumValueDescriptor* max_value = descriptor_->value(0); for (int i = 0; i < descriptor_->value_count(); i++) { - vars["name"] = EnumValueName(descriptor_->value(i)); + auto format_value = format; + format_value.Set("name", EnumValueName(descriptor_->value(i))); // In C++, an value of -2147483648 gets interpreted as the negative of // 2147483648, and since 2147483648 can't fit in an integer, this produces a // compiler warning. This works around that issue. - vars["number"] = Int32ToString(descriptor_->value(i)->number()); - vars["prefix"] = (descriptor_->containing_type() == NULL) ? - "" : classname_ + "_"; - vars["deprecation"] = descriptor_->value(i)->options().deprecated() ? - " PROTOBUF_DEPRECATED" : ""; + format_value.Set("number", Int32ToString(descriptor_->value(i)->number())); + format_value.Set( + "deprecation", + DeprecatedAttribute(options_, + descriptor_->value(i)->options().deprecated())); - if (i > 0) printer->Print(",\n"); - printer->Print(vars, "${$$prefix$$name$$}$$deprecation$ = $number$"); - printer->Annotate("{", "}", descriptor_->value(i)); + if (i > 0) format_value(",\n"); + format_value("${1$$prefix$$name$$}$ $deprecation$= $number$", + descriptor_->value(i)); if (descriptor_->value(i)->number() < min_value->number()) { min_value = descriptor_->value(i); @@ -122,153 +114,163 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { // For new enum semantics: generate min and max sentinel values equal to // INT32_MIN and INT32_MAX - if (descriptor_->value_count() > 0) printer->Print(",\n"); - printer->Print(vars, - "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,\n" - "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max"); + if (descriptor_->value_count() > 0) format(",\n"); + format( + "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = " + "std::numeric_limits<$int32$>::min(),\n" + "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = " + "std::numeric_limits<$int32$>::max()"); } - printer->Outdent(); - printer->Print("\n};\n"); + format.Outdent(); + format("\n};\n"); - vars["min_name"] = EnumValueName(min_value); - vars["max_name"] = EnumValueName(max_value); - - if (options_.dllexport_decl.empty()) { - vars["dllexport"] = ""; - } else { - vars["dllexport"] = options_.dllexport_decl + " "; - } - - printer->Print(vars, - "$dllexport$bool $classname$_IsValid(int value);\n" - "const $classname$ ${$$prefix$$short_name$_MIN$}$ = " - "$prefix$$min_name$;\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(vars, - "const $classname$ ${$$prefix$$short_name$_MAX$}$ = " - "$prefix$$max_name$;\n"); - printer->Annotate("{", "}", descriptor_); + format( + "$dllexport_decl $bool $classname$_IsValid(int value);\n" + "const $classname$ ${1$$prefix$$short_name$_MIN$}$ = " + "$prefix$$2$;\n" + "const $classname$ ${1$$prefix$$short_name$_MAX$}$ = " + "$prefix$$3$;\n", + descriptor_, EnumValueName(min_value), EnumValueName(max_value)); if (generate_array_size_) { - printer->Print(vars, - "const int ${$$prefix$$short_name$_ARRAYSIZE$}$ = " - "$prefix$$short_name$_MAX + 1;\n\n"); - printer->Annotate("{", "}", descriptor_); + format( + "const int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = " + "$prefix$$short_name$_MAX + 1;\n\n", + descriptor_); } if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print(vars, - "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n"); + format( + "$dllexport_decl $const ::$proto_ns$::EnumDescriptor* " + "$classname$_descriptor();\n"); // The _Name and _Parse methods - printer->Print( - vars, - "inline const ::std::string& $classname$_Name($classname$ value) {\n" - " return ::google::protobuf::internal::NameOfEnum(\n" - " $classname$_descriptor(), value);\n" + if (options_.opensource_runtime) { + // TODO(haberman): consider removing this in favor of the stricter + // version below. Would this break our compatibility guarantees? + format( + "inline const $string$& $classname$_Name($classname$ value) {\n" + " return ::$proto_ns$::internal::NameOfEnum(\n" + " $classname$_descriptor(), value);\n" + "}\n"); + } else { + // Support a stricter, type-checked enum-to-string method that + // statically checks whether the parameter is the exact enum type or is + // an integral type. + format( + "template<typename T>\n" + "inline const $string$& $classname$_Name(T enum_t_value) {\n" + " static_assert(::std::is_same<T, $classname$>::value ||\n" + " ::std::is_integral<T>::value,\n" + " \"Incorrect type passed to function $classname$_Name.\");\n" + " return ::$proto_ns$::internal::NameOfEnum(\n" + " $classname$_descriptor(), enum_t_value);\n" + "}\n"); + } + format( + "inline bool $classname$_Parse(\n" + " const $string$& name, $classname$* value) {\n" + " return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n" + " $classname$_descriptor(), name, value);\n" "}\n"); - printer->Print(vars, - "inline bool $classname$_Parse(\n" - " const ::std::string& name, $classname$* value) {\n" - " return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n" - " $classname$_descriptor(), name, value);\n" - "}\n"); } } -void EnumGenerator:: -GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { - printer->Print( - "template <> struct is_proto_enum< $classname$> : ::std::true_type " - "{};\n", - "classname", ClassName(descriptor_, true)); +void EnumGenerator::GenerateGetEnumDescriptorSpecializations( + io::Printer* printer) { + Formatter format(printer, variables_); + format( + "template <> struct is_proto_enum< $classtype$> : ::std::true_type " + "{};\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print( - "template <>\n" - "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n" - " return $classname$_descriptor();\n" - "}\n", - "classname", ClassName(descriptor_, true)); + format( + "template <>\n" + "inline const EnumDescriptor* GetEnumDescriptor< $classtype$>() {\n" + " return $classtype$_descriptor();\n" + "}\n"); } } -void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { - std::map<string, string> vars; - vars["nested_name"] = descriptor_->name(); - vars["classname"] = classname_; - vars["constexpr"] = options_.proto_h ? "constexpr " : ""; - vars["{"] = ""; - vars["}"] = ""; - printer->Print(vars, "typedef $classname$ $nested_name$;\n"); +void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const { + Formatter format(printer, variables_); + format("typedef $classname$ $nested_name$;\n"); for (int j = 0; j < descriptor_->value_count(); j++) { - vars["tag"] = EnumValueName(descriptor_->value(j)); - vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ? - "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : ""; - printer->Print(vars, - "$deprecated_attr$static $constexpr$const $nested_name$ ${$$tag$$}$ =\n" - " $classname$_$tag$;\n"); - printer->Annotate("{", "}", descriptor_->value(j)); + string deprecated_attr = DeprecatedAttribute( + options_, descriptor_->value(j)->options().deprecated()); + format( + "$1$static $constexpr $const $nested_name$ ${2$$3$$}$ =\n" + " $classname$_$3$;\n", + deprecated_attr, descriptor_->value(j), + EnumValueName(descriptor_->value(j))); } - printer->Print(vars, - "static inline bool $nested_name$_IsValid(int value) {\n" - " return $classname$_IsValid(value);\n" - "}\n" - "static const $nested_name$ ${$$nested_name$_MIN$}$ =\n" - " $classname$_$nested_name$_MIN;\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(vars, - "static const $nested_name$ ${$$nested_name$_MAX$}$ =\n" - " $classname$_$nested_name$_MAX;\n"); - printer->Annotate("{", "}", descriptor_); + format( + "static inline bool $nested_name$_IsValid(int value) {\n" + " return $classname$_IsValid(value);\n" + "}\n" + "static const $nested_name$ ${1$$nested_name$_MIN$}$ =\n" + " $classname$_$nested_name$_MIN;\n" + "static const $nested_name$ ${1$$nested_name$_MAX$}$ =\n" + " $classname$_$nested_name$_MAX;\n", + descriptor_); if (generate_array_size_) { - printer->Print(vars, - "static const int ${$$nested_name$_ARRAYSIZE$}$ =\n" - " $classname$_$nested_name$_ARRAYSIZE;\n"); - printer->Annotate("{", "}", descriptor_); + format( + "static const int ${1$$nested_name$_ARRAYSIZE$}$ =\n" + " $classname$_$nested_name$_ARRAYSIZE;\n", + descriptor_); } if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print(vars, - "static inline const ::google::protobuf::EnumDescriptor*\n" - "$nested_name$_descriptor() {\n" - " return $classname$_descriptor();\n" - "}\n"); - printer->Print(vars, - "static inline const ::std::string& " - "$nested_name$_Name($nested_name$ value) {" - "\n" - " return $classname$_Name(value);\n" - "}\n"); - printer->Print(vars, - "static inline bool $nested_name$_Parse(const ::std::string& name,\n" - " $nested_name$* value) {\n" - " return $classname$_Parse(name, value);\n" - "}\n"); + format( + "static inline const ::$proto_ns$::EnumDescriptor*\n" + "$nested_name$_descriptor() {\n" + " return $classname$_descriptor();\n" + "}\n"); + if (options_.opensource_runtime) { + // TODO(haberman): consider removing this in favor of the stricter + // version below. Would this break our compatibility guarantees? + format( + "static inline const $string$& " + "$nested_name$_Name($nested_name$ value) {" + "\n" + " return $classname$_Name(value);\n" + "}\n"); + } else { + // Support a stricter, type-checked enum-to-string method that + // statically checks whether the parameter is the exact enum type or is + // an integral type. + format( + "template<typename T>\n" + "static inline const $string$& $nested_name$_Name(T enum_t_value) {\n" + " static_assert(::std::is_same<T, $nested_name$>::value ||\n" + " ::std::is_integral<T>::value,\n" + " \"Incorrect type passed to function $nested_name$_Name.\");\n" + " return $classname$_Name(enum_t_value);\n" + "}\n"); + } + format( + "static inline bool $nested_name$_Parse(const $string$& name,\n" + " $nested_name$* value) {\n" + " return $classname$_Parse(name, value);\n" + "}\n"); } } void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { - std::map<string, string> vars; - vars["classname"] = classname_; - vars["index_in_metadata"] = SimpleItoa(idx); - vars["constexpr"] = options_.proto_h ? "constexpr " : ""; - vars["file_namespace"] = FileLevelNamespace(descriptor_->file()->name()); - + Formatter format(printer, variables_); if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print( - vars, - "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" - " $file_namespace$::protobuf_AssignDescriptorsOnce();\n" - " return " - "$file_namespace$::file_level_enum_descriptors[$index_in_metadata$];\n" - "}\n"); + format( + "const ::$proto_ns$::EnumDescriptor* $classname$_descriptor() {\n" + " ::$proto_ns$::internal::AssignDescriptors(&$assign_desc_table$);\n" + " return $file_level_enum_descriptors$[$1$];\n" + "}\n", + idx); } - printer->Print(vars, - "bool $classname$_IsValid(int value) {\n" - " switch (value) {\n"); + format( + "bool $classname$_IsValid(int value) {\n" + " switch (value) {\n"); // Multiple values may have the same number. Make sure we only cover // each number once by first constructing a set containing all valid @@ -280,44 +282,40 @@ void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { numbers.insert(value->number()); } - for (std::set<int>::iterator iter = numbers.begin(); - iter != numbers.end(); ++iter) { - printer->Print( - " case $number$:\n", - "number", Int32ToString(*iter)); + for (std::set<int>::iterator iter = numbers.begin(); iter != numbers.end(); + ++iter) { + format(" case $1$:\n", Int32ToString(*iter)); } - printer->Print(vars, - " return true;\n" - " default:\n" - " return false;\n" - " }\n" - "}\n" - "\n"); + format( + " return true;\n" + " default:\n" + " return false;\n" + " }\n" + "}\n" + "\n"); if (descriptor_->containing_type() != NULL) { + string parent = ClassName(descriptor_->containing_type(), false); // We need to "define" the static constants which were declared in the // header, to give the linker a place to put them. Or at least the C++ // standard says we have to. MSVC actually insists that we do _not_ define // them again in the .cc file, prior to VC++ 2015. - printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"); + format("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"); - vars["parent"] = ClassName(descriptor_->containing_type(), false); - vars["nested_name"] = descriptor_->name(); for (int i = 0; i < descriptor_->value_count(); i++) { - vars["value"] = EnumValueName(descriptor_->value(i)); - printer->Print(vars, - "$constexpr$const $classname$ $parent$::$value$;\n"); + format("$constexpr $const $classname$ $1$::$2$;\n", parent, + EnumValueName(descriptor_->value(i))); } - printer->Print(vars, - "const $classname$ $parent$::$nested_name$_MIN;\n" - "const $classname$ $parent$::$nested_name$_MAX;\n"); + format( + "const $classname$ $1$::$nested_name$_MIN;\n" + "const $classname$ $1$::$nested_name$_MAX;\n", + parent); if (generate_array_size_) { - printer->Print(vars, - "const int $parent$::$nested_name$_ARRAYSIZE;\n"); + format("const int $1$::$nested_name$_ARRAYSIZE;\n", parent); } - printer->Print("#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n"); + format("#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 0d2488a9..55e6b835 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -46,8 +46,10 @@ namespace protobuf { namespace io { class Printer; // printer.h } -} +} // namespace protobuf +} // namespace google +namespace google { namespace protobuf { namespace compiler { namespace cpp { @@ -55,20 +57,10 @@ namespace cpp { class EnumGenerator { public: // See generator.cc for the meaning of dllexport_decl. - EnumGenerator(const EnumDescriptor* descriptor, const Options& options); + EnumGenerator(const EnumDescriptor* descriptor, + const std::map<string, string>& vars, const Options& options); ~EnumGenerator(); - // Header stuff. - - // Fills the name to use when declaring the enum. This is for use when - // generating other .proto.h files. This code should be placed within the - // enum's package namespace, but NOT within any class, even for nested - // enums. A given key in enum_names will map from an enum class name to the - // EnumDescriptor that was responsible for its inclusion in the map. This can - // be used to associate the descriptor with the code generated for it. - void FillForwardDeclaration( - std::map<string, const EnumDescriptor*>* enum_names); - // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for // nested enums. @@ -82,7 +74,7 @@ class EnumGenerator { // symbols (e.g. the enum type name, all its values, etc.) into the class's // namespace. This should be placed inside the class definition in the // header. - void GenerateSymbolImports(io::Printer* printer); + void GenerateSymbolImports(io::Printer* printer) const; // Source file stuff. @@ -98,6 +90,8 @@ class EnumGenerator { // whether to generate the *_ARRAYSIZE constant. const bool generate_array_size_; + std::map<string, string> variables_; + friend class FileGenerator; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); }; @@ -105,6 +99,6 @@ class EnumGenerator { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 828d0be5..a406f2ee 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -61,457 +61,452 @@ void SetEnumVariables(const FieldDescriptor* descriptor, EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), descriptor_(descriptor) { + : FieldGenerator(descriptor, options) { SetEnumVariables(descriptor, &variables_, options); } EnumFieldGenerator::~EnumFieldGenerator() {} -void EnumFieldGenerator:: -GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, "int $name$_;\n"); +void EnumFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { + Formatter format(printer, variables_); + format("int $name$_;\n"); } -void EnumFieldGenerator:: -GenerateAccessorDeclarations(io::Printer* printer) const { - printer->Print(variables_, "$deprecated_attr$$type$ $name$() const;\n"); - printer->Annotate("name", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$set_$name$$}$($type$ value);\n"); - printer->Annotate("{", "}", descriptor_); +void EnumFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "$deprecated_attr$$type$ ${1$$name$$}$() const;\n" + "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n", + descriptor_); } -void EnumFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return static_cast< $type$ >($name$_);\n" - "}\n" - "inline void $classname$::set_$name$($type$ value) {\n"); +void EnumFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return static_cast< $type$ >($name$_);\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, - " assert($type$_IsValid(value));\n"); + format(" assert($type$_IsValid(value));\n"); } - printer->Print(variables_, - " $set_hasbit$\n" - " $name$_ = value;\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); + format( + " $set_hasbit$\n" + " $name$_ = value;\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); } -void EnumFieldGenerator:: -GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = $default$;\n"); +void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = $default$;\n"); } -void EnumFieldGenerator:: -GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, "set_$name$(from.$name$());\n"); +void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("set_$name$(from.$name$());\n"); } -void EnumFieldGenerator:: -GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "swap($name$_, other->$name$_);\n"); +void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("swap($name$_, other->$name$_);\n"); } -void EnumFieldGenerator:: -GenerateConstructorCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = $default$;\n"); +void EnumFieldGenerator::GenerateConstructorCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = $default$;\n"); } -void EnumFieldGenerator:: -GenerateCopyConstructorCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = from.$name$_;\n"); +void EnumFieldGenerator::GenerateCopyConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_ = from.$name$_;\n"); } -void EnumFieldGenerator:: -GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "int value = 0;\n" - "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" - " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" - " input, &value)));\n"); +void EnumFieldGenerator::GenerateMergeFromCodedStream( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "int value = 0;\n" + "DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n"); if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, - "set_$name$(static_cast< $type$ >(value));\n"); + format("set_$name$(static_cast< $type$ >(value));\n"); } else { - printer->Print(variables_, - "if ($type$_IsValid(value)) {\n" - " set_$name$(static_cast< $type$ >(value));\n"); + format( + "if ($type$_IsValid(value)) {\n" + " set_$name$(static_cast< $type$ >(value));\n"); if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(variables_, - "} else {\n" - " mutable_unknown_fields()->AddVarint(\n" - " $number$, static_cast< ::google::protobuf::uint64>(value));\n"); + format( + "} else {\n" + " mutable_unknown_fields()->AddVarint(\n" + " $number$, static_cast<$uint64$>(value));\n"); } else { - printer->Print( - "} else {\n" - " unknown_fields_stream.WriteVarint32($tag$u);\n" - " unknown_fields_stream.WriteVarint32(\n" - " static_cast< ::google::protobuf::uint32>(value));\n", - "tag", SimpleItoa(internal::WireFormat::MakeTag(descriptor_))); + format( + "} else {\n" + " unknown_fields_stream.WriteVarint32($1$u);\n" + " unknown_fields_stream.WriteVarint32(\n" + " static_cast<$uint32$>(value));\n", + internal::WireFormat::MakeTag(descriptor_)); } - printer->Print(variables_, - "}\n"); + format("}\n"); } } -void EnumFieldGenerator:: -GenerateSerializeWithCachedSizes(io::Printer* printer) const { - printer->Print(variables_, - "::google::protobuf::internal::WireFormatLite::WriteEnum(\n" - " $number$, this->$name$(), output);\n"); +void EnumFieldGenerator::GenerateSerializeWithCachedSizes( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "::$proto_ns$::internal::WireFormatLite::WriteEnum(\n" + " $number$, this->$name$(), output);\n"); } -void EnumFieldGenerator:: -GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - printer->Print(variables_, - "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n" - " $number$, this->$name$(), target);\n"); +void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n" + " $number$, this->$name$(), target);\n"); } -void EnumFieldGenerator:: -GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, - "total_size += $tag_size$ +\n" - " ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n"); +void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::EnumSize(this->$name$());\n"); } // =================================================================== -EnumOneofFieldGenerator:: -EnumOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : EnumFieldGenerator(descriptor, options) { +EnumOneofFieldGenerator::EnumOneofFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : EnumFieldGenerator(descriptor, options) { SetCommonOneofFieldVariables(descriptor, &variables_); } EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {} -void EnumOneofFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " if (has_$name$()) {\n" - " return static_cast< $type$ >($field_member$);\n" - " }\n" - " return static_cast< $type$ >($default$);\n" - "}\n" - "inline void $classname$::set_$name$($type$ value) {\n"); +void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " if (has_$name$()) {\n" + " return static_cast< $type$ >($field_member$);\n" + " }\n" + " return static_cast< $type$ >($default$);\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, - " assert($type$_IsValid(value));\n"); + format(" assert($type$_IsValid(value));\n"); } - printer->Print(variables_, - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " }\n" - " $field_member$ = value;\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); + format( + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " }\n" + " $field_member$ = value;\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); } -void EnumOneofFieldGenerator:: -GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$field_member$ = $default$;\n"); +void EnumOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); + format("$field_member$ = $default$;\n"); } -void EnumOneofFieldGenerator:: -GenerateSwappingCode(io::Printer* printer) const { +void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { // Don't print any swapping code. Swapping the union will swap this field. } -void EnumOneofFieldGenerator:: -GenerateConstructorCode(io::Printer* printer) const { - printer->Print(variables_, - "$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); +void EnumOneofFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); } // =================================================================== RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), descriptor_(descriptor) { + : FieldGenerator(descriptor, options) { SetEnumVariables(descriptor, &variables_, options); } RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} -void RepeatedEnumFieldGenerator:: -GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, - "::google::protobuf::RepeatedField<int> $name$_;\n"); +void RepeatedEnumFieldGenerator::GeneratePrivateMembers( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("::$proto_ns$::RepeatedField<int> $name$_;\n"); if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file(), options_)) { - printer->Print(variables_, - "mutable int _$name$_cached_byte_size_;\n"); + format("mutable std::atomic<int> _$name$_cached_byte_size_;\n"); } } -void RepeatedEnumFieldGenerator:: -GenerateAccessorDeclarations(io::Printer* printer) const { - printer->Print(variables_, - "$deprecated_attr$$type$ $name$(int index) const;\n"); - printer->Annotate("name", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$void ${$set_$name$$}$(int index, $type$ value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$add_$name$$}$($type$ value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$const ::google::protobuf::RepeatedField<int>& $name$() const;\n"); - printer->Annotate("name", descriptor_); - printer->Print(variables_, - "$deprecated_attr$::google::protobuf::RepeatedField<int>* " - "${$mutable_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); -} - -void RepeatedEnumFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return static_cast< $type$ >($name$_.Get(index));\n" - "}\n" - "inline void $classname$::set_$name$(int index, $type$ value) {\n"); +void RepeatedEnumFieldGenerator::GenerateAccessorDeclarations( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n" + "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedField<int>& " + "${1$$name$$}$() const;\n" + "$deprecated_attr$::$proto_ns$::RepeatedField<int>* " + "${1$mutable_$name$$}$();\n", + descriptor_); +} + +void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions( + io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return static_cast< $type$ >($name$_.Get(index));\n" + "}\n" + "inline void $classname$::set_$name$(int index, $type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, - " assert($type$_IsValid(value));\n"); + format(" assert($type$_IsValid(value));\n"); } - printer->Print(variables_, - " $name$_.Set(index, value);\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline void $classname$::add_$name$($type$ value) {\n"); + format( + " $name$_.Set(index, value);\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::add_$name$($type$ value) {\n"); if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, - " assert($type$_IsValid(value));\n"); + format(" assert($type$_IsValid(value));\n"); } - printer->Print(variables_, - " $name$_.Add(value);\n" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n" - "inline const ::google::protobuf::RepeatedField<int>&\n" - "$classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedField<int>*\n" - "$classname$::mutable_$name$() {\n" - " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$name$_;\n" - "}\n"); + format( + " $name$_.Add(value);\n" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + "}\n" + "inline const ::$proto_ns$::RepeatedField<int>&\n" + "$classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $name$_;\n" + "}\n" + "inline ::$proto_ns$::RepeatedField<int>*\n" + "$classname$::mutable_$name$() {\n" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return &$name$_;\n" + "}\n"); } -void RepeatedEnumFieldGenerator:: -GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); +void RepeatedEnumFieldGenerator::GenerateClearingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); } -void RepeatedEnumFieldGenerator:: -GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); +void RepeatedEnumFieldGenerator::GenerateMergingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); } -void RepeatedEnumFieldGenerator:: -GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n"); +void RepeatedEnumFieldGenerator::GenerateSwappingCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$name$_.InternalSwap(&other->$name$_);\n"); } -void RepeatedEnumFieldGenerator:: -GenerateConstructorCode(io::Printer* printer) const { +void RepeatedEnumFieldGenerator::GenerateConstructorCode( + io::Printer* printer) const { // Not needed for repeated fields. } -void RepeatedEnumFieldGenerator:: -GenerateMergeFromCodedStream(io::Printer* printer) const { +void RepeatedEnumFieldGenerator::GenerateMergeFromCodedStream( + io::Printer* printer) const { + Formatter format(printer, variables_); // Don't use ReadRepeatedPrimitive here so that the enum can be validated. - printer->Print(variables_, - "int value = 0;\n" - "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" - " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" - " input, &value)));\n"); + format( + "int value = 0;\n" + "DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n"); if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, - "add_$name$(static_cast< $type$ >(value));\n"); + format("add_$name$(static_cast< $type$ >(value));\n"); } else { - printer->Print(variables_, - "if ($type$_IsValid(value)) {\n" - " add_$name$(static_cast< $type$ >(value));\n"); + format( + "if ($type$_IsValid(value)) {\n" + " add_$name$(static_cast< $type$ >(value));\n"); if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(variables_, - "} else {\n" - " mutable_unknown_fields()->AddVarint(\n" - " $number$, static_cast< ::google::protobuf::uint64>(value));\n"); + format( + "} else {\n" + " mutable_unknown_fields()->AddVarint(\n" + " $number$, static_cast<$uint64$>(value));\n"); } else { - printer->Print( - "} else {\n" - " unknown_fields_stream.WriteVarint32(tag);\n" - " unknown_fields_stream.WriteVarint32(\n" - " static_cast< ::google::protobuf::uint32>(value));\n"); + format( + "} else {\n" + " unknown_fields_stream.WriteVarint32(tag);\n" + " unknown_fields_stream.WriteVarint32(\n" + " static_cast<$uint32$>(value));\n"); } - printer->Print("}\n"); + format("}\n"); } } -void RepeatedEnumFieldGenerator:: -GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { +void RepeatedEnumFieldGenerator::GenerateMergeFromCodedStreamWithPacking( + io::Printer* printer) const { + Formatter format(printer, variables_); if (!descriptor_->is_packed()) { - // This path is rarely executed, so we use a non-inlined implementation. + // This path is rarely executed, so we use a non-inlined implementation. if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, - "DO_((::google::protobuf::internal::" - "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n" - " input,\n" - " $number$,\n" - " NULL,\n" - " NULL,\n" - " this->mutable_$name$())));\n"); + format( + "DO_((::$proto_ns$::internal::" + "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n" + " input,\n" + " $number$,\n" + " NULL,\n" + " NULL,\n" + " this->mutable_$name$())));\n"); } else if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(variables_, - "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n" - " input,\n" - " $number$,\n" - " $type$_IsValid,\n" - " mutable_unknown_fields(),\n" - " this->mutable_$name$())));\n"); + format( + "DO_((::$proto_ns$::internal::WireFormat::" + "ReadPackedEnumPreserveUnknowns(\n" + " input,\n" + " $number$,\n" + " $type$_IsValid,\n" + " mutable_unknown_fields(),\n" + " this->mutable_$name$())));\n"); } else { - printer->Print(variables_, - "DO_((::google::protobuf::internal::" - "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n" - " input,\n" - " $number$,\n" - " $type$_IsValid,\n" - " &unknown_fields_stream,\n" - " this->mutable_$name$())));\n"); + format( + "DO_((::$proto_ns$::internal::" + "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n" + " input,\n" + " $number$,\n" + " $type$_IsValid,\n" + " &unknown_fields_stream,\n" + " this->mutable_$name$())));\n"); } } else { - printer->Print(variables_, - "::google::protobuf::uint32 length;\n" - "DO_(input->ReadVarint32(&length));\n" - "::google::protobuf::io::CodedInputStream::Limit limit = " - "input->PushLimit(static_cast<int>(length));\n" - "while (input->BytesUntilLimit() > 0) {\n" - " int value = 0;\n" - " DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" - " int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" - " input, &value)));\n"); + format( + "$uint32$ length;\n" + "DO_(input->ReadVarint32(&length));\n" + "::$proto_ns$::io::CodedInputStream::Limit limit = " + "input->PushLimit(static_cast<int>(length));\n" + "while (input->BytesUntilLimit() > 0) {\n" + " int value = 0;\n" + " DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n" + " int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n" + " input, &value)));\n"); if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { - printer->Print(variables_, - " add_$name$(static_cast< $type$ >(value));\n"); + format(" add_$name$(static_cast< $type$ >(value));\n"); } else { - printer->Print(variables_, - " if ($type$_IsValid(value)) {\n" - " add_$name$(static_cast< $type$ >(value));\n" - " } else {\n"); + format( + " if ($type$_IsValid(value)) {\n" + " add_$name$(static_cast< $type$ >(value));\n" + " } else {\n"); if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(variables_, - " mutable_unknown_fields()->AddVarint(\n" - " $number$, static_cast< ::google::protobuf::uint64>(value));\n"); + format( + " mutable_unknown_fields()->AddVarint(\n" + " $number$, static_cast<$uint64$>(value));\n"); } else { - printer->Print(variables_, - " unknown_fields_stream.WriteVarint32(tag);\n" - " unknown_fields_stream.WriteVarint32(\n" - " static_cast< ::google::protobuf::uint32>(value));\n"); + format( + " unknown_fields_stream.WriteVarint32(tag);\n" + " unknown_fields_stream.WriteVarint32(\n" + " static_cast<$uint32$>(value));\n"); } - printer->Print( - " }\n"); + format(" }\n"); } - printer->Print(variables_, - "}\n" - "input->PopLimit(limit);\n"); + format( + "}\n" + "input->PopLimit(limit);\n"); } } -void RepeatedEnumFieldGenerator:: -GenerateSerializeWithCachedSizes(io::Printer* printer) const { +void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizes( + io::Printer* printer) const { + Formatter format(printer, variables_); if (descriptor_->is_packed()) { // Write the tag and the size. - printer->Print(variables_, - "if (this->$name$_size() > 0) {\n" - " ::google::protobuf::internal::WireFormatLite::WriteTag(\n" - " $number$,\n" - " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" - " output);\n" - " output->WriteVarint32(\n" - " static_cast< ::google::protobuf::uint32>(_$name$_cached_byte_size_));\n" - "}\n"); + format( + "if (this->$name$_size() > 0) {\n" + " ::$proto_ns$::internal::WireFormatLite::WriteTag(\n" + " $number$,\n" + " " + "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" + " output);\n" + " output->WriteVarint32(_$name$_cached_byte_size_.load(\n" + " std::memory_order_relaxed));\n" + "}\n"); } - printer->Print(variables_, - "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"); + format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"); if (descriptor_->is_packed()) { - printer->Print(variables_, - " ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n" - " this->$name$(i), output);\n"); + format( + " ::$proto_ns$::internal::WireFormatLite::WriteEnumNoTag(\n" + " this->$name$(i), output);\n"); } else { - printer->Print(variables_, - " ::google::protobuf::internal::WireFormatLite::WriteEnum(\n" - " $number$, this->$name$(i), output);\n"); + format( + " ::$proto_ns$::internal::WireFormatLite::WriteEnum(\n" + " $number$, this->$name$(i), output);\n"); } - printer->Print("}\n"); + format("}\n"); } -void RepeatedEnumFieldGenerator:: -GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { +void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const { + Formatter format(printer, variables_); if (descriptor_->is_packed()) { // Write the tag and the size. - printer->Print(variables_, - "if (this->$name$_size() > 0) {\n" - " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n" - " $number$,\n" - " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" - " target);\n" - " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(" - " static_cast< ::google::protobuf::uint32>(\n" - " _$name$_cached_byte_size_), target);\n" - " target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n" - " this->$name$_, target);\n" - "}\n"); + format( + "if (this->$name$_size() > 0) {\n" + " target = ::$proto_ns$::internal::WireFormatLite::WriteTagToArray(\n" + " $number$,\n" + " " + "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" + " target);\n" + " target = ::$proto_ns$::io::CodedOutputStream::WriteVarint32ToArray(" + " _$name$_cached_byte_size_.load(std::memory_order_relaxed),\n" + " target);\n" + " target = " + "::$proto_ns$::internal::WireFormatLite::WriteEnumNoTagToArray(\n" + " this->$name$_, target);\n" + "}\n"); } else { - printer->Print(variables_, - "target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n" - " $number$, this->$name$_, target);\n"); + format( + "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n" + " $number$, this->$name$_, target);\n"); } } -void RepeatedEnumFieldGenerator:: -GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, - "{\n" - " size_t data_size = 0;\n" - " unsigned int count = static_cast<unsigned int>(this->$name$_size());"); - printer->Indent(); - printer->Print(variables_, +void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { + Formatter format(printer, variables_); + format( + "{\n" + " size_t data_size = 0;\n" + " unsigned int count = static_cast<unsigned int>(this->$name$_size());"); + format.Indent(); + format( "for (unsigned int i = 0; i < count; i++) {\n" - " data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n" + " data_size += ::$proto_ns$::internal::WireFormatLite::EnumSize(\n" " this->$name$(static_cast<int>(i)));\n" "}\n"); if (descriptor_->is_packed()) { - printer->Print(variables_, - "if (data_size > 0) {\n" - " total_size += $tag_size$ +\n" - " ::google::protobuf::internal::WireFormatLite::Int32Size(\n" - " static_cast< ::google::protobuf::int32>(data_size));\n" - "}\n" - "int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);\n" - "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - "_$name$_cached_byte_size_ = cached_size;\n" - "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" - "total_size += data_size;\n"); + format( + "if (data_size > 0) {\n" + " total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::Int32Size(\n" + " static_cast<$int32$>(data_size));\n" + "}\n" + "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n" + "_$name$_cached_byte_size_.store(cached_size,\n" + " std::memory_order_relaxed);\n" + "total_size += data_size;\n"); } else { - printer->Print(variables_, - "total_size += ($tag_size$UL * count) + data_size;\n"); + format("total_size += ($tag_size$UL * count) + data_size;\n"); } - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index d0e87b79..b43d402b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -63,10 +63,6 @@ class EnumFieldGenerator : public FieldGenerator { void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; - protected: - const FieldDescriptor* descriptor_; - std::map<string, string> variables_; - private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); }; @@ -109,15 +105,12 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; private: - const FieldDescriptor* descriptor_; - std::map<string, string> variables_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); }; } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index c416ba10..25bcc333 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -84,86 +84,88 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, break; default: type_traits_.append("PrimitiveTypeTraits< "); - type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type())); + type_traits_.append(PrimitiveTypeName(options_, descriptor_->cpp_type())); type_traits_.append(" >"); break; } + SetCommonVars(options, &variables_); + variables_["extendee"] = ExtendeeClassName(descriptor_); + variables_["type_traits"] = type_traits_; + string name = descriptor_->name(); + variables_["name"] = name; + variables_["constant_name"] = FieldConstantName(descriptor_); + variables_["field_type"] = + SimpleItoa(static_cast<int>(descriptor_->type())); + variables_["packed"] = descriptor_->options().packed() ? "true" : "false"; + + string scope = + IsScoped() ? ClassName(descriptor_->extension_scope(), false) + "::" : ""; + variables_["scope"] = scope; + string scoped_name = scope + name; + variables_["scoped_name"] = scoped_name; + variables_["number"] = SimpleItoa(descriptor_->number()); } ExtensionGenerator::~ExtensionGenerator() {} -void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { - std::map<string, string> vars; - vars["extendee" ] = ExtendeeClassName(descriptor_); - vars["number" ] = SimpleItoa(descriptor_->number()); - vars["type_traits" ] = type_traits_; - vars["name" ] = descriptor_->name(); - vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); - vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; - vars["constant_name"] = FieldConstantName(descriptor_); +bool ExtensionGenerator::IsScoped() const { + return descriptor_->extension_scope() != nullptr; +} + +void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) const { + Formatter format(printer, variables_); // If this is a class member, it needs to be declared "static". Otherwise, // it needs to be "extern". In the latter case, it also needs the DLL // export/import specifier. - if (descriptor_->extension_scope() == NULL) { - vars["qualifier"] = "extern"; + string qualifier; + if (!IsScoped()) { + qualifier = "extern"; if (!options_.dllexport_decl.empty()) { - vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"]; + qualifier = options_.dllexport_decl + " " + qualifier; } } else { - vars["qualifier"] = "static"; + qualifier = "static"; } - printer->Print(vars, - "static const int $constant_name$ = $number$;\n" - "$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" - " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" - " $name$;\n" - ); + format( + "static const int $constant_name$ = $number$;\n" + "$1$ ::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n" + " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n" + " $name$;\n", + qualifier); } void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { + Formatter format(printer, variables_); + string default_str; // If this is a class member, it needs to be declared in its class scope. - string scope = (descriptor_->extension_scope() == NULL) ? "" : - ClassName(descriptor_->extension_scope(), false) + "::"; - string name = scope + descriptor_->name(); - - std::map<string, string> vars; - vars["extendee" ] = ExtendeeClassName(descriptor_); - vars["type_traits" ] = type_traits_; - vars["name" ] = name; - vars["constant_name"] = FieldConstantName(descriptor_); - vars["default" ] = DefaultValue(descriptor_); - vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); - vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; - vars["scope" ] = scope; - if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { // We need to declare a global string which will contain the default value. // We cannot declare it at class scope because that would require exposing // it in the header which would be annoying for other reasons. So we // replace :: with _ in the name and declare it as a global. - string global_name = StringReplace(name, "::", "_", true); - vars["global_name"] = global_name; - printer->Print(vars, - "const ::std::string $global_name$_default($default$);\n"); - - // Update the default to refer to the string global. - vars["default"] = global_name + "_default"; + default_str = + StringReplace(variables_["scoped_name"], "::", "_", true) + "_default"; + format("const ::std::string $1$($2$);\n", default_str, + DefaultValue(options_, descriptor_)); + } else { + default_str = DefaultValue(options_, descriptor_); } // Likewise, class members need to declare the field constant variable. - if (descriptor_->extension_scope() != NULL) { - printer->Print(vars, - "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n" - "const int $scope$$constant_name$;\n" - "#endif\n"); + if (IsScoped()) { + format( + "#if !defined(_MSC_VER) || _MSC_VER >= 1900\n" + "const int $scope$$constant_name$;\n" + "#endif\n"); } - printer->Print(vars, - "::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" - " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" - " $name$($constant_name$, $default$);\n"); + format( + "::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n" + " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n" + " $scoped_name$($constant_name$, $1$);\n", + default_str); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h index 30236d71..c316f5da 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/src/google/protobuf/compiler/cpp/cpp_extension.h @@ -35,18 +35,22 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ +#include <map> #include <string> + #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { - class FieldDescriptor; // descriptor.h - namespace io { - class Printer; // printer.h - } +class FieldDescriptor; // descriptor.h +namespace io { +class Printer; // printer.h } +} // namespace protobuf +} // namespace google +namespace google { namespace protobuf { namespace compiler { namespace cpp { @@ -62,22 +66,26 @@ class ExtensionGenerator { ~ExtensionGenerator(); // Header stuff. - void GenerateDeclaration(io::Printer* printer); + void GenerateDeclaration(io::Printer* printer) const; // Source file stuff. void GenerateDefinition(io::Printer* printer); + bool IsScoped() const; + private: const FieldDescriptor* descriptor_; string type_traits_; Options options_; + std::map<string, string> variables_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); }; } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 0de20f84..582da4ae 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -38,6 +38,7 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_primitive_field.h> #include <google/protobuf/compiler/cpp/cpp_string_field.h> + #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/cpp/cpp_enum_field.h> @@ -58,6 +59,7 @@ using internal::WireFormat; void SetCommonFieldVariables(const FieldDescriptor* descriptor, std::map<string, string>* variables, const Options& options) { + SetCommonVars(options, variables); (*variables)["ns"] = Namespace(descriptor); (*variables)["name"] = FieldName(descriptor); (*variables)["index"] = SimpleItoa(descriptor->index()); @@ -67,20 +69,17 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["field_member"] = FieldName(descriptor) + "_"; (*variables)["tag_size"] = SimpleItoa( - WireFormat::TagSize(descriptor->number(), descriptor->type())); - (*variables)["deprecation"] = descriptor->options().deprecated() - ? " PROTOBUF_DEPRECATED" : ""; - (*variables)["deprecated_attr"] = descriptor->options().deprecated() - ? "GOOGLE_PROTOBUF_DEPRECATED_ATTR " : ""; + WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["deprecated_attr"] = + DeprecatedAttribute(options, descriptor->options().deprecated()); + (*variables)["set_hasbit"] = ""; + (*variables)["clear_hasbit"] = ""; if (HasFieldPresence(descriptor->file())) { - (*variables)["set_hasbit"] = - "set_has_" + FieldName(descriptor) + "();"; - (*variables)["clear_hasbit"] = - "clear_has_" + FieldName(descriptor) + "();"; + (*variables)["set_hasbit_io"] = + "HasBitSetters::set_has_" + FieldName(descriptor) + "(this);"; } else { - (*variables)["set_hasbit"] = ""; - (*variables)["clear_hasbit"] = ""; + (*variables)["set_hasbit_io"] = ""; } // These variables are placeholders to pick out the beginning and ends of @@ -91,11 +90,24 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["}"] = ""; } +void FieldGenerator::SetHasBitIndex(int32 has_bit_index) { + if (!HasFieldPresence(descriptor_->file()) || has_bit_index == -1) { + return; + } + variables_["set_hasbit"] = StrCat( + "_has_bits_[", has_bit_index / 32, "] |= 0x", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); + variables_["clear_hasbit"] = StrCat( + "_has_bits_[", has_bit_index / 32, "] &= ~0x", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); +} + void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, std::map<string, string>* variables) { const string prefix = descriptor->containing_oneof()->name() + "_."; (*variables)["oneof_name"] = descriptor->containing_oneof()->name(); - (*variables)["field_member"] = StrCat(prefix, (*variables)["name"], "_"); + (*variables)["field_member"] = + StrCat(prefix, (*variables)["name"], "_"); } FieldGenerator::~FieldGenerator() {} @@ -114,7 +126,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Options& options, - SCCAnalyzer* scc_analyzer) + MessageSCCAnalyzer* scc_analyzer) : descriptor_(descriptor), options_(options), field_generators_(descriptor->field_count()) { @@ -125,9 +137,22 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, } } -FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, - const Options& options, - SCCAnalyzer* scc_analyzer) { +FieldGenerator* FieldGeneratorMap::MakeGoogleInternalGenerator( + const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + + return nullptr; +} + +FieldGenerator* FieldGeneratorMap::MakeGenerator( + const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + FieldGenerator* generator = + MakeGoogleInternalGenerator(field, options, scc_analyzer); + if (generator) { + return generator; + } + if (field->is_repeated()) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: @@ -138,11 +163,7 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, scc_analyzer); } case FieldDescriptor::CPPTYPE_STRING: - switch (field->options().ctype()) { - default: // RepeatedStringFieldGenerator handles unknown ctypes. - case FieldOptions::STRING: - return new RepeatedStringFieldGenerator(field, options); - } + return new RepeatedStringFieldGenerator(field, options); case FieldDescriptor::CPPTYPE_ENUM: return new RepeatedEnumFieldGenerator(field, options); default: @@ -153,11 +174,7 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, case FieldDescriptor::CPPTYPE_MESSAGE: return new MessageOneofFieldGenerator(field, options, scc_analyzer); case FieldDescriptor::CPPTYPE_STRING: - switch (field->options().ctype()) { - default: // StringOneofFieldGenerator handles unknown ctypes. - case FieldOptions::STRING: - return new StringOneofFieldGenerator(field, options); - } + return new StringOneofFieldGenerator(field, options); case FieldDescriptor::CPPTYPE_ENUM: return new EnumOneofFieldGenerator(field, options); default: @@ -168,11 +185,7 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, case FieldDescriptor::CPPTYPE_MESSAGE: return new MessageFieldGenerator(field, options, scc_analyzer); case FieldDescriptor::CPPTYPE_STRING: - switch (field->options().ctype()) { - default: // StringFieldGenerator handles unknown ctypes. - case FieldOptions::STRING: - return new StringFieldGenerator(field, options); - } + return new StringFieldGenerator(field, options); case FieldDescriptor::CPPTYPE_ENUM: return new EnumFieldGenerator(field, options); default: diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 8cdbe886..4561b33e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -45,11 +45,13 @@ namespace google { namespace protobuf { - namespace io { - class Printer; // printer.h - } +namespace io { +class Printer; // printer.h } +} // namespace protobuf +} // namespace google +namespace google { namespace protobuf { namespace compiler { namespace cpp { @@ -67,7 +69,9 @@ void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, class FieldGenerator { public: - explicit FieldGenerator(const Options& options) : options_(options) {} + explicit FieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : descriptor_(descriptor), options_(options) {} virtual ~FieldGenerator(); // Generate lines of code declaring members fields of the message class @@ -95,17 +99,27 @@ class FieldGenerator { virtual void GenerateNonInlineAccessorDefinitions( io::Printer* /*printer*/) const {} + // Generate declarations of accessors that are for internal purposes only. + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateInternalAccessorDefinitions( + io::Printer* /*printer*/) const {} + + // Generate definitions of accessors that are for internal purposes only. + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateInternalAccessorDeclarations( + io::Printer* /*printer*/) const {} + // Generate lines of code (statements, not declarations) which clear the // field. This is used to define the clear_$name$() method virtual void GenerateClearingCode(io::Printer* printer) const = 0; - // Generate lines of code (statements, not declarations) which clear the field - // as part of the Clear() method for the whole message. For message types - // which have field presence bits, MessageGenerator::GenerateClear will have - // already checked the presence bits. + // Generate lines of code (statements, not declarations) which clear the + // field as part of the Clear() method for the whole message. For message + // types which have field presence bits, MessageGenerator::GenerateClear + // will have already checked the presence bits. // - // Since most field types can re-use GenerateClearingCode, this method is not - // pure virtual. + // Since most field types can re-use GenerateClearingCode, this method is + // not pure virtual. virtual void GenerateMessageClearingCode(io::Printer* printer) const { GenerateClearingCode(printer); } @@ -140,17 +154,17 @@ class FieldGenerator { // Generate a manual destructor invocation for use when the message is on an // arena. The code that this method generates will be executed inside a - // shared-for-the-whole-message-class method registered with OwnDestructor(). - // The method should return |true| if it generated any code that requires a - // call; this allows the message generator to eliminate the OwnDestructor() - // registration if no fields require it. + // shared-for-the-whole-message-class method registered with + // OwnDestructor(). The method should return |true| if it generated any code + // that requires a call; this allows the message generator to eliminate the + // OwnDestructor() registration if no fields require it. virtual bool GenerateArenaDestructorCode(io::Printer* printer) const { return false; } // Generate code that allocates the fields's default instance. - virtual void GenerateDefaultInstanceAllocator(io::Printer* /*printer*/) - const {} + virtual void GenerateDefaultInstanceAllocator( + io::Printer* /*printer*/) const {} // Generate lines to decode this field, which will be placed inside the // message's MergeFromCodedStream() method. @@ -162,8 +176,8 @@ class FieldGenerator { // Generate lines to decode this field from a packed value, which will be // placed inside the message's MergeFromCodedStream() method. - virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) - const; + virtual void GenerateMergeFromCodedStreamWithPacking( + io::Printer* printer) const; // Generate lines to serialize this field, which are placed within the // message's SerializeWithCachedSizes() method. @@ -184,8 +198,12 @@ class FieldGenerator { virtual uint32 CalculateFieldTag() const { return 0; } virtual bool IsInlined() const { return false; } + void SetHasBitIndex(int32 has_bit_index); + protected: + const FieldDescriptor* descriptor_; const Options& options_; + std::map<string, string> variables_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); @@ -195,19 +213,28 @@ class FieldGenerator { class FieldGeneratorMap { public: FieldGeneratorMap(const Descriptor* descriptor, const Options& options, - SCCAnalyzer* scc_analyzer); + MessageSCCAnalyzer* scc_analyzer); ~FieldGeneratorMap(); const FieldGenerator& get(const FieldDescriptor* field) const; + void SetHasBitIndices(const std::vector<int>& has_bit_indices_) { + for (int i = 0; i < descriptor_->field_count(); ++i) { + field_generators_[i]->SetHasBitIndex(has_bit_indices_[i]); + } + } + private: const Descriptor* descriptor_; const Options& options_; std::vector<std::unique_ptr<FieldGenerator>> field_generators_; + static FieldGenerator* MakeGoogleInternalGenerator( + const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); static FieldGenerator* MakeGenerator(const FieldDescriptor* field, const Options& options, - SCCAnalyzer* scc_analyzer); + MessageSCCAnalyzer* scc_analyzer); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); }; @@ -215,6 +242,6 @@ class FieldGeneratorMap { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 02f360bb..414da2f8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -44,72 +44,79 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_message.h> #include <google/protobuf/compiler/cpp/cpp_service.h> +#include <google/protobuf/compiler/scc.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> + +#include <google/protobuf/port_def.inc> + namespace google { namespace protobuf { namespace compiler { namespace cpp { FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) - : file_(file), - options_(options), - scc_analyzer_(options), - enum_generators_owner_( - new std::unique_ptr<EnumGenerator>[file->enum_type_count()]), - service_generators_owner_( - new std::unique_ptr<ServiceGenerator>[file->service_count()]), - extension_generators_owner_( - new std::unique_ptr<ExtensionGenerator>[file->extension_count()]) { + : file_(file), options_(options), scc_analyzer_(options) { + // These variables are the same on a file level + SetCommonVars(options, &variables_); + variables_["dllexport_decl"] = options.dllexport_decl; + variables_["tablename"] = UniqueName("TableStruct", file_, options_); + variables_["assign_desc_table"] = + UniqueName("assign_descriptors_table", file_, options_); + variables_["file_level_metadata"] = + UniqueName("file_level_metadata", file_, options_); + variables_["file_level_enum_descriptors"] = + UniqueName("file_level_enum_descriptors", file_, options_); + variables_["file_level_service_descriptors"] = + UniqueName("file_level_service_descriptors", file_, options_); + variables_["add_descriptors"] = UniqueName("AddDescriptors", file_, options_); + variables_["filename"] = file_->name(); + variables_["package_ns"] = Namespace(file_); + variables_["init_defaults"] = UniqueName("InitDefaults", file_, options_); + std::vector<const Descriptor*> msgs = FlattenMessagesInFile(file); for (int i = 0; i < msgs.size(); i++) { // Deleted in destructor MessageGenerator* msg_gen = - new MessageGenerator(msgs[i], i, options, &scc_analyzer_); - message_generators_.push_back(msg_gen); + new MessageGenerator(msgs[i], variables_, i, options, &scc_analyzer_); + message_generators_.emplace_back(msg_gen); msg_gen->AddGenerators(&enum_generators_, &extension_generators_); } for (int i = 0; i < file->enum_type_count(); i++) { - enum_generators_owner_[i].reset( - new EnumGenerator(file->enum_type(i), options)); - enum_generators_.push_back(enum_generators_owner_[i].get()); + enum_generators_.emplace_back( + new EnumGenerator(file->enum_type(i), variables_, options)); } for (int i = 0; i < file->service_count(); i++) { - service_generators_owner_[i].reset( - new ServiceGenerator(file->service(i), options)); - service_generators_.push_back(service_generators_owner_[i].get()); + service_generators_.emplace_back( + new ServiceGenerator(file->service(i), variables_, options)); } if (HasGenericServices(file_, options_)) { for (int i = 0; i < service_generators_.size(); i++) { service_generators_[i]->index_in_metadata_ = i; } } - for (int i = 0; i < file->extension_count(); i++) { - extension_generators_owner_[i].reset( + extension_generators_.emplace_back( new ExtensionGenerator(file->extension(i), options)); - extension_generators_.push_back(extension_generators_owner_[i].get()); } - - - package_parts_ = Split(file_->package(), ".", true); -} - -FileGenerator::~FileGenerator() { - for (int i = 0; i < message_generators_.size(); i++) { - delete message_generators_[i]; + for (int i = 0; i < file->weak_dependency_count(); ++i) { + weak_deps_.insert(file->weak_dependency(i)); } } +FileGenerator::~FileGenerator() = default; + void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { + Formatter format(printer, variables_); // Only do this for protobuf's own types. There are some google3 protos using // macros as field names and the generated code compiles after the macro // expansion. Undefing these macros actually breaks such code. - if (file_->name() != "google/protobuf/compiler/plugin.proto") { + if (file_->name() != "net/proto2/compiler/proto/plugin.proto" && + file_->name() != "google/protobuf/compiler/plugin.proto") { return; } std::vector<string> names_to_undef; @@ -126,70 +133,89 @@ void FileGenerator::GenerateMacroUndefs(io::Printer* printer) { } } for (int i = 0; i < names_to_undef.size(); ++i) { - printer->Print( - "#ifdef $name$\n" - "#undef $name$\n" + format( + "#ifdef $1$\n" + "#undef $1$\n" "#endif\n", - "name", names_to_undef[i]); + names_to_undef[i]); } } void FileGenerator::GenerateHeader(io::Printer* printer) { - printer->Print( - "// @@protoc_insertion_point(includes)\n"); + Formatter format(printer, variables_); - printer->Print("#define PROTOBUF_INTERNAL_EXPORT_$filename$ $export$\n", - "filename", FileLevelNamespace(file_), - "export", options_.dllexport_decl); + // port_def.inc must be included after all other includes. + IncludeFile("net/proto2/public/port_def.inc", printer); + format("#define $1$$ dllexport_decl$\n", + UniqueName("PROTOBUF_INTERNAL_EXPORT", file_, options_)); GenerateMacroUndefs(printer); + if (IsProto2MessageSetFile(file_, options_)) { + // Proto2 MessageSet overrides GetMapper() so we forward declare TagMapper + // to avoid inclusion of "tagmapper.h". + format("class TagMapper;\n"); + } + + if (!options_.opensource_runtime) { + // EmbeddedMessageHolder is a proxy class to provide access into arena + // constructors for proto1 message objects. + // See net/proto/proto_arena_internal.h + format( + "namespace proto {\n" + "namespace internal {\n" + "template <typename T> struct EmbeddedMessageHolder;\n" + "} // namespace internal\n" + "} // namespace proto\n"); + } GenerateGlobalStateFunctionDeclarations(printer); GenerateForwardDeclarations(printer); { - NamespaceOpener ns(Namespace(file_), printer); + NamespaceOpener ns(Namespace(file_), format); - printer->Print("\n"); + format("\n"); GenerateEnumDefinitions(printer); - printer->Print(kThickSeparator); - printer->Print("\n"); + format(kThickSeparator); + format("\n"); GenerateMessageDefinitions(printer); - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); + format("\n"); + format(kThickSeparator); + format("\n"); GenerateServiceDefinitions(printer); GenerateExtensionIdentifiers(printer); - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); + format("\n"); + format(kThickSeparator); + format("\n"); GenerateInlineFunctionDefinitions(printer); - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n" - "\n"); + format( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n" + "\n"); } // We need to specialize some templates in the ::google::protobuf namespace: GenerateProto2NamespaceEnumSpecializations(printer); - printer->Print( - "\n" - "// @@protoc_insertion_point(global_scope)\n" - "\n"); + format( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + IncludeFile("net/proto2/public/port_undef.inc", printer); } void FileGenerator::GenerateProtoHeader(io::Printer* printer, const string& info_path) { + Formatter format(printer, variables_); if (!options_.proto_h) { return; } @@ -197,18 +223,35 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer, string filename_identifier = FilenameIdentifier(file_->name()); GenerateTopHeaderGuard(printer, filename_identifier); + if (!options_.opensource_runtime) { + format( + "#ifdef SWIG\n" + "#error \"Do not SWIG-wrap protobufs.\"\n" + "#endif // SWIG\n" + "\n"); + } + + if (IsBootstrapProto(options_, file_)) { + format("// IWYU pragma: private, include \"$1$.proto.h\"\n\n", + StripProto(file_->name())); + } GenerateLibraryIncludes(printer); for (int i = 0; i < file_->public_dependency_count(); i++) { const FileDescriptor* dep = file_->public_dependency(i); const char* extension = ".proto.h"; + // The proto1 compiler only generates .pb.h files, so even if we are + // running in proto-h mode, we can only use the .pb.h. + if (IsProto1(dep, options_)) { + extension = ".pb.h"; + } string dependency = StripProto(dep->name()) + extension; - printer->Print( - "#include \"$dependency$\" // IWYU pragma: export\n", - "dependency", dependency); + format("#include \"$1$\"\n", dependency); } + format("// @@protoc_insertion_point(includes)\n"); + GenerateMetadataPragma(printer, info_path); GenerateHeader(printer); @@ -218,78 +261,147 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer, void FileGenerator::GeneratePBHeader(io::Printer* printer, const string& info_path) { + Formatter format(printer, variables_); string filename_identifier = FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : "")); GenerateTopHeaderGuard(printer, filename_identifier); if (options_.proto_h) { string target_basename = StripProto(file_->name()); - printer->Print("#include \"$basename$.proto.h\" // IWYU pragma: export\n", - "basename", target_basename); + if (!options_.opensource_runtime) { + GetBootstrapBasename(options_, target_basename, &target_basename); + } + format("#include \"$1$.proto.h\" // IWYU pragma: export\n", + target_basename); } else { GenerateLibraryIncludes(printer); } - GenerateDependencyIncludes(printer); + if (options_.transitive_pb_h) { + GenerateDependencyIncludes(printer); + } + + // This is unfortunately necessary for some plugins. I don't see why we + // need two of the same insertion points. + // TODO(gerbens) remove this. + format("// @@protoc_insertion_point(includes)\n"); + GenerateMetadataPragma(printer, info_path); if (!options_.proto_h) { GenerateHeader(printer); } else { - // This is unfortunately necessary for some plugins. I don't see why we - // need two of the same insertion points. - // TODO(gerbens) remove this. - printer->Print( - "// @@protoc_insertion_point(includes)\n"); { - NamespaceOpener ns(Namespace(file_), printer); - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); + NamespaceOpener ns(Namespace(file_), format); + format( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); } - printer->Print( - "\n" - "// @@protoc_insertion_point(global_scope)\n" - "\n"); + format( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); } GenerateBottomHeaderGuard(printer, filename_identifier); } +void FileGenerator::DoIncludeFile(const string& google3_name, bool do_export, + io::Printer* printer) { + Formatter format(printer, variables_); + const string prefix = "net/proto2/"; + GOOGLE_CHECK(google3_name.find(prefix) == 0) << google3_name; + + if (options_.opensource_runtime) { + string path = google3_name.substr(prefix.size()); + + path = StringReplace(path, "internal/", "", false); + path = StringReplace(path, "proto/", "", false); + path = StringReplace(path, "public/", "", false); + if (options_.opensource_include_paths) { + format("#include <google/protobuf/$1$>", path); + } else { + format( + "#include " + "\"third_party/protobuf/testing/extracted/src/google/protobuf/$1$\"", + path); + } + } else { + format("#include \"$1$\"", google3_name); + } + + if (do_export) { + format(" // IWYU pragma: export"); + } + + format("\n"); +} + +string FileGenerator::CreateHeaderInclude(const string& basename, + const FileDescriptor* file) { + bool use_system_include = false; + string name = basename; + + if (options_.opensource_runtime) { + if (IsWellKnownMessage(file)) { + if (options_.opensource_include_paths) { + use_system_include = true; + } else { + name = "third_party/protobuf/testing/extracted/src/" + basename; + } + } + } + + string left = "\""; + string right = "\""; + if (use_system_include) { + left = "<"; + right = ">"; + } + return left + name + right; +} + void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { + Formatter format(printer, variables_); string target_basename = StripProto(file_->name()); - const bool use_system_include = IsWellKnownMessage(file_); - - string header = target_basename + (options_.proto_h ? ".proto.h" : ".pb.h"); - printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n" - "#include $left$$header$$right$\n" - "\n" - "#include <algorithm>\n" // for swap() - "\n" - "#include <google/protobuf/stubs/common.h>\n" - "#include <google/protobuf/stubs/port.h>\n" - "#include <google/protobuf/io/coded_stream.h>\n" - "#include <google/protobuf/wire_format_lite_inl.h>\n", - "filename", file_->name(), - "header", header, - "left", use_system_include ? "<" : "\"", - "right", use_system_include ? ">" : "\""); + if (!options_.opensource_runtime) { + GetBootstrapBasename(options_, target_basename, &target_basename); + } + target_basename += options_.proto_h ? ".proto.h" : ".pb.h"; + format( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n" + "#include $1$\n" + "\n" + "#include <algorithm>\n" // for swap() + "\n", + CreateHeaderInclude(target_basename, file_)); + + if (options_.opensource_runtime) { + DoIncludeFile("net/proto2/public/stubs/common.h", false, printer); + } + + IncludeFile("net/proto2/io/public/coded_stream.h", printer); + // TODO(gerbens) This is to include parse_context.h, we need a better way + IncludeFile("net/proto2/public/extension_set.h", printer); + IncludeFile("net/proto2/public/wire_format_lite_inl.h", printer); // Unknown fields implementation in lite mode uses StringOutputStream if (!UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { - printer->Print( - "#include <google/protobuf/io/zero_copy_stream_impl_lite.h>\n"); + IncludeFile("net/proto2/io/public/zero_copy_stream_impl_lite.h", printer); } if (HasDescriptorMethods(file_, options_)) { - printer->Print( - "#include <google/protobuf/descriptor.h>\n" - "#include <google/protobuf/generated_message_reflection.h>\n" - "#include <google/protobuf/reflection_ops.h>\n" - "#include <google/protobuf/wire_format.h>\n"); + IncludeFile("net/proto2/public/descriptor.h", printer); + IncludeFile("net/proto2/public/generated_message_reflection.h", printer); + IncludeFile("net/proto2/public/reflection_ops.h", printer); + IncludeFile("net/proto2/public/wire_format.h", printer); + } + if (IsProto2MessageSetFile(file_, options_)) { + format( + // Implementation of proto1 MessageSet API methods. + "#include \"net/proto2/bridge/internal/message_set_util.h\"\n"); } if (options_.proto_h) { @@ -298,10 +410,18 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { const FileDescriptor* dep = file_->dependency(i); const char* extension = ".proto.h"; string basename = StripProto(dep->name()); + // Do not import weak deps. + if (!options_.opensource_runtime && IsDepWeak(dep)) continue; + // The proto1 compiler only generates .pb.h files, so even if we are + // running in proto-h mode, we can only use the .pb.h. + if (IsProto1(dep, options_)) { + extension = ".pb.h"; + } + if (IsBootstrapProto(options_, file_)) { + GetBootstrapBasename(options_, basename, &basename); + } string dependency = basename + extension; - printer->Print( - "#include \"$dependency$\"\n", - "dependency", dependency); + format("#include \"$1$\"\n", dependency); } } @@ -311,91 +431,93 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { // and is also linking internal proto2. This is to prevent regressions while // we work cleaning up the code base. After this is completed and we have // one proto lib all code uses this should be removed. - printer->Print( - "// This is a temporary google only hack\n" - "#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS\n" - "#include \"third_party/protobuf/version.h\"\n" - "#endif\n"); - - printer->Print( - "// @@protoc_insertion_point(includes)\n"); + if (options_.opensource_runtime) { + format( + "// This is a temporary google only hack\n" + "#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS\n" + "#include \"third_party/protobuf/version.h\"\n" + "#endif\n"); + } + + format("// @@protoc_insertion_point(includes)\n"); + IncludeFile("net/proto2/public/port_def.inc", printer); } void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* printer) { - printer->Print( - "class $classname$DefaultTypeInternal {\n" + Formatter format(printer, variables_); + format( + "class $1$DefaultTypeInternal {\n" " public:\n" - " ::google::protobuf::internal::ExplicitlyConstructed<$classname$>\n" - " _instance;\n", - "classname", message_generators_[idx]->classname_); - printer->Indent(); + " ::$proto_ns$::internal::ExplicitlyConstructed<$1$> _instance;\n", + message_generators_[idx]->classname_); + format.Indent(); message_generators_[idx]->GenerateExtraDefaultFields(printer); - printer->Outdent(); - printer->Print("} _$classname$_default_instance_;\n", "classname", - message_generators_[idx]->classname_); + format.Outdent(); + format("} _$1$_default_instance_;\n", message_generators_[idx]->classname_); } -namespace { - // Generates weak symbol declarations for types that are to be considered weakly // referenced. -void GenerateInternalForwardDeclarations( +void FileGenerator::GenerateInternalForwardDeclarations( const std::vector<const FieldDescriptor*>& fields, const Options& options, - SCCAnalyzer* scc_analyzer, io::Printer* printer) { + MessageSCCAnalyzer* scc_analyzer, io::Printer* printer) { + Formatter format(printer); // To ensure determinism and minimize the number of namespace statements, // we output the forward declarations sorted on namespace and type / function // name. + std::set<string> global_namespace_decls; + // weak defaults std::set<std::pair<string, string> > messages; - std::set<std::pair<string, string> > sccs; - std::set<std::pair<string, string> > inits; for (int i = 0; i < fields.size(); ++i) { const FieldDescriptor* field = fields[i]; const Descriptor* msg = field->message_type(); if (msg == nullptr) continue; bool is_weak = IsImplicitWeakField(field, options, scc_analyzer); - string flns = FileLevelNamespace(msg); - auto scc = scc_analyzer->GetSCC(msg); - string repr = ClassName(scc->GetRepresentative()); + if (field->options().weak()) { + GOOGLE_CHECK(!options_.opensource_runtime); + is_weak = true; + } string weak_attr; if (is_weak) { - inits.insert(std::make_pair(flns, "AddDescriptors")); + global_namespace_decls.insert( + "void " + UniqueName("AddDescriptors", msg, options_) + + "() __attribute__((weak))"); messages.insert(std::make_pair(Namespace(msg), ClassName(msg))); weak_attr = " __attribute__((weak))"; } - string dllexport = "PROTOBUF_INTERNAL_EXPORT_" + FileLevelNamespace(msg); - sccs.insert(std::make_pair(flns, "extern " + dllexport + weak_attr + - " ::google::protobuf::internal::SCCInfo<" + - SimpleItoa(scc->children.size()) + - "> scc_info_" + repr + ";\n")); - } - - printer->Print("\n"); - NamespaceOpener ns(printer); - for (std::set<std::pair<string, string> >::const_iterator it = - messages.begin(); - it != messages.end(); ++it) { - ns.ChangeTo(it->first); - printer->Print( - "extern __attribute__((weak)) $classname$DefaultTypeInternal " - "_$classname$_default_instance_;\n", - "classname", it->second); - } - for (std::set<std::pair<string, string> >::const_iterator it = inits.begin(); - it != inits.end(); ++it) { - ns.ChangeTo(it->first); - printer->Print("void $name$() __attribute__((weak));\n", - "name", it->second); - } - for (const auto& p : sccs) { - ns.ChangeTo(p.first); - printer->Print(p.second.c_str()); + string dllexport = UniqueName("PROTOBUF_INTERNAL_EXPORT", msg, options_); + if (IsProto1(msg->file(), options_) || IsWeak(field, options_)) { + dllexport = ""; + } + auto scc = scc_analyzer->GetSCC(msg); + string repr = + UniqueName(ClassName(scc->GetRepresentative()), msg, options_); + global_namespace_decls.insert( + "extern " + dllexport + weak_attr + " ::" + ProtobufNamespace(options) + + "::internal::SCCInfo<" + SimpleItoa(scc->children.size()) + + "> scc_info_" + repr); + } + + format("\n"); + + for (const string& decl : global_namespace_decls) { + format("$1$;\n", decl); } -} -} // namespace + // Weak external fields + NamespaceOpener ns(format); + for (const auto& pair : messages) { + ns.ChangeTo(pair.first); + format( + "extern __attribute__((weak)) $1$DefaultTypeInternal " + "_$1$_default_instance_;\n", + pair.second); + } +} void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { + Formatter format(printer, variables_); GenerateSourceIncludes(printer); // Generate weak declarations. We do this for the whole strongly-connected @@ -411,45 +533,43 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { printer); if (IsSCCRepresentative(message_generators_[idx]->descriptor_)) { - NamespaceOpener ns(FileLevelNamespace(file_), printer); GenerateInitForSCC(GetSCC(message_generators_[idx]->descriptor_), printer); } { // package namespace - NamespaceOpener ns(Namespace(file_), printer); + NamespaceOpener ns(Namespace(file_), format); // Define default instances GenerateSourceDefaultInstance(idx, printer); if (options_.lite_implicit_weak_fields) { - printer->Print("void $classname$_ReferenceStrong() {}\n", "classname", - message_generators_[idx]->classname_); + format("void $1$_ReferenceStrong() {}\n", + message_generators_[idx]->classname_); } // Generate classes. - printer->Print("\n"); + format("\n"); message_generators_[idx]->GenerateClassMethods(printer); - printer->Print( + format( "\n" "// @@protoc_insertion_point(namespace_scope)\n"); } // end package namespace - printer->Print( - "namespace google {\nnamespace protobuf {\n"); - message_generators_[idx]->GenerateSourceInProto2Namespace(printer); - printer->Print( - "} // namespace protobuf\n} // namespace google\n"); + { + NamespaceOpener proto_ns(ProtobufNamespace(options_), format); + message_generators_[idx]->GenerateSourceInProto2Namespace(printer); + } - printer->Print( + format( "\n" "// @@protoc_insertion_point(global_scope)\n"); } void FileGenerator::GenerateGlobalSource(io::Printer* printer) { + Formatter format(printer, variables_); GenerateSourceIncludes(printer); { - NamespaceOpener ns(FileLevelNamespace(file_), printer); GenerateTables(printer); // Define the code to initialize reflection. This code uses a global @@ -459,7 +579,7 @@ void FileGenerator::GenerateGlobalSource(io::Printer* printer) { } } - NamespaceOpener ns(Namespace(file_), printer); + NamespaceOpener ns(Namespace(file_), format); // Generate enums. for (int i = 0; i < enum_generators_.size(); i++) { @@ -474,15 +594,16 @@ void FileGenerator::GenerateGlobalSource(io::Printer* printer) { if (HasGenericServices(file_, options_)) { // Generate services. for (int i = 0; i < service_generators_.size(); i++) { - if (i == 0) printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); + if (i == 0) format("\n"); + format(kThickSeparator); + format("\n"); service_generators_[i]->GenerateImplementation(printer); } } } void FileGenerator::GenerateSource(io::Printer* printer) { + Formatter format(printer, variables_); GenerateSourceIncludes(printer); std::vector<const FieldDescriptor*> fields; ListAllFields(file_, &fields); @@ -490,20 +611,19 @@ void FileGenerator::GenerateSource(io::Printer* printer) { printer); { - NamespaceOpener ns(Namespace(file_), printer); + NamespaceOpener ns(Namespace(file_), format); // Define default instances for (int i = 0; i < message_generators_.size(); i++) { GenerateSourceDefaultInstance(i, printer); if (options_.lite_implicit_weak_fields) { - printer->Print("void $classname$_ReferenceStrong() {}\n", "classname", - message_generators_[i]->classname_); + format("void $1$_ReferenceStrong() {}\n", + message_generators_[i]->classname_); } } } { - NamespaceOpener ns(FileLevelNamespace(file_), printer); GenerateTables(printer); // Now generate the InitDefaults for each SCC. @@ -514,26 +634,28 @@ void FileGenerator::GenerateSource(io::Printer* printer) { } } - printer->Print("void InitDefaults() {\n"); - for (int i = 0; i < message_generators_.size(); i++) { - if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; - string scc_name = ClassName(message_generators_[i]->descriptor_); - printer->Print( - " ::google::protobuf::internal::InitSCC(&scc_info_$scc_name$.base);\n", - "scc_name", scc_name); - } - printer->Print("}\n\n"); - - // Define the code to initialize reflection. This code uses a global - // constructor to register reflection data with the runtime pre-main. if (HasDescriptorMethods(file_, options_)) { + // TODO(gerbens) This is for proto1 interoperability. Remove when proto1 + // is gone. + format("void $init_defaults$() {\n"); + for (int i = 0; i < message_generators_.size(); i++) { + if (!IsSCCRepresentative(message_generators_[i]->descriptor_)) continue; + string scc_name = + UniqueName(ClassName(message_generators_[i]->descriptor_), + message_generators_[i]->descriptor_, options_); + format(" ::$proto_ns$::internal::InitSCC(&scc_info_$1$.base);\n", + scc_name); + } + format("}\n\n"); + + // Define the code to initialize reflection. This code uses a global + // constructor to register reflection data with the runtime pre-main. GenerateReflectionInitializationCode(printer); } } - { - NamespaceOpener ns(Namespace(file_), printer); + NamespaceOpener ns(Namespace(file_), format); // Actually implement the protos @@ -544,18 +666,18 @@ void FileGenerator::GenerateSource(io::Printer* printer) { // Generate classes. for (int i = 0; i < message_generators_.size(); i++) { - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); + format("\n"); + format(kThickSeparator); + format("\n"); message_generators_[i]->GenerateClassMethods(printer); } if (HasGenericServices(file_, options_)) { // Generate services. for (int i = 0; i < service_generators_.size(); i++) { - if (i == 0) printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); + if (i == 0) format("\n"); + format(kThickSeparator); + format("\n"); service_generators_[i]->GenerateImplementation(printer); } } @@ -565,144 +687,26 @@ void FileGenerator::GenerateSource(io::Printer* printer) { extension_generators_[i]->GenerateDefinition(printer); } - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); - } - - printer->Print( - "namespace google {\nnamespace protobuf {\n"); - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateSourceInProto2Namespace(printer); - } - printer->Print( - "} // namespace protobuf\n} // namespace google\n"); - - printer->Print( - "\n" - "// @@protoc_insertion_point(global_scope)\n"); -} - -class FileGenerator::ForwardDeclarations { - public: - ~ForwardDeclarations() { - for (std::map<string, ForwardDeclarations*>::iterator - it = namespaces_.begin(), - end = namespaces_.end(); - it != end; ++it) { - delete it->second; - } - namespaces_.clear(); - } - - ForwardDeclarations* AddOrGetNamespace(const string& ns_name) { - ForwardDeclarations*& ns = namespaces_[ns_name]; - if (ns == nullptr) { - ns = new ForwardDeclarations; - } - return ns; - } - - std::map<string, const Descriptor*>& classes() { return classes_; } - std::map<string, const EnumDescriptor*>& enums() { return enums_; } - - void PrintForwardDeclarations(io::Printer* printer, - const Options& options) const { - PrintNestedDeclarations(printer, options); - PrintTopLevelDeclarations(printer, options); - } - - - private: - void PrintNestedDeclarations(io::Printer* printer, - const Options& options) const { - PrintDeclarationsInsideNamespace(printer, options); - for (std::map<string, ForwardDeclarations *>::const_iterator - it = namespaces_.begin(), - end = namespaces_.end(); - it != end; ++it) { - printer->Print("namespace $nsname$ {\n", - "nsname", it->first); - it->second->PrintNestedDeclarations(printer, options); - printer->Print("} // namespace $nsname$\n", - "nsname", it->first); - } - } - - void PrintTopLevelDeclarations(io::Printer* printer, - const Options& options) const { - PrintDeclarationsOutsideNamespace(printer, options); - for (std::map<string, ForwardDeclarations *>::const_iterator - it = namespaces_.begin(), - end = namespaces_.end(); - it != end; ++it) { - it->second->PrintTopLevelDeclarations(printer, options); - } - } - - void PrintDeclarationsInsideNamespace(io::Printer* printer, - const Options& options) const { - for (std::map<string, const EnumDescriptor *>::const_iterator - it = enums_.begin(), - end = enums_.end(); - it != end; ++it) { - printer->Print("enum $enumname$ : int;\n", "enumname", it->first); - printer->Annotate("enumname", it->second); - printer->Print("bool $enumname$_IsValid(int value);\n", "enumname", - it->first); - } - for (std::map<string, const Descriptor*>::const_iterator - it = classes_.begin(), - end = classes_.end(); - it != end; ++it) { - printer->Print("class $classname$;\n", "classname", it->first); - printer->Annotate("classname", it->second); - - printer->Print( - "class $classname$DefaultTypeInternal;\n" - "$dllexport_decl$" - "extern $classname$DefaultTypeInternal " - "_$classname$_default_instance_;\n", // NOLINT - "dllexport_decl", - options.dllexport_decl.empty() ? "" : options.dllexport_decl + " ", - "classname", - it->first); - if (options.lite_implicit_weak_fields) { - printer->Print("void $classname$_ReferenceStrong();\n", - "classname", it->first); - } - } + format( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); } - void PrintDeclarationsOutsideNamespace(io::Printer* printer, - const Options& options) const { - if (classes_.size() == 0) return; - - printer->Print( - "namespace google {\nnamespace protobuf {\n"); - for (std::map<string, const Descriptor*>::const_iterator - it = classes_.begin(), - end = classes_.end(); - it != end; ++it) { - const Descriptor* d = it->second; - printer->Print( - "template<> " - "$dllexport_decl$" - "$classname$* Arena::CreateMaybeMessage<$classname$>" - "(Arena*);\n", - "classname", QualifiedClassName(d), "dllexport_decl", - options.dllexport_decl.empty() ? "" : options.dllexport_decl + " "); + { + NamespaceOpener proto_ns(ProtobufNamespace(options_), format); + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->GenerateSourceInProto2Namespace(printer); } - printer->Print( - "} // namespace protobuf\n} // namespace google\n"); } - std::map<string, ForwardDeclarations*> namespaces_; - std::map<string, const Descriptor*> classes_; - std::map<string, const EnumDescriptor*> enums_; -}; + format( + "\n" + "// @@protoc_insertion_point(global_scope)\n"); +} void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { + Formatter format(printer, variables_); + // AddDescriptors() is a file-level procedure which adds the encoded // FileDescriptorProto for this .proto file to the global DescriptorPool for // generated files (DescriptorPool::generated_pool()). It ordinarily runs at @@ -716,39 +720,50 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // in the file. if (!message_generators_.empty()) { - printer->Print("::google::protobuf::Metadata file_level_metadata[$size$];\n", "size", - SimpleItoa(message_generators_.size())); + format("::$proto_ns$::Metadata $file_level_metadata$[$1$];\n", + message_generators_.size()); + } else { + format( + "constexpr ::$proto_ns$::Metadata* $file_level_metadata$ = nullptr;\n"); } if (!enum_generators_.empty()) { - printer->Print( - "const ::google::protobuf::EnumDescriptor* " - "file_level_enum_descriptors[$size$];\n", - "size", SimpleItoa(enum_generators_.size())); + format( + "const ::$proto_ns$::EnumDescriptor* " + "$file_level_enum_descriptors$[$1$];\n", + enum_generators_.size()); + } else { + format( + "constexpr ::$proto_ns$::EnumDescriptor const** " + "$file_level_enum_descriptors$ = nullptr;\n"); } if (HasGenericServices(file_, options_) && file_->service_count() > 0) { - printer->Print( - "const ::google::protobuf::ServiceDescriptor* " - "file_level_service_descriptors[$size$];\n", - "size", SimpleItoa(file_->service_count())); + format( + "const ::$proto_ns$::ServiceDescriptor* " + "$file_level_service_descriptors$[$1$];\n", + file_->service_count()); + } else { + format( + "constexpr ::$proto_ns$::ServiceDescriptor const** " + "$file_level_service_descriptors$ = nullptr;\n"); } if (!message_generators_.empty()) { - printer->Print( + format( "\n" - "const ::google::protobuf::uint32 TableStruct::offsets[] " - "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); + "const $uint32$ $tablename$::offsets[] " + "$GOOGLE_PROTOBUF$_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); std::vector<std::pair<size_t, size_t> > pairs; pairs.reserve(message_generators_.size()); for (int i = 0; i < message_generators_.size(); i++) { pairs.push_back(message_generators_[i]->GenerateOffsets(printer)); } - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "};\n" - "static const ::google::protobuf::internal::MigrationSchema schemas[] " - "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); + "static const ::$proto_ns$::internal::MigrationSchema schemas[] " + "$GOOGLE_PROTOBUF$_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); { int offset = 0; for (int i = 0; i < message_generators_.size(); i++) { @@ -757,30 +772,33 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { offset += pairs[i].first; } } - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "};\n" "\nstatic " - "::google::protobuf::Message const * const file_default_instances[] = {\n"); - printer->Indent(); + "::$proto_ns$::Message const * const file_default_instances[] = {\n"); + format.Indent(); for (int i = 0; i < message_generators_.size(); i++) { const Descriptor* descriptor = message_generators_[i]->descriptor_; - printer->Print( + format( "reinterpret_cast<const " - "::google::protobuf::Message*>(&$ns$::_$classname$_default_instance_),\n", - "classname", ClassName(descriptor), "ns", Namespace(descriptor)); + "::$proto_ns$::Message*>(&$1$::_$2$_default_instance_),\n", + Namespace(descriptor), // 1 + ClassName(descriptor)); // 2 } - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "};\n" "\n"); } else { // we still need these symbols to exist - printer->Print( + format( // MSVC doesn't like empty arrays, so we add a dummy. - "const ::google::protobuf::uint32 TableStruct::offsets[1] = {};\n" - "static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n" - "static const ::google::protobuf::Message* const* " + "const $uint32$ $tablename$::offsets[1] = {};\n" + "static constexpr ::$proto_ns$::internal::MigrationSchema* schemas = " + "NULL;" + "\n" + "static constexpr ::$proto_ns$::Message* const* " "file_default_instances = NULL;\n" "\n"); } @@ -790,161 +808,90 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // protobuf_AssignDescriptorsOnce(): The first time it is called, calls // AssignDescriptors(). All later times, waits for the first call to // complete and then returns. - printer->Print( - "static void protobuf_AssignDescriptors() {\n" - // Make sure the file has found its way into the pool. If a descriptor - // is requested *during* static init then AddDescriptors() may not have - // been called yet, so we call it manually. Note that it's fine if - // AddDescriptors() is called multiple times. - " AddDescriptors();\n" - " AssignDescriptors(\n" - " \"$filename$\", schemas, file_default_instances, " - "TableStruct::offsets,\n" - " $metadata$, $enum_descriptors$, $service_descriptors$);\n", - "filename", file_->name(), "metadata", - !message_generators_.empty() ? "file_level_metadata" : "NULL", - "enum_descriptors", - !enum_generators_.empty() ? "file_level_enum_descriptors" : "NULL", - "service_descriptors", - HasGenericServices(file_, options_) && file_->service_count() > 0 - ? "file_level_service_descriptors" - : "NULL"); - printer->Print( - "}\n" - "\n" - "static void protobuf_AssignDescriptorsOnce() {\n" - " static ::google::protobuf::internal::once_flag once;\n" - " ::google::protobuf::internal::call_once(once, protobuf_AssignDescriptors);\n" - "}\n" - "\n", - "filename", file_->name(), "metadata", - !message_generators_.empty() ? "file_level_metadata" : "NULL", - "enum_descriptors", - !enum_generators_.empty() ? "file_level_enum_descriptors" : "NULL", - "service_descriptors", - HasGenericServices(file_, options_) && file_->service_count() > 0 - ? "file_level_service_descriptors" - : "NULL"); - - // Only here because of useless string reference that we don't want in - // protobuf_AssignDescriptorsOnce, because that is called from all the - // GetMetadata member methods. - printer->Print( - "void protobuf_RegisterTypes(const ::std::string&) " - "GOOGLE_PROTOBUF_ATTRIBUTE_COLD;\n" - "void protobuf_RegisterTypes(const ::std::string&) {\n" - " protobuf_AssignDescriptorsOnce();\n"); - printer->Indent(); - - // All normal messages can be done generically - if (!message_generators_.empty()) { - printer->Print( - "::google::protobuf::internal::RegisterAllTypes(file_level_metadata, $size$);\n", - "size", SimpleItoa(message_generators_.size())); - } - - printer->Outdent(); - printer->Print( - "}\n" - "\n"); + format( + "::$proto_ns$::internal::AssignDescriptorsTable $assign_desc_table$ = " + "{\n" + " {}, $add_descriptors$, \"$filename$\", schemas,\n" + " file_default_instances, $tablename$::offsets,\n" + " $file_level_metadata$, $1$, $file_level_enum_descriptors$, " + "$file_level_service_descriptors$,\n" + "};\n" + "\n", + message_generators_.size()); + + // Now generate the AddDescriptors() function. + format( + "::$proto_ns$::internal::DescriptorTable $1$ = {\n" + " false, $init_defaults$, \n", + UniqueName("descriptor_table", file_, options_)); + format.Indent(); + + // Embed the descriptor. We simply serialize the entire + // FileDescriptorProto + // and embed it as a string literal, which is parsed and built into real + // descriptors at initialization time. + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + string file_data; + file_proto.SerializeToString(&file_data); - // Now generate the AddDescriptors() function. - printer->Print( - "static void AddDescriptorsImpl() {\n" - " InitDefaults();\n"); - printer->Indent(); - - // Embed the descriptor. We simply serialize the entire - // FileDescriptorProto - // and embed it as a string literal, which is parsed and built into real - // descriptors at initialization time. - FileDescriptorProto file_proto; - file_->CopyTo(&file_proto); - string file_data; - file_proto.SerializeToString(&file_data); - - printer->Print("static const char descriptor[] " - "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) " - "= {\n"); - printer->Indent(); - - if (file_data.size() > 65535) { - // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535 - // bytes in length". Declare a static array of characters rather than use - // a string literal. Only write 25 bytes per line. - static const int kBytesPerLine = 25; - for (int i = 0; i < file_data.size();) { - for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { - printer->Print("'$char$', ", "char", - CEscape(file_data.substr(i, 1))); - } - printer->Print("\n"); - } - } else { - // Only write 40 bytes per line. - static const int kBytesPerLine = 40; - for (int i = 0; i < file_data.size(); i += kBytesPerLine) { - printer->Print(" \"$data$\"\n", "data", - EscapeTrigraphs(CEscape( - file_data.substr(i, kBytesPerLine)))); - } + { + // Only write 40 bytes per line. + static const int kBytesPerLine = 40; + for (int i = 0; i < file_data.size(); i += kBytesPerLine) { + format( + "\"$1$\"\n", + EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine)))); } - - printer->Outdent(); - printer->Print("};\n"); - printer->Print( - "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(\n" - " descriptor, $size$);\n", - "size", SimpleItoa(file_data.size())); - - // Call MessageFactory::InternalRegisterGeneratedFile(). - printer->Print( - "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n" - " \"$filename$\", &protobuf_RegisterTypes);\n", - "filename", file_->name()); - - // Call the AddDescriptors() methods for all of our dependencies, to make - // sure they get added first. - for (int i = 0; i < file_->dependency_count(); i++) { - const FileDescriptor* dependency = file_->dependency(i); - // Print the namespace prefix for the dependency. - string file_namespace = FileLevelNamespace(dependency); - // Call its AddDescriptors function. - printer->Print("::$file_namespace$::AddDescriptors();\n", "file_namespace", - file_namespace); } - printer->Outdent(); - printer->Print( - "}\n" - "\n" - "void AddDescriptors() {\n" - " static ::google::protobuf::internal::once_flag once;\n" - " ::google::protobuf::internal::call_once(once, AddDescriptorsImpl);\n" - "}\n"); - - printer->Print( - "// Force AddDescriptors() to be called at dynamic initialization " - "time.\n" - "struct StaticDescriptorInitializer {\n" - " StaticDescriptorInitializer() {\n" - " AddDescriptors();\n" - " }\n" - "} static_descriptor_initializer;\n"); + format.Outdent(); + const int num_deps = file_->dependency_count(); + format( + ",\n \"$filename$\", &$assign_desc_table$, $1$,\n" + "};\n\n" + "void $add_descriptors$() {\n" + " static constexpr ::$proto_ns$::internal::InitFunc deps[$2$] =\n" + " {\n", + file_data.size(), std::max(num_deps, 1)); + for (int i = 0; i < num_deps; i++) { + const FileDescriptor* dependency = file_->dependency(i); + format(" ::$1$,\n", UniqueName("AddDescriptors", dependency, options_)); + } + format( + " };\n" + " ::$proto_ns$::internal::AddDescriptors(&$1$, deps, $2$);\n" + "}\n\n", + UniqueName("descriptor_table", file_, options_), // 1 + num_deps); // 2 + format( + "// Force running AddDescriptors() at dynamic initialization time.\n" + "static bool $1$ = []() { $add_descriptors$(); return true; }();\n", + UniqueName("dynamic_init_dummy", file_, options_)); } void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { + Formatter format(printer, variables_); const string scc_name = ClassName(scc->GetRepresentative()); // We use static and not anonymous namespace because symbol names are // substantially shorter. - printer->Print( - "static void InitDefaults$scc_name$() {\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n" - , // awkward comma due to macro - "scc_name", scc_name); + format("static void InitDefaults$1$() {\n", + UniqueName(scc_name, scc->GetRepresentative(), options_)); - printer->Indent(); + if (options_.opensource_runtime) { + format(" GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n"); + } + format.Indent(); + + if (!options_.opensource_runtime) { + for (int i = 0; i < scc->children.size(); i++) { + const SCC* child_scc = scc->children[i]; + const FileDescriptor* dependency = child_scc->GetRepresentative()->file(); + if (!IsProto1(dependency, options_)) continue; + format("$1$();\n", UniqueName("InitDefaults", dependency, options_)); + } + } // First construct all the necessary default instances. for (int i = 0; i < message_generators_.size(); i++) { @@ -954,17 +901,18 @@ void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { // TODO(gerbens) This requires this function to be friend. Remove // the need for this. message_generators_[i]->GenerateFieldDefaultInstances(printer); - printer->Print( + format( "{\n" - " void* ptr = &$ns$::_$classname$_default_instance_;\n" - " new (ptr) $ns$::$classname$();\n", - "ns", Namespace(message_generators_[i]->descriptor_), - "classname", ClassName(message_generators_[i]->descriptor_)); - if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) { - printer->Print( + " void* ptr = &$1$::_$2$_default_instance_;\n" + " new (ptr) $1$::$2$();\n", + Namespace(message_generators_[i]->descriptor_), // 1 + ClassName(message_generators_[i]->descriptor_)); // 2 + if (options_.opensource_runtime && + !IsMapEntryMessage(message_generators_[i]->descriptor_)) { + format( " ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);\n"); } - printer->Print("}\n"); + format("}\n"); } // TODO(gerbens) make default instances be the same as normal instances. @@ -974,37 +922,44 @@ void FileGenerator::GenerateInitForSCC(const SCC* scc, io::Printer* printer) { if (scc_analyzer_.GetSCC(message_generators_[i]->descriptor_) != scc) { continue; } - printer->Print("$classname$::InitAsDefaultInstance();\n", "classname", - QualifiedClassName(message_generators_[i]->descriptor_)); - } - printer->Outdent(); - printer->Print("}\n\n"); - - printer->Print( - "$dllexport_decl$::google::protobuf::internal::SCCInfo<$size$> " - "scc_info_$scc_name$ =\n" - " {{ATOMIC_VAR_INIT(::google::protobuf::internal::SCCInfoBase::kUninitialized), " - "$size$, InitDefaults$scc_name$}, {", - "size", SimpleItoa(scc->children.size()), "scc_name", - ClassName(scc->GetRepresentative()), "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + format("$1$::InitAsDefaultInstance();\n", + QualifiedClassName(message_generators_[i]->descriptor_)); + } + format.Outdent(); + format("}\n\n"); + + format( + "$dllexport_decl $::$proto_ns$::internal::SCCInfo<$1$> " + "scc_info_$2$ =\n" + " " + "{{ATOMIC_VAR_INIT(::$proto_ns$::internal::SCCInfoBase::kUninitialized), " + "$1$, InitDefaults$2$}, {", + scc->children.size(), // 1 + UniqueName(ClassName(scc->GetRepresentative()), scc->GetRepresentative(), + options_)); for (const SCC* child : scc->children) { auto repr = child->GetRepresentative(); - printer->Print("\n &$ns$::scc_info_$child$.base,", "ns", - FileLevelNamespace(repr), "child", ClassName(repr)); + if (IsProto1(repr->file(), options_)) { + GOOGLE_CHECK(!options_.opensource_runtime); + format("\n nullptr,"); + continue; + } + format("\n &scc_info_$1$.base,", + UniqueName(ClassName(repr), repr, options_)); } - printer->Print("}};\n\n"); + format("}};\n\n"); } void FileGenerator::GenerateTables(io::Printer* printer) { + Formatter format(printer, variables_); if (options_.table_driven_parsing) { // TODO(ckennelly): Gate this with the same options flag to enable // table-driven parsing. - printer->Print( - "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField\n" - " const TableStruct::entries[] " - "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); + format( + "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTableField\n" + " const $tablename$::entries[] " + "$GOOGLE_PROTOBUF$_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); std::vector<size_t> entries; size_t count = 0; @@ -1016,17 +971,18 @@ void FileGenerator::GenerateTables(io::Printer* printer) { // We need these arrays to exist, and MSVC does not like empty arrays. if (count == 0) { - printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n"); + format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n"); } - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "};\n" "\n" - "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField\n" - " const TableStruct::aux[] " - "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); + "PROTOBUF_CONSTEXPR_VAR " + "::$proto_ns$::internal::AuxillaryParseTableField\n" + " const $tablename$::aux[] " + "$GOOGLE_PROTOBUF$_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); std::vector<size_t> aux_entries; count = 0; @@ -1037,16 +993,16 @@ void FileGenerator::GenerateTables(io::Printer* printer) { } if (count == 0) { - printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n"); + format("::$proto_ns$::internal::AuxillaryParseTableField(),\n"); } - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "};\n" - "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const\n" - " TableStruct::schema[] " - "GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); - printer->Indent(); + "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTable const\n" + " $tablename$::schema[] " + "$GOOGLE_PROTOBUF$_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); + format.Indent(); size_t offset = 0; size_t aux_offset = 0; @@ -1057,20 +1013,21 @@ void FileGenerator::GenerateTables(io::Printer* printer) { } if (message_generators_.empty()) { - printer->Print("{ NULL, NULL, 0, -1, -1, false },\n"); + format("{ NULL, NULL, 0, -1, -1, false },\n"); } - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "};\n" "\n"); } if (!message_generators_.empty() && options_.table_driven_serialization) { - printer->Print( - "const ::google::protobuf::internal::FieldMetadata TableStruct::field_metadata[] " + format( + "const ::$proto_ns$::internal::FieldMetadata " + "$tablename$::field_metadata[] " "= {\n"); - printer->Indent(); + format.Indent(); std::vector<int> field_metadata_offsets; int idx = 0; for (int i = 0; i < message_generators_.size(); i++) { @@ -1078,12 +1035,12 @@ void FileGenerator::GenerateTables(io::Printer* printer) { idx += message_generators_[i]->GenerateFieldMetadata(printer); } field_metadata_offsets.push_back(idx); - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "};\n" - "const ::google::protobuf::internal::SerializationTable " - "TableStruct::serialization_table[] = {\n"); - printer->Indent(); + "const ::$proto_ns$::internal::SerializationTable " + "$tablename$::serialization_table[] = {\n"); + format.Indent(); // We rely on the order we layout the tables to match the order we // calculate them with FlattenMessagesInFile, so we check here that // these match exactly. @@ -1092,235 +1049,327 @@ void FileGenerator::GenerateTables(io::Printer* printer) { GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size()); for (int i = 0; i < message_generators_.size(); i++) { GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_); - printer->Print( - "{$num_fields$, TableStruct::field_metadata + $index$},\n", - "classname", message_generators_[i]->classname_, "num_fields", - SimpleItoa(field_metadata_offsets[i + 1] - field_metadata_offsets[i]), - "index", SimpleItoa(field_metadata_offsets[i])); + format("{$1$, $tablename$::field_metadata + $2$},\n", + field_metadata_offsets[i + 1] - field_metadata_offsets[i], // 1 + field_metadata_offsets[i]); // 2 } - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "};\n" "\n"); } } -void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { - ForwardDeclarations decls; - FillForwardDeclarations(&decls); - decls.PrintForwardDeclarations(printer, options_); +class FileGenerator::ForwardDeclarations { + public: + void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; } + void AddEnum(const EnumDescriptor* d) { enums_[ClassName(d)] = d; } + + void Print(const Formatter& format, const Options& options) const { + for (const auto& p : enums_) { + const string& enumname = p.first; + const EnumDescriptor* enum_desc = p.second; + format( + "enum ${1$$2$$}$ : int;\n" + "bool $2$_IsValid(int value);\n", + enum_desc, enumname); + } + for (const auto& p : classes_) { + const string& classname = p.first; + const Descriptor* class_desc = p.second; + format( + "class ${1$$2$$}$;\n" + "class $2$DefaultTypeInternal;\n" + "$dllexport_decl $extern " + "$2$DefaultTypeInternal _$2$_default_instance_;\n", + class_desc, classname); + if (options.lite_implicit_weak_fields) { + format("void $1$_ReferenceStrong();\n", classname); + } + } + } + + void PrintTopLevelDecl(const Formatter& format) const { + for (const auto& pair : classes_) { + format( + "template<> $dllexport_decl $" + "$1$* Arena::CreateMaybeMessage<$1$>(Arena*);\n", + QualifiedClassName(pair.second)); + } + } + + private: + std::map<string, const Descriptor*> classes_; + std::map<string, const EnumDescriptor*> enums_; +}; + +static void PublicImportDFS(const FileDescriptor* fd, + std::unordered_set<const FileDescriptor*>* fd_set) { + for (int i = 0; i < fd->public_dependency_count(); i++) { + const FileDescriptor* dep = fd->public_dependency(i); + if (fd_set->insert(dep).second) PublicImportDFS(dep, fd_set); + } } -void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) { - for (int i = 0; i < package_parts_.size(); i++) { - decls = decls->AddOrGetNamespace(package_parts_[i]); +void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { + Formatter format(printer, variables_); + std::vector<const Descriptor*> classes; + std::vector<const EnumDescriptor*> enums; + + FlattenMessagesInFile(file_, &classes); // All messages need forward decls. + + if (options_.proto_h) { // proto.h needs extra forward declarations. + // All classes / enums refered to as field members + std::vector<const FieldDescriptor*> fields; + ListAllFields(file_, &fields); + for (int i = 0; i < fields.size(); i++) { + classes.push_back(fields[i]->containing_type()); + classes.push_back(fields[i]->message_type()); + enums.push_back(fields[i]->enum_type()); + } + ListAllTypesForServices(file_, &classes); } - // Generate enum definitions. - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->FillForwardDeclaration(&decls->enums()); + + // Calculate the set of files whose definitions we get through include. + // No need to forward declare types that are defined in these. + std::unordered_set<const FileDescriptor*> public_set; + PublicImportDFS(file_, &public_set); + + std::map<string, ForwardDeclarations> decls; + for (int i = 0; i < classes.size(); i++) { + const Descriptor* d = classes[i]; + if (d && !public_set.count(d->file())) decls[Namespace(d)].AddMessage(d); } - // Generate forward declarations of classes. - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->FillMessageForwardDeclarations( - &decls->classes()); + for (int i = 0; i < enums.size(); i++) { + const EnumDescriptor* d = enums[i]; + if (d && !public_set.count(d->file())) decls[Namespace(d)].AddEnum(d); + } + + + NamespaceOpener ns(format); + for (const auto& pair : decls) { + ns.ChangeTo(pair.first); + pair.second.Print(format, options_); + } + ns.ChangeTo(variables_["proto_ns"]); + for (const auto& pair : decls) { + pair.second.PrintTopLevelDecl(format); } } void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, const string& filename_identifier) { + Formatter format(printer, variables_); // Generate top of header. - printer->Print( + format( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" "\n" - "#ifndef PROTOBUF_INCLUDED_$filename_identifier$\n" - "#define PROTOBUF_INCLUDED_$filename_identifier$\n" + "#ifndef PROTOBUF_INCLUDED_$1$\n" + "#define PROTOBUF_INCLUDED_$1$\n" "\n" + "#include <limits>\n" "#include <string>\n", - "filename", file_->name(), "filename_identifier", filename_identifier); - printer->Print("\n"); + filename_identifier); + if (!options_.opensource_runtime && !enum_generators_.empty()) { + // Add header to provide std::is_integral for safe Enum_Name() function. + format("#include <type_traits>\n"); + } + format("\n"); } void FileGenerator::GenerateBottomHeaderGuard( io::Printer* printer, const string& filename_identifier) { - printer->Print( - "#endif // PROTOBUF_INCLUDED_$filename_identifier$\n", - "filename_identifier", filename_identifier); + Formatter format(printer, variables_); + format("#endif // PROTOBUF_INCLUDED_$1$\n", filename_identifier); } void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { + Formatter format(printer, variables_); if (UsingImplicitWeakFields(file_, options_)) { - printer->Print("#include <google/protobuf/implicit_weak_message.h>\n"); - } - - printer->Print( - "#include <google/protobuf/stubs/common.h>\n" - "\n"); - - // Verify the protobuf library header version is compatible with the protoc - // version before going any further. - printer->Print( - "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n" - "#error This file was generated by a newer version of protoc which is\n" - "#error incompatible with your Protocol Buffer headers. Please update\n" - "#error your headers.\n" - "#endif\n" - "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n" - "#error This file was generated by an older version of protoc which is\n" - "#error incompatible with your Protocol Buffer headers. Please\n" - "#error regenerate this file with a newer version of protoc.\n" - "#endif\n" - "\n", - "min_header_version", - SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc), - "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION)); + IncludeFile("net/proto2/public/implicit_weak_message.h", printer); + } + if (HasWeakFields(file_, options_)) { + GOOGLE_CHECK(!options_.opensource_runtime); + IncludeFile("net/proto2/public/weak_field_map.h", printer); + } + if (HasLazyFields(file_, options_)) { + GOOGLE_CHECK(!options_.opensource_runtime); + IncludeFile("net/proto2/public/lazy_field.h", printer); + } + + if (options_.opensource_runtime) { + DoIncludeFile("net/proto2/public/stubs/common.h", false, printer); + + // Verify the protobuf library header version is compatible with the protoc + // version before going any further. + format( + "#if GOOGLE_PROTOBUF_VERSION < $1$\n" + "#error This file was generated by a newer version of protoc which is\n" + "#error incompatible with your Protocol Buffer headers. Please update\n" + "#error your headers.\n" + "#endif\n" + "#if $2$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n" + "#error This file was generated by an older version of protoc which " + "is\n" + "#error incompatible with your Protocol Buffer headers. Please\n" + "#error regenerate this file with a newer version of protoc.\n" + "#endif\n" + "\n", + GOOGLE_PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC, // 1 + GOOGLE_PROTOBUF_VERSION); // 2 + } // OK, it's now safe to #include other files. - printer->Print( - "#include <google/protobuf/io/coded_stream.h>\n" - "#include <google/protobuf/arena.h>\n" - "#include <google/protobuf/arenastring.h>\n" - "#include <google/protobuf/generated_message_table_driven.h>\n" - "#include <google/protobuf/generated_message_util.h>\n" - "#include <google/protobuf/inlined_string_field.h>\n"); - + IncludeFile("net/proto2/io/public/coded_stream.h", printer); + IncludeFile("net/proto2/public/arena.h", printer); + IncludeFile("net/proto2/public/arenastring.h", printer); + IncludeFile("net/proto2/public/generated_message_table_driven.h", printer); + IncludeFile("net/proto2/public/generated_message_util.h", printer); + IncludeFile("net/proto2/public/inlined_string_field.h", printer); if (HasDescriptorMethods(file_, options_)) { - printer->Print( - "#include <google/protobuf/metadata.h>\n"); + IncludeFile("net/proto2/public/metadata.h", printer); } else { - printer->Print( - "#include <google/protobuf/metadata_lite.h>\n"); + IncludeFile("net/proto2/public/metadata_lite.h", printer); } if (!message_generators_.empty()) { if (HasDescriptorMethods(file_, options_)) { - printer->Print( - "#include <google/protobuf/message.h>\n"); + IncludeFile("net/proto2/public/message.h", printer); } else { - printer->Print( - "#include <google/protobuf/message_lite.h>\n"); + IncludeFile("net/proto2/public/message_lite.h", printer); + } + } + if (options_.opensource_runtime) { + // Open-source relies on unconditional includes of these. + IncludeFileAndExport("net/proto2/public/repeated_field.h", printer); + IncludeFileAndExport("net/proto2/public/extension_set.h", printer); + } else { + // Google3 includes these files only when they are necessary. + if (HasExtensionsOrExtendableMessage(file_)) { + IncludeFileAndExport("net/proto2/public/extension_set.h", printer); + } + if (HasRepeatedFields(file_)) { + IncludeFileAndExport("net/proto2/public/repeated_field.h", printer); + } + if (HasStringPieceFields(file_, options_)) { + IncludeFile("net/proto2/public/string_piece_field_support.h", printer); + } + if (HasCordFields(file_, options_)) { + format("#include \"third_party/absl/strings/cord.h\"\n"); } } - printer->Print( - "#include <google/protobuf/repeated_field.h>" - " // IWYU pragma: export\n" - "#include <google/protobuf/extension_set.h>" - " // IWYU pragma: export\n"); if (HasMapFields(file_)) { - printer->Print( - "#include <google/protobuf/map.h>" - " // IWYU pragma: export\n"); + IncludeFileAndExport("net/proto2/public/map.h", printer); if (HasDescriptorMethods(file_, options_)) { - printer->Print("#include <google/protobuf/map_entry.h>\n"); - printer->Print("#include <google/protobuf/map_field_inl.h>\n"); + IncludeFile("net/proto2/public/map_entry.h", printer); + IncludeFile("net/proto2/public/map_field_inl.h", printer); } else { - printer->Print("#include <google/protobuf/map_entry_lite.h>\n"); - printer->Print("#include <google/protobuf/map_field_lite.h>\n"); + IncludeFile("net/proto2/public/map_entry_lite.h", printer); + IncludeFile("net/proto2/public/map_field_lite.h", printer); } } if (HasEnumDefinitions(file_)) { if (HasDescriptorMethods(file_, options_)) { - printer->Print( - "#include <google/protobuf/generated_enum_reflection.h>\n"); + IncludeFile("net/proto2/public/generated_enum_reflection.h", printer); } else { - printer->Print( - "#include <google/protobuf/generated_enum_util.h>\n"); + IncludeFile("net/proto2/public/generated_enum_util.h", printer); } } if (HasGenericServices(file_, options_)) { - printer->Print( - "#include <google/protobuf/service.h>\n"); + IncludeFile("net/proto2/public/service.h", printer); } if (UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { - printer->Print( - "#include <google/protobuf/unknown_field_set.h>\n"); + IncludeFile("net/proto2/public/unknown_field_set.h", printer); } - if (IsAnyMessage(file_)) { - printer->Print( - "#include <google/protobuf/any.h>\n"); + IncludeFile("net/proto2/internal/any.h", printer); } } void FileGenerator::GenerateMetadataPragma(io::Printer* printer, const string& info_path) { + Formatter format(printer, variables_); if (!info_path.empty() && !options_.annotation_pragma_name.empty() && !options_.annotation_guard_name.empty()) { - printer->Print( + format.Set("guard", options_.annotation_guard_name); + format.Set("pragma", options_.annotation_pragma_name); + format.Set("info_path", info_path); + format( "#ifdef $guard$\n" "#pragma $pragma$ \"$info_path$\"\n" - "#endif // $guard$\n", - "guard", options_.annotation_guard_name, "pragma", - options_.annotation_pragma_name, "info_path", info_path); + "#endif // $guard$\n"); } } void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { - std::set<string> public_import_names; - for (int i = 0; i < file_->public_dependency_count(); i++) { - public_import_names.insert(file_->public_dependency(i)->name()); - } - + Formatter format(printer, variables_); for (int i = 0; i < file_->dependency_count(); i++) { - const bool use_system_include = IsWellKnownMessage(file_->dependency(i)); - const string& name = file_->dependency(i)->name(); - bool public_import = (public_import_names.count(name) != 0); - string basename = StripProto(name); + string basename = StripProto(file_->dependency(i)->name()); + // Do not import weak deps. + if (IsDepWeak(file_->dependency(i))) continue; - printer->Print( - "#include $left$$dependency$.pb.h$right$$iwyu$\n", - "dependency", basename, - "iwyu", (public_import) ? " // IWYU pragma: export" : "", - "left", use_system_include ? "<" : "\"", - "right", use_system_include ? ">" : "\""); + if (IsBootstrapProto(options_, file_)) { + GetBootstrapBasename(options_, basename, &basename); + } + + format("#include $1$\n", + CreateHeaderInclude(basename + ".pb.h", file_->dependency(i))); } } void FileGenerator::GenerateGlobalStateFunctionDeclarations( io::Printer* printer) { -// Forward-declare the AddDescriptors, InitDefaults because these are called -// by .pb.cc files depending on this file. - printer->Print( + Formatter format(printer, variables_); + // Forward-declare the AddDescriptors, InitDefaults because these are called + // by .pb.cc files depending on this file. + // + // The TableStruct is also outputted in weak_message_field.cc, because the + // weak fields must refer to table struct but cannot include the header. + // Also it annotates extra weak attributes. + // TODO(gerbens) make sure this situation is handled better. + format( "\n" - "namespace $file_namespace$ {\n" "// Internal implementation detail -- do not use these members.\n" - "struct $dllexport_decl$TableStruct {\n" + "struct $dllexport_decl $$tablename$ {\n" // These tables describe how to serialize and parse messages. Used // for table driven code. - " static const ::google::protobuf::internal::ParseTableField entries[];\n" - " static const ::google::protobuf::internal::AuxillaryParseTableField aux[];\n" - " static const ::google::protobuf::internal::ParseTable schema[$num$];\n" - " static const ::google::protobuf::internal::FieldMetadata field_metadata[];\n" - " static const ::google::protobuf::internal::SerializationTable " + " static const ::$proto_ns$::internal::ParseTableField entries[]\n" + " $GOOGLE_PROTOBUF$_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold);\n" + " static const ::$proto_ns$::internal::AuxillaryParseTableField aux[]\n" + " $GOOGLE_PROTOBUF$_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold);\n" + " static const ::$proto_ns$::internal::ParseTable schema[$1$]\n" + " $GOOGLE_PROTOBUF$_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold);\n" + " static const ::$proto_ns$::internal::FieldMetadata field_metadata[];\n" + " static const ::$proto_ns$::internal::SerializationTable " "serialization_table[];\n" - " static const ::google::protobuf::uint32 offsets[];\n" + " static const $uint32$ offsets[];\n" "};\n", - "file_namespace", FileLevelNamespace(file_), "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ", - "num", SimpleItoa(std::max(size_t(1), message_generators_.size()))); + std::max(size_t(1), message_generators_.size())); if (HasDescriptorMethods(file_, options_)) { - printer->Print( - "void $dllexport_decl$AddDescriptors();\n", "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + format("void $dllexport_decl $$add_descriptors$();\n"); + if (!options_.opensource_runtime) { + // TODO(gerbens) This is for proto1 interoperability. Remove when proto1 + // is gone. + format("void $dllexport_decl $$init_defaults$();\n"); + } } - printer->Print( - "} // namespace $file_namespace$\n", - "file_namespace", FileLevelNamespace(file_)); } void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { + Formatter format(printer, variables_); // Generate class definitions. for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { - printer->Print("\n"); - printer->Print(kThinSeparator); - printer->Print("\n"); + format("\n"); + format(kThinSeparator); + format("\n"); } message_generators_[i]->GenerateClassDefinition(printer); } @@ -1334,74 +1383,77 @@ void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { } void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { + Formatter format(printer, variables_); if (HasGenericServices(file_, options_)) { // Generate service definitions. for (int i = 0; i < service_generators_.size(); i++) { if (i > 0) { - printer->Print("\n"); - printer->Print(kThinSeparator); - printer->Print("\n"); + format("\n"); + format(kThinSeparator); + format("\n"); } service_generators_[i]->GenerateDeclarations(printer); } - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); + format("\n"); + format(kThickSeparator); + format("\n"); } } void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { // Declare extension identifiers. These are in global scope and so only // the global scope extensions. - for (int i = 0; i < file_->extension_count(); i++) { - extension_generators_owner_[i]->GenerateDeclaration(printer); + for (auto& extension_generator : extension_generators_) { + if (extension_generator->IsScoped()) continue; + extension_generator->GenerateDeclaration(printer); } } void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { + Formatter format(printer, variables_); // TODO(gerbens) remove pragmas when gcc is no longer used. Current version // of gcc fires a bogus error when compiled with strict-aliasing. - printer->Print( - "#ifdef __GNUC__\n" - " #pragma GCC diagnostic push\n" - " #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n" - "#endif // __GNUC__\n"); + format( + "#ifdef __GNUC__\n" + " #pragma GCC diagnostic push\n" + " #pragma GCC diagnostic ignored \"-Wstrict-aliasing\"\n" + "#endif // __GNUC__\n"); // Generate class inline methods. for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { - printer->Print(kThinSeparator); - printer->Print("\n"); + format(kThinSeparator); + format("\n"); } message_generators_[i]->GenerateInlineMethods(printer); } - printer->Print( - "#ifdef __GNUC__\n" - " #pragma GCC diagnostic pop\n" - "#endif // __GNUC__\n"); + format( + "#ifdef __GNUC__\n" + " #pragma GCC diagnostic pop\n" + "#endif // __GNUC__\n"); for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { - printer->Print(kThinSeparator); - printer->Print("\n"); + format(kThinSeparator); + format("\n"); } } } void FileGenerator::GenerateProto2NamespaceEnumSpecializations( io::Printer* printer) { + Formatter format(printer, variables_); // Emit GetEnumDescriptor specializations into google::protobuf namespace: if (HasEnumDefinitions(file_)) { - printer->Print( - "\n" - "namespace google {\nnamespace protobuf {\n" - "\n"); - for (int i = 0; i < enum_generators_.size(); i++) { - enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + format("\n"); + { + NamespaceOpener proto_ns(ProtobufNamespace(options_), format); + format("\n"); + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + format("\n"); } - printer->Print( - "\n" - "} // namespace protobuf\n} // namespace google\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index 94da9a14..9dfdf50f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -44,23 +44,26 @@ #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/scc.h> namespace google { namespace protobuf { - class FileDescriptor; // descriptor.h - namespace io { - class Printer; // printer.h - } +class FileDescriptor; // descriptor.h +namespace io { +class Printer; // printer.h } +} // namespace protobuf +} // namespace google +namespace google { namespace protobuf { namespace compiler { namespace cpp { -class EnumGenerator; // enum.h -class MessageGenerator; // message.h -class ServiceGenerator; // service.h -class ExtensionGenerator; // extension.h +class EnumGenerator; // enum.h +class MessageGenerator; // message.h +class ServiceGenerator; // service.h +class ExtensionGenerator; // extension.h class FileGenerator { public: @@ -71,14 +74,12 @@ class FileGenerator { // Shared code between the two header generators below. void GenerateHeader(io::Printer* printer); - // info_path, if non-empty, should be the path (relative to printer's output) - // to the metadata file describing this proto header. - void GenerateProtoHeader(io::Printer* printer, - const string& info_path); - // info_path, if non-empty, should be the path (relative to printer's output) - // to the metadata file describing this PB header. - void GeneratePBHeader(io::Printer* printer, - const string& info_path); + // info_path, if non-empty, should be the path (relative to printer's + // output) to the metadata file describing this proto header. + void GenerateProtoHeader(io::Printer* printer, const string& info_path); + // info_path, if non-empty, should be the path (relative to printer's + // output) to the metadata file describing this PB header. + void GeneratePBHeader(io::Printer* printer, const string& info_path); void GenerateSource(io::Printer* printer); int NumMessages() const { return message_generators_.size(); } @@ -90,6 +91,20 @@ class FileGenerator { // Internal type used by GenerateForwardDeclarations (defined in file.cc). class ForwardDeclarations; + void IncludeFile(const string& google3_name, io::Printer* printer) { + DoIncludeFile(google3_name, false, printer); + } + void IncludeFileAndExport(const string& google3_name, io::Printer* printer) { + DoIncludeFile(google3_name, true, printer); + } + void DoIncludeFile(const string& google3_name, bool do_export, + io::Printer* printer); + + string CreateHeaderInclude(const string& basename, + const FileDescriptor* file); + void GenerateInternalForwardDeclarations( + const std::vector<const FieldDescriptor*>& fields, const Options& options, + MessageSCCAnalyzer* scc_analyzer, io::Printer* printer); void GenerateSourceIncludes(io::Printer* printer); void GenerateSourceDefaultInstance(int idx, io::Printer* printer); @@ -100,11 +115,6 @@ class FileGenerator { // For other imports, generates their forward-declarations. void GenerateForwardDeclarations(io::Printer* printer); - // Internal helper used by GenerateForwardDeclarations: fills 'decls' - // with all necessary forward-declarations for this file and its - // transient depednencies. - void FillForwardDeclarations(ForwardDeclarations* decls); - // Generates top or bottom of a header file. void GenerateTopHeaderGuard(io::Printer* printer, const string& filename_identifier); @@ -138,13 +148,13 @@ class FileGenerator { void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer); - // Sometimes the names we use in a .proto file happen to be defined as macros - // on some platforms (e.g., macro/minor used in plugin.proto are defined as - // macros in sys/types.h on FreeBSD and a few other platforms). To make the - // generated code compile on these platforms, we either have to undef the - // macro for these few platforms, or rename the field name for all platforms. - // Since these names are part of protobuf public API, renaming is generally - // a breaking change so we prefer the #undef approach. + // Sometimes the names we use in a .proto file happen to be defined as + // macros on some platforms (e.g., macro/minor used in plugin.proto are + // defined as macros in sys/types.h on FreeBSD and a few other platforms). + // To make the generated code compile on these platforms, we either have to + // undef the macro for these few platforms, or rename the field name for all + // platforms. Since these names are part of protobuf public API, renaming is + // generally a breaking change so we prefer the #undef approach. void GenerateMacroUndefs(io::Printer* printer); bool IsSCCRepresentative(const Descriptor* d) { @@ -157,30 +167,29 @@ class FileGenerator { return scc_analyzer_.GetSCC(d); } + bool IsDepWeak(const FileDescriptor* dep) const { + if (weak_deps_.count(dep) != 0) { + GOOGLE_CHECK(!options_.opensource_runtime); + return true; + } + return false; + } + + std::set<const FileDescriptor*> weak_deps_; const FileDescriptor* file_; const Options options_; - SCCAnalyzer scc_analyzer_; + MessageSCCAnalyzer scc_analyzer_; + std::map<string, string> variables_; // Contains the post-order walk of all the messages (and child messages) in // this file. If you need a pre-order walk just reverse iterate. - std::vector<MessageGenerator*> message_generators_; - std::vector<EnumGenerator*> enum_generators_; - std::vector<ServiceGenerator*> service_generators_; - std::vector<ExtensionGenerator*> extension_generators_; - - // These members are just for owning (and thus proper deleting). - // Nested (enum/extension)_generators are owned by child messages. - std::unique_ptr<std::unique_ptr<EnumGenerator> []> enum_generators_owner_; - std::unique_ptr<std::unique_ptr<ServiceGenerator> []> - service_generators_owner_; - std::unique_ptr<std::unique_ptr<ExtensionGenerator> []> - extension_generators_owner_; - - // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}. - std::vector<string> package_parts_; + std::vector<std::unique_ptr<MessageGenerator>> message_generators_; + std::vector<std::unique_ptr<EnumGenerator>> enum_generators_; + std::vector<std::unique_ptr<ServiceGenerator>> service_generators_; + std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); }; @@ -188,6 +197,6 @@ class FileGenerator { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index 20bb8a1a..79f773ee 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -77,6 +77,21 @@ bool CppGenerator::Generate(const FileDescriptor* file, // __declspec(dllimport) depending on what is being compiled. // Options file_options; + + switch (runtime_) { + case Runtime::kGoogle3: + file_options.opensource_runtime = false; + break; + case Runtime::kOpensource: + file_options.opensource_runtime = true; + file_options.opensource_include_paths = true; + break; + case Runtime::kOpensourceGoogle3: + file_options.opensource_runtime = true; + file_options.opensource_include_paths = false; + break; + } + for (int i = 0; i < options.size(); i++) { if (options[i].first == "dllexport_decl") { file_options.dllexport_decl = options[i].second; @@ -108,7 +123,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, // The safe_boundary_check option controls behavior for Google-internal // protobuf APIs. - if (file_options.safe_boundary_check) { + if (file_options.safe_boundary_check && file_options.opensource_runtime) { *error = "The safe_boundary_check option is not supported outside of Google."; return false; @@ -119,6 +134,10 @@ bool CppGenerator::Generate(const FileDescriptor* file, string basename = StripProto(file->name()); + if (MaybeBootstrap(file_options, generator_context, file_options.bootstrap, + &basename)) { + return true; + } FileGenerator file_generator(file, file_options); @@ -184,8 +203,8 @@ bool CppGenerator::Generate(const FileDescriptor* file, } for (int i = 0; i < num_cc_files; i++) { // TODO(gerbens) Agree on naming scheme. - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(basename + "." + SimpleItoa(i) + ".cc")); + std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + basename + ".out/" + SimpleItoa(i) + ".cc")); io::Printer printer(output.get(), '$'); if (i < file_generator.NumMessages()) { file_generator.GenerateSourceForMessage(i, &printer); diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h index 3d517cf4..06d3c36f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.h +++ b/src/google/protobuf/compiler/cpp/cpp_generator.h @@ -54,6 +54,20 @@ class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator { CppGenerator(); ~CppGenerator(); + enum class LIBPROTOC_EXPORT Runtime { + kGoogle3, // Use the internal google3 runtime. + kOpensource, // Use the open-source runtime. + + // Use the open-source runtime with google3 #include paths. We make these + // absolute to avoid ambiguity, so the runtime will be #included like: + // #include "third_party/protobuf/<...>/google/protobuf/message.h" + kOpensourceGoogle3 + }; + + void set_runtime(Runtime runtime) { + runtime_ = runtime; + } + // implements CodeGenerator ---------------------------------------- bool Generate(const FileDescriptor* file, const string& parameter, @@ -61,12 +75,13 @@ class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator { string* error) const; private: + Runtime runtime_ = Runtime::kOpensource; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator); }; } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 163dac0a..e565a0c5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -32,21 +32,25 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/stubs/hash.h> #include <limits> #include <map> #include <queue> +#include <unordered_set> #include <vector> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/scc.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/wire_format_lite.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> +#include <google/protobuf/stubs/hash.h> namespace google { @@ -83,15 +87,15 @@ const char* const kKeywordList[] = { "while", "xor", "xor_eq" }; -hash_set<string> MakeKeywordsMap() { - hash_set<string> result; +std::unordered_set<string> MakeKeywordsMap() { + std::unordered_set<string> result; for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) { result.insert(kKeywordList[i]); } return result; } -hash_set<string> kKeywords = MakeKeywordsMap(); +std::unordered_set<string> kKeywords = MakeKeywordsMap(); // Returns whether the provided descriptor has an extension. This includes its // nested types. @@ -131,8 +135,55 @@ string Base63(I n, int k) { return res; } +string IntTypeName(const Options& options, const string& type) { + if (options.opensource_runtime) { + return "::google::protobuf::" + type; + } else { + return "::" + type; + } +} + +string StringTypeName(const Options& options) { + return options.opensource_runtime ? "::std::string" : "::std::string"; +} + +void SetIntVar(const Options& options, const string& type, + std::map<string, string>* variables) { + (*variables)[type] = IntTypeName(options, type); +} + } // namespace +void SetCommonVars(const Options& options, + std::map<string, string>* variables) { + (*variables)["proto_ns"] = ProtobufNamespace(options); + + // Warning: there is some clever naming/splitting here to avoid extract script + // rewrites. The names of these variables must not be things that the extract + // script will rewrite. That's why we use "CHK" (for example) instead of + // "GOOGLE_CHECK". + if (options.opensource_runtime) { + (*variables)["GOOGLE_PROTOBUF"] = "GOOGLE_PROTOBUF"; + (*variables)["CHK"] = "GOOGLE_CHECK"; + (*variables)["DCHK"] = "GOOGLE_DCHECK"; + } else { + // These values are things the extract script would rewrite if we did not + // split them. It might not strictly matter since we don't generate google3 + // code in open-source. But it's good to prevent surprising things from + // happening. + (*variables)["GOOGLE_PROTOBUF"] = "GOOGLE3" "_PROTOBUF"; + (*variables)["CHK"] = "CH" "ECK"; + (*variables)["DCHK"] = "DCH" "ECK"; + } + + SetIntVar(options, "uint8", variables); + SetIntVar(options, "uint32", variables); + SetIntVar(options, "uint64", variables); + SetIntVar(options, "int32", variables); + SetIntVar(options, "int64", variables); + (*variables)["string"] = StringTypeName(options); +} + string UnderscoresToCamelCase(const string& input, bool cap_next_letter) { string result; // Note: I distrust ctype.h due to locales. @@ -205,11 +256,25 @@ string ClassName(const EnumDescriptor* enum_descriptor) { } } +string QualifiedClassName(const Descriptor* d) { + return Namespace(d) + "::" + ClassName(d); +} + +string QualifiedClassName(const EnumDescriptor* d) { + return Namespace(d) + "::" + ClassName(d); +} + string Namespace(const string& package) { if (package.empty()) return ""; return "::" + DotsToColons(package); } +string Namespace(const Descriptor* d) { return Namespace(d->file()); } + +string Namespace(const FieldDescriptor* d) { return Namespace(d->file()); } + +string Namespace(const EnumDescriptor* d) { return Namespace(d->file()); } + string DefaultInstanceName(const Descriptor* descriptor) { string prefix = descriptor->file()->package().empty() ? "" : "::"; return prefix + DotsToColons(descriptor->file()->package()) + "::_" + @@ -221,9 +286,9 @@ string ReferenceFunctionName(const Descriptor* descriptor) { } string SuperClassName(const Descriptor* descriptor, const Options& options) { - return HasDescriptorMethods(descriptor->file(), options) - ? "::google::protobuf::Message" - : "::google::protobuf::MessageLite"; + return "::" + ProtobufNamespace(options) + + (HasDescriptorMethods(descriptor->file(), options) ? "::Message" + : "::MessageLite"); } string FieldName(const FieldDescriptor* field) { @@ -318,6 +383,38 @@ const char* PrimitiveTypeName(FieldDescriptor::CppType type) { return NULL; } +string PrimitiveTypeName(const Options& options, + FieldDescriptor::CppType type) { + switch (type) { + case FieldDescriptor::CPPTYPE_INT32: + return IntTypeName(options, "int32"); + case FieldDescriptor::CPPTYPE_INT64: + return IntTypeName(options, "int64"); + case FieldDescriptor::CPPTYPE_UINT32: + return IntTypeName(options, "uint32"); + case FieldDescriptor::CPPTYPE_UINT64: + return IntTypeName(options, "uint64"); + case FieldDescriptor::CPPTYPE_DOUBLE: + return "double"; + case FieldDescriptor::CPPTYPE_FLOAT: + return "float"; + case FieldDescriptor::CPPTYPE_BOOL: + return "bool"; + case FieldDescriptor::CPPTYPE_ENUM: + return "int"; + case FieldDescriptor::CPPTYPE_STRING: + return StringTypeName(options); + case FieldDescriptor::CPPTYPE_MESSAGE: + return ""; + + // No default because we want the compiler to complain if any new + // CppTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { switch (type) { case FieldDescriptor::TYPE_INT32 : return "Int32"; @@ -349,44 +446,59 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { } string Int32ToString(int number) { - // gcc rejects the decimal form of kint32min. if (number == kint32min) { - GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error); - return "(~0x7fffffff)"; + // This needs to be special-cased, see explanation here: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661 + return SimpleItoa(number + 1) + " - 1"; } else { return SimpleItoa(number); } } -string Int64ToString(int64 number) { - // gcc rejects the decimal form of kint64min +string Int64ToString(const string& macro_prefix, int64 number) { if (number == kint64min) { - // Make sure we are in a 2's complement system. - GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(~0x7fffffffffffffff), - kint64min_value_error); - return "GOOGLE_LONGLONG(~0x7fffffffffffffff)"; + // This needs to be special-cased, see explanation here: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661 + return macro_prefix + "_LONGLONG(" + SimpleItoa(number + 1) + + ") - 1"; } - return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")"; + return macro_prefix + "_LONGLONG(" + SimpleItoa(number) + ")"; +} + +string UInt64ToString(const string& macro_prefix, uint64 number) { + return macro_prefix + "_ULONGLONG(" + SimpleItoa(number) + ")"; } string DefaultValue(const FieldDescriptor* field) { switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT64: + return Int64ToString("GG", field->default_value_int64()); + case FieldDescriptor::CPPTYPE_UINT64: + return UInt64ToString("GG", field->default_value_uint64()); + default: + return DefaultValue(Options(), field); + } +} + +string DefaultValue(const Options& options, const FieldDescriptor* field) { + switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: return Int32ToString(field->default_value_int32()); case FieldDescriptor::CPPTYPE_UINT32: return SimpleItoa(field->default_value_uint32()) + "u"; case FieldDescriptor::CPPTYPE_INT64: - return Int64ToString(field->default_value_int64()); + return Int64ToString(MacroPrefix(options), field->default_value_int64()); case FieldDescriptor::CPPTYPE_UINT64: - return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; + return UInt64ToString(MacroPrefix(options), + field->default_value_uint64()); case FieldDescriptor::CPPTYPE_DOUBLE: { double value = field->default_value_double(); if (value == std::numeric_limits<double>::infinity()) { - return "::google::protobuf::internal::Infinity()"; + return "std::numeric_limits<double>::infinity()"; } else if (value == -std::numeric_limits<double>::infinity()) { - return "-::google::protobuf::internal::Infinity()"; + return "-std::numeric_limits<double>::infinity()"; } else if (value != value) { - return "::google::protobuf::internal::NaN()"; + return "std::numeric_limits<double>::quiet_NaN()"; } else { return SimpleDtoa(value); } @@ -395,11 +507,11 @@ string DefaultValue(const FieldDescriptor* field) { { float value = field->default_value_float(); if (value == std::numeric_limits<float>::infinity()) { - return "static_cast<float>(::google::protobuf::internal::Infinity())"; + return "std::numeric_limits<float>::infinity()"; } else if (value == -std::numeric_limits<float>::infinity()) { - return "static_cast<float>(-::google::protobuf::internal::Infinity())"; + return "-std::numeric_limits<float>::infinity()"; } else if (value != value) { - return "static_cast<float>(::google::protobuf::internal::NaN())"; + return "std::numeric_limits<float>::quiet_NaN()"; } else { string float_value = SimpleFtoa(value); // If floating point value contains a period (.) or an exponent @@ -450,8 +562,9 @@ string FilenameIdentifier(const string& filename) { return result; } -string FileLevelNamespace(const string& filename) { - return "protobuf_" + FilenameIdentifier(filename); +string UniqueName(const string& name, const string& filename, + const Options& options) { + return name + "_" + FilenameIdentifier(filename); } // Return the qualified C++ name for a file level symbol. @@ -487,6 +600,126 @@ string SafeFunctionName(const Descriptor* descriptor, return function_name; } +static bool HasLazyFields(const Descriptor* descriptor, + const Options& options) { + for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) { + if (IsLazy(descriptor->field(field_idx), options)) { + return true; + } + } + for (int idx = 0; idx < descriptor->extension_count(); idx++) { + if (IsLazy(descriptor->extension(idx), options)) { + return true; + } + } + for (int idx = 0; idx < descriptor->nested_type_count(); idx++) { + if (HasLazyFields(descriptor->nested_type(idx), options)) { + return true; + } + } + return false; +} + +// Does the given FileDescriptor use lazy fields? +bool HasLazyFields(const FileDescriptor* file, const Options& options) { + for (int i = 0; i < file->message_type_count(); i++) { + const Descriptor* descriptor(file->message_type(i)); + if (HasLazyFields(descriptor, options)) { + return true; + } + } + for (int field_idx = 0; field_idx < file->extension_count(); field_idx++) { + if (IsLazy(file->extension(field_idx), options)) { + return true; + } + } + return false; +} + +static bool HasRepeatedFields(const Descriptor* descriptor) { + for (int i = 0; i < descriptor->field_count(); ++i) { + if (descriptor->field(i)->label() == FieldDescriptor::LABEL_REPEATED) { + return true; + } + } + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasRepeatedFields(descriptor->nested_type(i))) return true; + } + return false; +} + +bool HasRepeatedFields(const FileDescriptor* file) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasRepeatedFields(file->message_type(i))) return true; + } + return false; +} + +static bool IsStringPieceField(const FieldDescriptor* field, + const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE; +} + +static bool HasStringPieceFields(const Descriptor* descriptor, + const Options& options) { + for (int i = 0; i < descriptor->field_count(); ++i) { + if (IsStringPieceField(descriptor->field(i), options)) return true; + } + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasStringPieceFields(descriptor->nested_type(i), options)) return true; + } + return false; +} + +bool HasStringPieceFields(const FileDescriptor* file, const Options& options) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasStringPieceFields(file->message_type(i), options)) return true; + } + return false; +} + +static bool IsCordField(const FieldDescriptor* field, const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::CORD; +} + +static bool HasCordFields(const Descriptor* descriptor, + const Options& options) { + for (int i = 0; i < descriptor->field_count(); ++i) { + if (IsCordField(descriptor->field(i), options)) return true; + } + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasCordFields(descriptor->nested_type(i), options)) return true; + } + return false; +} + +bool HasCordFields(const FileDescriptor* file, const Options& options) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasCordFields(file->message_type(i), options)) return true; + } + return false; +} + +static bool HasExtensionsOrExtendableMessage(const Descriptor* descriptor) { + if (descriptor->extension_range_count() > 0) return true; + if (descriptor->extension_count() > 0) return true; + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + if (HasExtensionsOrExtendableMessage(descriptor->nested_type(i))) { + return true; + } + } + return false; +} + +bool HasExtensionsOrExtendableMessage(const FileDescriptor* file) { + if (file->extension_count() > 0) return true; + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasExtensionsOrExtendableMessage(file->message_type(i))) return true; + } + return false; +} static bool HasMapFields(const Descriptor* descriptor) { for (int i = 0; i < descriptor->field_count(); ++i) { @@ -543,11 +776,16 @@ bool IsStringOrMessage(const FieldDescriptor* field) { return false; } -FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) { +FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field, + const Options& options) { GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); - // Open-source protobuf release only supports STRING ctype. - return FieldOptions::STRING; - + if (options.opensource_runtime) { + // Open-source protobuf release only supports STRING ctype. + return FieldOptions::STRING; + } else { + // Google-internal supports all ctypes. + return field->options().ctype(); + } } bool IsAnyMessage(const FileDescriptor* descriptor) { @@ -569,62 +807,81 @@ enum Utf8CheckMode { NONE = 2, // No UTF-8 check. }; +static bool FieldEnforceUtf8(const FieldDescriptor* field, + const Options& options) { + return true; +} + +static bool FileUtf8Verification(const FileDescriptor* file, + const Options& options) { + return true; +} + // Which level of UTF-8 enforcemant is placed on this file. static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, const Options& options) { - if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + FieldEnforceUtf8(field, options)) { return STRICT; } else if (GetOptimizeFor(field->file(), options) != - FileOptions::LITE_RUNTIME) { + FileOptions::LITE_RUNTIME && + FileUtf8Verification(field->file(), options)) { return VERIFY; } else { return NONE; } } +string GetUtf8Suffix(const FieldDescriptor* field, const Options& options) { + switch (GetUtf8CheckMode(field, options)) { + case STRICT: + return "UTF8"; + case VERIFY: + return "UTF8Verify"; + case NONE: + default: // Some build configs warn on missing return without default. + return ""; + } +} + static void GenerateUtf8CheckCode(const FieldDescriptor* field, const Options& options, bool for_parse, - const std::map<string, string>& variables, const char* parameters, const char* strict_function, const char* verify_function, - io::Printer* printer) { + const Formatter& format) { switch (GetUtf8CheckMode(field, options)) { case STRICT: { if (for_parse) { - printer->Print("DO_("); + format("DO_("); } - printer->Print( - "::google::protobuf::internal::WireFormatLite::$function$(\n", - "function", strict_function); - printer->Indent(); - printer->Print(variables, parameters); + format("::$proto_ns$::internal::WireFormatLite::$1$(\n", strict_function); + format.Indent(); + format(parameters); if (for_parse) { - printer->Print("::google::protobuf::internal::WireFormatLite::PARSE,\n"); + format("::$proto_ns$::internal::WireFormatLite::PARSE,\n"); } else { - printer->Print("::google::protobuf::internal::WireFormatLite::SERIALIZE,\n"); + format("::$proto_ns$::internal::WireFormatLite::SERIALIZE,\n"); } - printer->Print("\"$full_name$\")", "full_name", field->full_name()); + format("\"$1$\")", field->full_name()); if (for_parse) { - printer->Print(")"); + format(")"); } - printer->Print(";\n"); - printer->Outdent(); + format(";\n"); + format.Outdent(); break; } case VERIFY: { - printer->Print( - "::google::protobuf::internal::WireFormat::$function$(\n", - "function", verify_function); - printer->Indent(); - printer->Print(variables, parameters); + format("::$proto_ns$::internal::WireFormat::$1$(\n", verify_function); + format.Indent(); + format(parameters); if (for_parse) { - printer->Print("::google::protobuf::internal::WireFormat::PARSE,\n"); + format("::$proto_ns$::internal::WireFormat::PARSE,\n"); } else { - printer->Print("::google::protobuf::internal::WireFormat::SERIALIZE,\n"); + format("::$proto_ns$::internal::WireFormat::SERIALIZE,\n"); } - printer->Print("\"$full_name$\");\n", "full_name", field->full_name()); - printer->Outdent(); + format("\"$1$\");\n", field->full_name()); + format.Outdent(); break; } case NONE: @@ -634,21 +891,19 @@ static void GenerateUtf8CheckCode(const FieldDescriptor* field, void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, const Options& options, bool for_parse, - const std::map<string, string>& variables, const char* parameters, - io::Printer* printer) { - GenerateUtf8CheckCode(field, options, for_parse, variables, parameters, + const Formatter& format) { + GenerateUtf8CheckCode(field, options, for_parse, parameters, "VerifyUtf8String", "VerifyUTF8StringNamedField", - printer); + format); } void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, const Options& options, bool for_parse, - const std::map<string, string>& variables, const char* parameters, - io::Printer* printer) { - GenerateUtf8CheckCode(field, options, for_parse, variables, parameters, - "VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer); + const Formatter& format) { + GenerateUtf8CheckCode(field, options, for_parse, parameters, "VerifyUtf8Cord", + "VerifyUTF8CordNamedField", format); } namespace { @@ -669,11 +924,17 @@ void FlattenMessagesInFile(const FileDescriptor* file, } } -bool HasWeakFields(const Descriptor* descriptor) { +bool HasWeakFields(const Descriptor* descriptor, const Options& options) { + for (int i = 0; i < descriptor->field_count(); i++) { + if (IsWeak(descriptor->field(i), options)) return true; + } return false; } -bool HasWeakFields(const FileDescriptor* file) { +bool HasWeakFields(const FileDescriptor* file, const Options& options) { + for (int i = 0; i < file->message_type_count(); ++i) { + if (HasWeakFields(file->message_type(i), options)) return true; + } return false; } @@ -684,7 +945,7 @@ bool UsingImplicitWeakFields(const FileDescriptor* file, } bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, - SCCAnalyzer* scc_analyzer) { + MessageSCCAnalyzer* scc_analyzer) { return UsingImplicitWeakFields(field->file(), options) && field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_required() && !field->is_map() && @@ -696,85 +957,18 @@ bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, scc_analyzer->GetSCC(field->message_type()); } -struct CompareDescriptors { - bool operator()(const Descriptor* a, const Descriptor* b) { - return a->full_name() < b->full_name(); - } -}; - -SCCAnalyzer::NodeData SCCAnalyzer::DFS(const Descriptor* descriptor) { - // Must not have visited already. - GOOGLE_DCHECK_EQ(cache_.count(descriptor), 0); - - // Mark visited by inserting in map. - NodeData& result = cache_[descriptor]; - // Initialize data structures. - result.index = result.lowlink = index_++; - stack_.push_back(descriptor); - - // Recurse the fields / nodes in graph - for (int i = 0; i < descriptor->field_count(); i++) { - const Descriptor* child = descriptor->field(i)->message_type(); - if (child) { - if (cache_.count(child) == 0) { - // unexplored node - NodeData child_data = DFS(child); - result.lowlink = std::min(result.lowlink, child_data.lowlink); - } else { - NodeData child_data = cache_[child]; - if (child_data.scc == NULL) { - // Still in the stack_ so we found a back edge - result.lowlink = std::min(result.lowlink, child_data.index); - } - } - } - } - if (result.index == result.lowlink) { - // This is the root of a strongly connected component - SCC* scc = CreateSCC(); - while (true) { - const Descriptor* scc_desc = stack_.back(); - scc->descriptors.push_back(scc_desc); - // Remove from stack - stack_.pop_back(); - cache_[scc_desc].scc = scc; - - if (scc_desc == descriptor) break; - } - - // The order of descriptors is random and depends how this SCC was - // discovered. In-order to ensure maximum stability we sort it by name. - std::sort(scc->descriptors.begin(), scc->descriptors.end(), - CompareDescriptors()); - AddChildren(scc); - } - return result; -} - -void SCCAnalyzer::AddChildren(SCC* scc) { - std::set<const SCC*> seen; - for (int i = 0; i < scc->descriptors.size(); i++) { - const Descriptor* descriptor = scc->descriptors[i]; - for (int j = 0; j < descriptor->field_count(); j++) { - const Descriptor* child_msg = descriptor->field(j)->message_type(); - if (child_msg) { - const SCC* child = GetSCC(child_msg); - if (child == scc) continue; - if (seen.insert(child).second) { - scc->children.push_back(child); - } - } - } - } -} - -MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) { +MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) { if (analysis_cache_.count(scc)) return analysis_cache_[scc]; - MessageAnalysis result = MessageAnalysis(); + MessageAnalysis result{}; for (int i = 0; i < scc->descriptors.size(); i++) { const Descriptor* descriptor = scc->descriptors[i]; if (descriptor->extension_range_count() > 0) { result.contains_extension = true; + // Extensions are found by looking up default_instance and extension + // number in a map. So you'd maybe expect here + // result.constructor_requires_initialization = true; + // However the extension registration mechanism already makes sure + // the default will be initialized. } for (int i = 0; i < descriptor->field_count(); i++) { const FieldDescriptor* field = descriptor->field(i); @@ -784,6 +978,7 @@ MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) { switch (field->type()) { case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_BYTES: { + result.constructor_requires_initialization = true; if (field->options().ctype() == FieldOptions::CORD) { result.contains_cord = true; } @@ -791,7 +986,8 @@ MessageAnalysis SCCAnalyzer::GetSCCAnalysis(const SCC* scc) { } case FieldDescriptor::TYPE_GROUP: case FieldDescriptor::TYPE_MESSAGE: { - const SCC* child = GetSCC(field->message_type()); + result.constructor_requires_initialization = true; + const SCC* child = analyzer_.GetSCC(field->message_type()); if (child != scc) { MessageAnalysis analysis = GetSCCAnalysis(child); result.contains_cord |= analysis.contains_cord; @@ -860,6 +1056,543 @@ void ListAllTypesForServices(const FileDescriptor* fd, } } +bool GetBootstrapBasename(const Options& options, const string& basename, + string* bootstrap_basename) { + if (options.opensource_runtime) { + return false; + } + + std::unordered_map<string, string> bootstrap_mapping{ + {"net/proto2/proto/descriptor", + "net/proto2/internal/descriptor"}, + {"net/proto2/compiler/proto/plugin", + "net/proto2/compiler/proto/plugin"}, + {"net/proto2/compiler/proto/profile", + "net/proto2/compiler/proto/profile_bootstrap"}, + }; + auto iter = bootstrap_mapping.find(basename); + if (iter == bootstrap_mapping.end()) { + *bootstrap_basename = basename; + return false; + } else { + *bootstrap_basename = iter->second; + return true; + } +} + +bool IsBootstrapProto(const Options& options, const FileDescriptor* file) { + string my_name = StripProto(file->name()); + return GetBootstrapBasename(options, my_name, &my_name); +} + +bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, + bool bootstrap_flag, string* basename) { + string bootstrap_basename; + if (!GetBootstrapBasename(options, *basename, &bootstrap_basename)) { + return false; + } + + if (bootstrap_flag) { + // Adjust basename, but don't abort code generation. + *basename = bootstrap_basename; + return false; + } else { + string forward_to_basename = bootstrap_basename; + + // Generate forwarding headers and empty .pb.cc. + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".pb.h")); + io::Printer printer(output.get(), '$', nullptr); + printer.Print( + "#ifndef PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n" + "#define PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n" + "#include \"$forward_to_basename$.pb.h\" // IWYU pragma: export\n" + "#endif // PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PB_H\n", + "forward_to_basename", forward_to_basename, + "filename_identifier", FilenameIdentifier(*basename)); + + if (!options.opensource_runtime) { + // HACK HACK HACK, tech debt from the deeps of proto1 and SWIG + // protocoltype is SWIG'ed and we need to forward + if (*basename == "net/proto/protocoltype") { + printer.Print( + "#ifdef SWIG\n" + "%include \"$forward_to_basename$.pb.h\"\n" + "#endif // SWIG\n", + "forward_to_basename", forward_to_basename); + } + } + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".proto.h")); + io::Printer printer(output.get(), '$', nullptr); + printer.Print( + "#ifndef PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n" + "#define PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n" + "#include \"$forward_to_basename$.proto.h\" // IWYU pragma: " + "export\n" + "#endif // " + "PROTOBUF_INCLUDED_$filename_identifier$_FORWARD_PROTO_H\n", + "forward_to_basename", forward_to_basename, + "filename_identifier", FilenameIdentifier(*basename)); + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".pb.cc")); + io::Printer printer(output.get(), '$', nullptr); + printer.Print("\n"); + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".pb.h.meta")); + } + + { + std::unique_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(*basename + ".proto.h.meta")); + } + + // Abort code generation. + return true; + } +} + +bool ShouldRepeat(const FieldDescriptor* descriptor, + internal::WireFormatLite::WireType wiretype) { + return descriptor->is_repeated() && + (!descriptor->is_packable() || + wiretype != internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); +} + +void GenerateCaseBody(internal::WireFormatLite::WireType wiretype, + const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer, + const Formatter& format) { + using internal::WireFormat; + using internal::WireFormatLite; + + if (ShouldRepeat(field, wiretype)) { + format("do {\n"); + format.Indent(); + } + switch (wiretype) { + case WireFormatLite::WIRETYPE_VARINT: { + format( + "$uint64$ val;\n" + "ptr = Varint::Parse64(ptr, &val);\n" + "if (!ptr) goto error;\n"); + string type = PrimitiveTypeName(options, field->cpp_type()); + if (field->type() == FieldDescriptor::TYPE_SINT32 || + field->type() == FieldDescriptor::TYPE_SINT64) { + int size = EstimateAlignmentSize(field) * 8; + format( + "$1$ value = " + "::$proto_ns$::internal::WireFormatLite::ZigZagDecode$2$(val);\n", + type, size); + } else if (field->type() == FieldDescriptor::TYPE_ENUM && + !IsProto1(field->file(), options)) { + if (!HasPreservingUnknownEnumSemantics(field->file())) { + format( + "if (!$1$_IsValid(val)) {\n" + " ::$proto_ns$::internal::WriteVarint($2$, val, " + "msg->mutable_unknown_fields());\n" + " break;\n" + "}\n", + QualifiedClassName(field->enum_type()), field->number()); + } + format("$1$ value = static_cast<$1$>(val);\n", + QualifiedClassName(field->enum_type())); + } else { + format("$1$ value = val;\n", type); + } + if (field->is_repeated()) { + format("msg->add_$1$(value);\n", FieldName(field)); + } else { + format("msg->set_$1$(value);\n", FieldName(field)); + } + break; + } + case WireFormatLite::WIRETYPE_FIXED64: { + string type = PrimitiveTypeName(options, field->cpp_type()); + format( + "$1$ val;\n" + "::std::memcpy(&val, ptr, 8);\n" + "ptr += 8;\n", + type); + if (field->is_repeated()) { + format("msg->add_$1$(val);\n", FieldName(field)); + } else { + format("msg->set_$1$(val);\n", FieldName(field)); + } + break; + } + case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: { + format( + "ptr = Varint::Parse32Inline(ptr, &size);\n" + "if (!ptr) goto error;\n"); + if (!IsProto1(field->file(), options) && field->is_packable()) { + if (!HasPreservingUnknownEnumSemantics(field->file()) && + field->type() == FieldDescriptor::TYPE_ENUM) { + format( + "ctx->extra_parse_data().SetEnumValidator($1$_IsValid, " + "msg->mutable_unknown_fields(), $2$);\n" + "parser_till_end = " + "::$proto_ns$::internal::PackedValidEnumParser$3$;\n" + "object = msg->mutable_$4$();\n", + QualifiedClassName(field->enum_type()), field->number(), + UseUnknownFieldSet(field->file(), options) ? "" : "Lite", + FieldName(field)); + } else { + format( + "parser_till_end = ::$proto_ns$::internal::Packed$1$Parser;\n" + "object = msg->mutable_$2$();\n", + DeclaredTypeMethodName(field->type()), FieldName(field)); + } + } else { + auto field_type = field->type(); + if (IsProto1(field->file(), options)) { + if (field->is_packable()) { + // Sigh ... packed fields endup as a string in proto1 + field_type = FieldDescriptor::TYPE_BYTES; + } + if (field_type == FieldDescriptor::TYPE_STRING) { + // In proto1 strings are treated as bytes + field_type = FieldDescriptor::TYPE_BYTES; + } + } + string utf8 = ""; + switch (field_type) { + case FieldDescriptor::TYPE_STRING: + utf8 = GetUtf8Suffix(field, options); + if (!utf8.empty()) { + string name = "nullptr"; + if (HasDescriptorMethods(field->file(), options)) { + name = field->full_name(); + } + format("ctx->extra_parse_data().SetFieldName(\"$1$\");\n", name); + } + [[clang::fallthrough]]; + case FieldDescriptor::TYPE_BYTES: { + if (field->options().ctype() == FieldOptions::STRING || + (IsProto1(field->file(), options) && + field->options().ctype() == FieldOptions::STRING_PIECE)) { + format( + "parser_till_end = ::$proto_ns$::internal::StringParser$1$;\n" + "$string$* str = msg->$2$_$3$();\n" + "str->clear();\n", + utf8, + field->is_repeated() && !field->is_map() && + !field->is_packable() + ? "add" + : "mutable", + FieldName(field)); + } else if (field->options().ctype() == FieldOptions::CORD) { + string cord_parser = "CordParser" + utf8; + format( + "parser_till_end = ::$proto_ns$::internal::$1$;\n" + "auto* str = msg->$2$_$3$();\n" + "str->Clear();\n", + cord_parser, + field->is_repeated() && !field->is_map() ? "add" : "mutable", + FieldName(field)); + } else if (field->options().ctype() == FieldOptions::STRING_PIECE) { + format( + "parser_till_end = " + "::$proto_ns$::internal::StringPieceParser$1$;\n" + "::$proto_ns$::internal::StringPieceField* str = " + "msg->$2$_$3$();\n" + "str->Clear();\n", + utf8, + field->is_repeated() && !field->is_map() ? "add" : "mutable", + FieldName(field)); + } + format("object = str;\n"); + break; + } + case FieldDescriptor::TYPE_MESSAGE: { + GOOGLE_CHECK(field->message_type()); + if (IsImplicitWeakField(field, options, scc_analyzer)) { + if (!field->is_repeated()) { + format("object = HasBitSetters::mutable_$1$(msg);\n", + FieldName(field)); + } else { + format( + "object = " + "CastToBase(&msg->$1$_)->AddWeak(reinterpret_cast<const " + "::proto2::MessageLite*>(&$2$::_$3$_default_instance_));\n", + FieldName(field), Namespace(field->message_type()), + ClassName(field->message_type())); + } + format( + "parser_till_end = static_cast<::$proto_ns$::MessageLite*>(" + "object)->_ParseFunc();\n"); + break; + } else if (IsWeak(field, options)) { + if (IsProto1(field->file(), options)) { + format("object = msg->internal_mutable_$1$();\n", + FieldName(field)); + } else { + format( + "object = msg->_weak_field_map_.MutableMessage($1$, " + "_$classname$_default_instance_.$2$_);\n", + field->number(), FieldName(field)); + } + format( + "parser_till_end = static_cast<::$proto_ns$::MessageLite*>(" + "object)->_ParseFunc();\n"); + break; + } + format( + "parser_till_end = $1$::_InternalParse;\n" + "object = msg->$2$_$3$();\n", + QualifiedClassName(field->message_type()), + field->is_repeated() && !field->is_map() ? "add" : "mutable", + FieldName(field)); + break; + } + default: + GOOGLE_LOG(FATAL) << "Illegal combination for length delimited wiretype " + << " filed type is " << field->type(); + } + } + format( + "if (size > end - ptr) goto len_delim_till_end;\n" + "auto newend = ptr + size;\n" + "if (!ctx->ParseExactRange({parser_till_end, object}, ptr, newend)) " + "goto error;\n" + "ptr = newend;\n"); + break; + } + case WireFormatLite::WIRETYPE_START_GROUP: { + format( + "parser_till_end = $1$::_InternalParse;\n" + "object = msg->$2$_$3$();\n" + "if (!ctx->PrepareGroup(tag, &depth)) goto error;\n" + "ptr = parser_till_end(ptr, end, object, ctx);\n" + "if (!ptr) goto error;\n" + "if (ctx->GroupContinues(depth)) goto group_continues;\n", + QualifiedClassName(field->message_type()), + field->is_repeated() ? "add" : "mutable", FieldName(field)); + break; + } + case WireFormatLite::WIRETYPE_END_GROUP: { + GOOGLE_LOG(FATAL) << "Can't have end group field\n"; + break; + } + case WireFormatLite::WIRETYPE_FIXED32: { + string type = PrimitiveTypeName(options, field->cpp_type()); + format( + "$1$ val;\n" + "std::memcpy(&val, ptr, 4);\n" + "ptr += 4;\n", + type); + if (field->is_repeated()) { + format("msg->add_$1$(val);\n", FieldName(field)); + } else { + format("msg->set_$1$(val);\n", FieldName(field)); + } + break; + } + } // switch (wire_type) + + if (ShouldRepeat(field, wiretype)) { + format("if (ptr >= end) break;\n"); + uint32 x = field->number() * 8 + wiretype; + uint64 y = 0; + int cnt = 0; + do { + y += static_cast<uint64>((x & 0x7F) + (x >= 128 ? 128 : 0)) + << (cnt++ * 8); + x >>= 7; + } while (x); + uint64 mask = (1ull << (cnt * 8)) - 1; + format.Outdent(); + format( + "} while((*reinterpret_cast<const $uint64$*>(ptr) & $1$) == $2$ && " + "(ptr += $3$));\n", + mask, y, cnt); + } + format("break;\n"); +} + +void GenerateCaseBody(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer, + const Formatter& format) { + using internal::WireFormat; + using internal::WireFormatLite; + + if (!IsProto1(field->file(), options) && field->is_packable()) { + auto expected_wiretype = WireFormat::WireTypeForFieldType(field->type()); + GOOGLE_CHECK(expected_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + uint32 expected_tag = + WireFormatLite::MakeTag(field->number(), expected_wiretype); + auto fallback_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED; + uint32 fallback_tag = + WireFormatLite::MakeTag(field->number(), fallback_wiretype); + + if (field->is_packed()) { + std::swap(expected_tag, fallback_tag); + std::swap(expected_wiretype, fallback_wiretype); + } + + format("if (static_cast<$uint8$>(tag) == $1$) {\n", expected_tag & 0xFF); + format.Indent(); + GenerateCaseBody(expected_wiretype, field, options, scc_analyzer, format); + format.Outdent(); + format( + "} else if (static_cast<$uint8$>(tag) != $1$) goto handle_unusual;\n", + fallback_tag & 0xFF); + GenerateCaseBody(fallback_wiretype, field, options, scc_analyzer, format); + } else { + auto wiretype = WireFormat::WireTypeForField(field); + format("if (static_cast<$uint8$>(tag) != $1$) goto handle_unusual;\n", + WireFormat::MakeTag(field) & 0xFF); + GenerateCaseBody(wiretype, field, options, scc_analyzer, format); + } +} + +void GenerateParserLoop(const Descriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer, + io::Printer* printer) { + using internal::WireFormat; + using internal::WireFormatLite; + + Formatter format(printer); + format.Set("classname", ClassName(descriptor)); + format.Set("proto_ns", ProtobufNamespace(options)); + std::map<string, string> vars; + SetCommonVars(options, &vars); + format.AddMap(vars); + + std::vector<const FieldDescriptor*> ordered_fields; + for (auto field : FieldRange(descriptor)) { + ordered_fields.push_back(field); + } + std::sort(ordered_fields.begin(), ordered_fields.end(), + [](const FieldDescriptor* a, const FieldDescriptor* b) { + return a->number() < b->number(); + }); + + format( + "const char* $classname$::_InternalParse(const char* begin, const char* " + "end, void* object,\n" + " ::$proto_ns$::internal::ParseContext* ctx) {\n" + " auto msg = static_cast<$classname$*>(object);\n" + " $uint32$ size; (void)size;\n" + " int depth; (void)depth;\n" + " ::$proto_ns$::internal::ParseFunc parser_till_end; " + "(void)parser_till_end;\n" + " auto ptr = begin;\n" + " while (ptr < end) {\n" + " $uint32$ tag;\n" + " ptr = Varint::Parse32Inline(ptr, &tag);\n" + " if (!ptr) goto error;\n" + " switch (tag >> 3) {\n" + " case 0: goto error;\n"); + + format.Indent(); + format.Indent(); + format.Indent(); + + for (const auto* field : ordered_fields) { + if (IsProto1(descriptor->file(), options)) { + if (field->number() >= (1 << 14)) continue; + } + // Print the field's (or oneof's) proto-syntax definition as a comment. + // We don't want to print group bodies so we cut off after the first + // line. + string def; + { + DebugStringOptions options; + options.elide_group_body = true; + options.elide_oneof_body = true; + def = field->DebugStringWithOptions(options); + def = def.substr(0, def.find_first_of('\n')); + } + format( + "// $1$\n" + "case $2$: {\n", + def, field->number()); + format.Indent(); + GenerateCaseBody(field, options, scc_analyzer, format); + format.Outdent(); + format("}\n"); // case + } // for fields + format( + "default: {\n" + "handle_unusual: (void)&&handle_unusual;\n" + " if ((tag & 7) == 4) {\n" + " if (!ctx->ValidEndGroup(tag)) goto error;\n" + " return ptr;\n" + " }\n"); + if (IsMapEntryMessage(descriptor)) { + format( + " break;\n" + "}\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 start_tag = WireFormatLite::MakeTag( + range->start, static_cast<WireFormatLite::WireType>(0)); + uint32 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( + " auto res = msg->_extensions_.ParseField(tag, {_InternalParse, " + "msg}, ptr, end,\n" + " internal_default_instance(), &msg->_internal_metadata_, " + "ctx);\n" + " ptr = res.first;\n" + " if (res.second) return ptr;\n" + " continue;\n" + "}\n"); + } + format( + " auto res = UnknownFieldParse(tag, {_InternalParse, msg},\n" + " ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), " + "ctx);\n" + " ptr = res.first;\n" + " if (res.second) return ptr;\n" + "}\n"); // default case + } + format.Outdent(); + format.Outdent(); + format.Outdent(); + format( + " } // switch\n" + " } // while\n" + " return ptr;\n" + "error:\n" + " return nullptr;\n" + "len_delim_till_end: (void)&&len_delim_till_end;\n" + " return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},\n" + " {parser_till_end, object}, size);\n" + "group_continues: (void)&&group_continues;\n" + " $DCHK$(ptr >= end);\n" + // Group crossed end and must be continued. Either this a parse failure + // or we need to resume on the next chunk and thus save the state. + " ctx->StoreGroup({_InternalParse, msg}, {parser_till_end, object}, " + "depth);\n" + " return ptr;\n" + "}\n"); +} } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index eac65124..98cd9c57 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -35,25 +35,57 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ +#include <iterator> #include <map> #include <string> + #include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/scc.h> #include <google/protobuf/compiler/code_generator.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.h> +#include <google/protobuf/port.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/port_def.inc> + namespace google { namespace protobuf { namespace compiler { namespace cpp { +inline string ProtobufNamespace(const Options& options) { + return options.opensource_runtime ? "google::protobuf" : "proto2"; +} + +inline string MacroPrefix(const Options& options) { + return options.opensource_runtime ? "GOOGLE_PROTOBUF" : "GOOGLE_PROTOBUF"; +} + +inline string DeprecatedAttribute(const Options& options, bool deprecated) { + if (!deprecated) { + return ""; + } + return MacroPrefix(options) + "_DEPRECATED "; +} + // Commonly-used separator comments. Thick is a line of '=', thin is a line // of '-'. extern const char kThickSeparator[]; extern const char kThinSeparator[]; +inline bool IsProto1(const FileDescriptor* file, const Options& options) { + return false; +} + +void SetCommonVars(const Options& options, std::map<string, string>* variables); + +bool GetBootstrapBasename(const Options& options, const string& basename, + string* bootstrap_basename); +bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, + bool bootstrap_flag, string* basename); +bool IsBootstrapProto(const Options& options, const FileDescriptor* file); // Name space of the proto file. This namespace is such that the string // "<namespace>::some_name" is the correct fully qualified namespace. @@ -63,20 +95,19 @@ string Namespace(const string& package); inline string Namespace(const FileDescriptor* d) { return Namespace(d->package()); } -template <typename Desc> -string Namespace(const Desc* d) { - return Namespace(d->file()); -} + +string Namespace(const Descriptor* d); +string Namespace(const FieldDescriptor* d); +string Namespace(const EnumDescriptor* d); // Returns true if it's safe to reset "field" to zero. bool CanInitializeByZeroing(const FieldDescriptor* field); string ClassName(const Descriptor* descriptor); string ClassName(const EnumDescriptor* enum_descriptor); -template <typename Desc> -string QualifiedClassName(const Desc* d) { - return Namespace(d) + "::" + ClassName(d); -} + +string QualifiedClassName(const Descriptor* d); +string QualifiedClassName(const EnumDescriptor* d); // DEPRECATED just use ClassName or QualifiedClassName, a boolean is very // unreadable at the callsite. @@ -104,7 +135,7 @@ string DefaultInstanceName(const Descriptor* descriptor); // fields. string ReferenceFunctionName(const Descriptor* descriptor); -// Name of the base class: google::protobuf::Message or google::protobuf::MessageLite. +// Name of the base class: proto2::Message or proto2::MessageLite. string SuperClassName(const Descriptor* descriptor, const Options& options); // Get the (unqualified) name that should be used for this field in C++ code. @@ -141,11 +172,8 @@ string FieldMessageTypeName(const FieldDescriptor* field); LIBPROTOC_EXPORT string StripProto(const string& filename); // Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.). -// Note: non-built-in type names will be qualified, meaning they will start -// with a ::. If you are using the type as a template parameter, you will -// need to insure there is a space between the < and the ::, because the -// ridiculous C++ standard defines "<:" to be a synonym for "[". const char* PrimitiveTypeName(FieldDescriptor::CppType type); +string PrimitiveTypeName(const Options& options, FieldDescriptor::CppType type); // Get the declared type name in CamelCase format, as is used e.g. for the // methods of WireFormat. For example, TYPE_INT32 becomes "Int32". @@ -155,22 +183,59 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type); string Int32ToString(int number); // Return the code that evaluates to the number when compiled. -string Int64ToString(int64 number); +string Int64ToString(const Options& options, int64 number); // Get code that evaluates to the field's default value. +string DefaultValue(const Options& options, const FieldDescriptor* field); + +// Compatibility function for callers outside proto2. string DefaultValue(const FieldDescriptor* field); // Convert a file name into a valid identifier. string FilenameIdentifier(const string& filename); -// For each .proto file generates a unique namespace. In this namespace global -// definitions are put to prevent collisions. -string FileLevelNamespace(const string& filename); -inline string FileLevelNamespace(const FileDescriptor* file) { - return FileLevelNamespace(file->name()); +// For each .proto file generates a unique name. To prevent collisions of +// symbols in the global namespace +string UniqueName(const string& name, const string& filename, + const Options& options); +inline string UniqueName(const string& name, const FileDescriptor* d, + const Options& options) { + return UniqueName(name, d->name(), options); +} +inline string UniqueName(const string& name, const Descriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} +inline string UniqueName(const string& name, const EnumDescriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} +inline string UniqueName(const string& name, const ServiceDescriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} + +// Versions for call sites that only support the internal runtime (like proto1 +// support). +inline Options InternalRuntimeOptions() { + Options options; + options.opensource_runtime = false; + return options; +} +inline string UniqueName(const string& name, const string& filename) { + return UniqueName(name, filename, InternalRuntimeOptions()); } -inline string FileLevelNamespace(const Descriptor* d) { - return FileLevelNamespace(d->file()); +inline string UniqueName(const string& name, const FileDescriptor* d) { + return UniqueName(name, d->name(), InternalRuntimeOptions()); +} +inline string UniqueName(const string& name, const Descriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); +} +inline string UniqueName(const string& name, const EnumDescriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); +} +inline string UniqueName(const string& name, const ServiceDescriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); } // Return the qualified C++ name for a file level symbol. @@ -184,24 +249,14 @@ string SafeFunctionName(const Descriptor* descriptor, const FieldDescriptor* field, const string& prefix); -// Returns true if unknown fields are always preserved after parsing. -inline bool AlwaysPreserveUnknownFields(const FileDescriptor* file) { - return file->syntax() != FileDescriptor::SYNTAX_PROTO3; -} - -// Returns true if unknown fields are preserved after parsing. -inline bool AlwaysPreserveUnknownFields(const Descriptor* message) { - return AlwaysPreserveUnknownFields(message->file()); -} - // Returns true if generated messages have public unknown fields accessors inline bool PublicUnknownFieldsAccessors(const Descriptor* message) { return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; } // Returns the optimize mode for <file>, respecting <options.enforce_lite>. -::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( - const FileDescriptor* file, const Options& options); +FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options); // Determines whether unknown fields will be stored in an UnknownFieldSet or // a string. @@ -210,6 +265,56 @@ inline bool UseUnknownFieldSet(const FileDescriptor* file, return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; } +inline bool IsWeak(const FieldDescriptor* field, const Options& options) { + if (field->options().weak()) { + GOOGLE_CHECK(!options.opensource_runtime); + return true; + } + return false; +} + +// 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, + const Options& options); + +inline bool IsCord(const FieldDescriptor* field, const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::CORD; +} + +inline bool IsStringPiece(const FieldDescriptor* field, + const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE; +} + +// Does the given FileDescriptor use lazy fields? +bool HasLazyFields(const FileDescriptor* file, const Options& options); + +// Is the given field a supported lazy field? +inline bool IsLazy(const FieldDescriptor* field, const Options& options) { + return field->options().lazy() && !field->is_repeated() && + field->type() == FieldDescriptor::TYPE_MESSAGE && + GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME && + !options.opensource_runtime; +} + +// Does the file contain any definitions that need extension_set.h? +bool HasExtensionsOrExtendableMessage(const FileDescriptor* file); + +// Does the file have any repeated fields, necessitating the file to include +// repeated_field.h? This does not include repeated extensions, since those are +// all stored internally in an ExtensionSet, not a separate RepeatedField*. +bool HasRepeatedFields(const FileDescriptor* file); + +// Does the file have any string/bytes fields with ctype=STRING_PIECE? This +// does not include extensions, since ctype is ignored for extensions. +bool HasStringPieceFields(const FileDescriptor* file, const Options& options); + +// Does the file have any string/bytes fields with ctype=CORD? This does not +// include extensions, since ctype is ignored for extensions. +bool HasCordFields(const FileDescriptor* file, const Options& options); // Does the file have any map fields, necessitating the file to include // map_field_inl.h and map.h. @@ -247,6 +352,18 @@ inline bool HasFastArraySerialization(const FileDescriptor* file, return GetOptimizeFor(file, options) == FileOptions::SPEED; } +inline bool IsProto2MessageSet(const Descriptor* descriptor, + const Options& options) { + return !options.opensource_runtime && + descriptor->options().message_set_wire_format() && + descriptor->full_name() == "google.protobuf.bridge.MessageSet"; +} + +inline bool IsProto2MessageSetFile(const FileDescriptor* file, + const Options& options) { + return !options.opensource_runtime && + file->name() == "net/proto2/bridge/proto/message_set.proto"; +} inline bool IsMapEntryMessage(const Descriptor* descriptor) { return descriptor->options().map_entry(); @@ -255,10 +372,6 @@ inline bool IsMapEntryMessage(const Descriptor* descriptor) { // Returns true if the field's CPPTYPE is string or message. bool IsStringOrMessage(const FieldDescriptor* field); -// 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); - string UnderscoresToCamelCase(const string& input, bool cap_next_letter); inline bool HasFieldPresence(const FileDescriptor* file) { @@ -302,19 +415,8 @@ bool IsAnyMessage(const Descriptor* descriptor); bool IsWellKnownMessage(const FileDescriptor* descriptor); -void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, - const Options& options, bool for_parse, - const std::map<string, string>& variables, - const char* parameters, - io::Printer* printer); - -void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, - const Options& options, bool for_parse, - const std::map<string, string>& variables, - const char* parameters, io::Printer* printer); - -inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( - const FileDescriptor* file, const Options& options) { +inline FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options) { return options.enforce_lite ? FileOptions::LITE_RUNTIME : file->options().optimize_for(); @@ -330,21 +432,173 @@ inline std::vector<const Descriptor*> FlattenMessagesInFile( return result; } -bool HasWeakFields(const Descriptor* desc); -bool HasWeakFields(const FileDescriptor* desc); +bool HasWeakFields(const Descriptor* desc, const Options& options); +bool HasWeakFields(const FileDescriptor* desc, const Options& options); // Returns true if the "required" restriction check should be ignored for the // given field. inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, const Options& options) { - return false; + // Do not check "required" for lazy fields. + return IsLazy(field, options); } +struct MessageAnalysis { + bool is_recursive; + bool contains_cord; + bool contains_extension; + bool contains_required; + bool constructor_requires_initialization; +}; + +// This class is used in FileGenerator, to ensure linear instead of +// quadratic performance, if we do this per message we would get O(V*(V+E)). +// Logically this is just only used in message.cc, but in the header for +// FileGenerator to help share it. +class LIBPROTOC_EXPORT MessageSCCAnalyzer { + public: + explicit MessageSCCAnalyzer(const Options& options) : options_(options) {} + + MessageAnalysis GetSCCAnalysis(const SCC* scc); + + bool HasRequiredFields(const Descriptor* descriptor) { + MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor)); + return result.contains_required || result.contains_extension; + } + const SCC* GetSCC(const Descriptor* descriptor) { + return analyzer_.GetSCC(descriptor); + } + + private: + SCCAnalyzer analyzer_; + Options options_; + std::map<const SCC*, MessageAnalysis> analysis_cache_; +}; + +void ListAllFields(const Descriptor* d, + std::vector<const FieldDescriptor*>* fields); +void ListAllFields(const FileDescriptor* d, + std::vector<const FieldDescriptor*>* fields); +void ListAllTypesForServices(const FileDescriptor* fd, + std::vector<const Descriptor*>* types); + +// Indicates whether we should use implicit weak fields for this file. +bool UsingImplicitWeakFields(const FileDescriptor* file, + const Options& options); + +// Indicates whether to treat this field as implicitly weak. +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +// 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 +// the format string $1$, $2$, etc... are substituted for the first, second, ... +// direct argument respectively in the format call, it accepts both strings and +// integers. The implementation verifies all arguments are used and are "first" +// used in order of appearance in the argument list. For example, +// +// Format("return array[$1$];", 3) -> "return array[3];" +// Format("array[$2$] = $1$;", "Bla", 3) -> FATAL error (wrong order) +// Format("array[$1$] = $2$;", 3, "Bla") -> "array[3] = Bla;" +// +// The arguments can be used more than once like +// +// Format("array[$1$] = $2$; // Index = $1$", 3, "Bla") -> +// "array[3] = Bla; // Index = 3" +// +// If you use more arguments use the following style to help the reader, +// +// Format("int $1$() {\n" +// " array[$2$] = $3$;\n" +// " return $4$;" +// "}\n", +// funname, // 1 +// idx, // 2 +// varname, // 3 +// retval); // 4 +// +// but consider using named variables. Named variables like $foo$, with some +// identifier foo, are looked up in the map. One additional feature is that +// spaces are accepted between the '$' delimiters, $ foo$ will +// substiture to " bar" if foo stands for "bar", but in case it's empty +// will substitute to "". Hence, for example, +// +// Format(vars, "$dllexport $void fun();") -> "void fun();" +// "__declspec(export) void fun();" +// +// which is convenient to prevent double, leading or trailing spaces. +class LIBPROTOC_EXPORT Formatter { + public: + explicit Formatter(io::Printer* printer) : printer_(printer) {} + Formatter(io::Printer* printer, const std::map<string, string>& vars) + : printer_(printer), vars_(vars) {} + + template <typename T> + void Set(const string& key, const T& value) { + vars_[key] = ToString(value); + } + + void AddMap(const std::map<string, string>& vars) { + for (const auto& keyval : vars) vars_[keyval.first] = keyval.second; + } + + template <typename... Args> + void operator()(const char* format, const Args&... args) const { + printer_->FormatInternal({ToString(args)...}, vars_, format); + } + + void Indent() const { printer_->Indent(); } + void Outdent() const { printer_->Outdent(); } + io::Printer* printer() const { return printer_; } + + class LIBPROTOC_EXPORT SaveState { + public: + explicit SaveState(Formatter* format) + : format_(format), vars_(format->vars_) {} + ~SaveState() { format_->vars_.swap(vars_); } + + private: + Formatter* format_; + std::map<string, string> vars_; + }; + + private: + io::Printer* printer_; + std::map<string, string> vars_; + + // Convenience overloads to accept different types as arguments. + static string ToString(const string& s) { return s; } + template <typename I, typename = typename std::enable_if< + std::is_integral<I>::value>::type> + static string ToString(I x) { + return SimpleItoa(x); + } + static string ToString(strings::Hex x) { return StrCat(x); } + static string ToString(const FieldDescriptor* d) { return Payload(d); } + static string ToString(const Descriptor* d) { return Payload(d); } + static string ToString(const EnumDescriptor* d) { return Payload(d); } + static string ToString(const EnumValueDescriptor* d) { return Payload(d); } + + template <typename Descriptor> + static string Payload(const Descriptor* descriptor) { + std::vector<int> path; + descriptor->GetLocationPath(&path); + GeneratedCodeInfo::Annotation annotation; + for (int i = 0; i < path.size(); ++i) { + annotation.add_path(path[i]); + } + annotation.set_source_file(descriptor->file()->name()); + return annotation.SerializeAsString(); + } +}; + class LIBPROTOC_EXPORT NamespaceOpener { public: - explicit NamespaceOpener(io::Printer* printer) : printer_(printer) {} - NamespaceOpener(const string& name, io::Printer* printer) - : printer_(printer) { + explicit NamespaceOpener(const Formatter& format) + : printer_(format.printer()) {} + NamespaceOpener(const string& name, const Formatter& format) + : NamespaceOpener(format) { ChangeTo(name); } ~NamespaceOpener() { ChangeTo(""); } @@ -372,90 +626,97 @@ class LIBPROTOC_EXPORT NamespaceOpener { std::vector<string> name_stack_; }; -// Description of each strongly connected component. Note that the order -// of both the descriptors in this SCC and the order of children is -// deterministic. -struct SCC { - std::vector<const Descriptor*> descriptors; - std::vector<const SCC*> children; +string GetUtf8Suffix(const FieldDescriptor* field, const Options& options); +void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const Formatter& format); - const Descriptor* GetRepresentative() const { return descriptors[0]; } -}; +void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const Formatter& format); -struct MessageAnalysis { - bool is_recursive; - bool contains_cord; - bool contains_extension; - bool contains_required; +template <typename T> +struct FieldRangeImpl { + struct Iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const FieldDescriptor*; + using difference_type = int; + + value_type operator*() { return descriptor->field(idx); } + + friend bool operator==(const Iterator& a, const Iterator& b) { + GOOGLE_DCHECK(a.descriptor == b.descriptor); + return a.idx == b.idx; + } + friend bool operator!=(const Iterator& a, const Iterator& b) { + return !(a == b); + } + + Iterator& operator++() { + idx++; + return *this; + } + + int idx; + const T* descriptor; + }; + + Iterator begin() const { return {0, descriptor}; } + Iterator end() const { return {descriptor->field_count(), descriptor}; } + + const T* descriptor; }; -// This class is used in FileGenerator, to ensure linear instead of -// quadratic performance, if we do this per message we would get O(V*(V+E)). -// Logically this is just only used in message.cc, but in the header for -// FileGenerator to help share it. -class LIBPROTOC_EXPORT SCCAnalyzer { - public: - explicit SCCAnalyzer(const Options& options) : options_(options), index_(0) {} - ~SCCAnalyzer() { - for (int i = 0; i < garbage_bin_.size(); i++) delete garbage_bin_[i]; - } +template <typename T> +FieldRangeImpl<T> FieldRange(const T* desc) { + return {desc}; +} - const SCC* GetSCC(const Descriptor* descriptor) { - if (cache_.count(descriptor)) return cache_[descriptor].scc; - return DFS(descriptor).scc; - } +struct OneOfRangeImpl { + struct Iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const OneofDescriptor*; + using difference_type = int; - MessageAnalysis GetSCCAnalysis(const SCC* scc); + value_type operator*() { return descriptor->oneof_decl(idx); } - bool HasRequiredFields(const Descriptor* descriptor) { - MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor)); - return result.contains_required || result.contains_extension; - } + friend bool operator==(const Iterator& a, const Iterator& b) { + GOOGLE_DCHECK(a.descriptor == b.descriptor); + return a.idx == b.idx; + } + friend bool operator!=(const Iterator& a, const Iterator& b) { + return !(a == b); + } - private: - struct NodeData { - const SCC* scc; // if null it means its still on the stack - int index; - int lowlink; - }; + Iterator& operator++() { + idx++; + return *this; + } - Options options_; - std::map<const Descriptor*, NodeData> cache_; - std::map<const SCC*, MessageAnalysis> analysis_cache_; - std::vector<const Descriptor*> stack_; - int index_; - std::vector<SCC*> garbage_bin_; + int idx; + const Descriptor* descriptor; + }; - SCC* CreateSCC() { - garbage_bin_.push_back(new SCC()); - return garbage_bin_.back(); + Iterator begin() const { return {0, descriptor}; } + Iterator end() const { + return {descriptor->oneof_decl_count(), descriptor}; } - // Tarjan's Strongly Connected Components algo - NodeData DFS(const Descriptor* descriptor); - - // Add the SCC's that are children of this SCC to its children. - void AddChildren(SCC* scc); + const Descriptor* descriptor; }; -void ListAllFields(const Descriptor* d, - std::vector<const FieldDescriptor*>* fields); -void ListAllFields(const FileDescriptor* d, - std::vector<const FieldDescriptor*>* fields); -void ListAllTypesForServices(const FileDescriptor* fd, - std::vector<const Descriptor*>* types); +inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; } -// Indicates whether we should use implicit weak fields for this file. -bool UsingImplicitWeakFields(const FileDescriptor* file, - const Options& options); - -// Indicates whether to treat this field as implicitly weak. -bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, - SCCAnalyzer* scc_analyzer); +void GenerateParserLoop(const Descriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer, io::Printer* printer); } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + +#include <google/protobuf/port_undef.inc> + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 0e485cac..4ab407d2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -32,9 +32,9 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> - #include <google/protobuf/stubs/strutil.h> + namespace google { namespace protobuf { namespace compiler { @@ -50,8 +50,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = ClassName(descriptor->message_type(), false); - (*variables)["file_namespace"] = - FileLevelNamespace(descriptor->file()->name()); (*variables)["stream_writer"] = (*variables)["declared_type"] + (HasFastArraySerialization(descriptor->message_type()->file(), options) @@ -63,7 +61,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, descriptor->message_type()->FindFieldByName("key"); const FieldDescriptor* val = descriptor->message_type()->FindFieldByName("value"); - (*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type()); + (*variables)["key_cpp"] = PrimitiveTypeName(options, key->cpp_type()); switch (val->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: (*variables)["val_cpp"] = FieldMessageTypeName(val); @@ -74,18 +72,17 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["wrapper"] = "EnumEntryWrapper"; break; default: - (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type()); + (*variables)["val_cpp"] = PrimitiveTypeName(options, val->cpp_type()); (*variables)["wrapper"] = "EntryWrapper"; } (*variables)["key_wire_type"] = - "::google::protobuf::internal::WireFormatLite::TYPE_" + - ToUpper(DeclaredTypeMethodName(key->type())); + "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type())); (*variables)["val_wire_type"] = - "::google::protobuf::internal::WireFormatLite::TYPE_" + - ToUpper(DeclaredTypeMethodName(val->type())); + "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type())); (*variables)["map_classname"] = ClassName(descriptor->message_type(), false); (*variables)["number"] = SimpleItoa(descriptor->number()); - (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + (*variables)["tag"] = + SimpleItoa(internal::WireFormat::MakeTag(descriptor)); if (HasDescriptorMethods(descriptor->file(), options)) { (*variables)["lite"] = ""; @@ -104,7 +101,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), descriptor_(descriptor) { + : FieldGenerator(descriptor, options) { SetMessageVariables(descriptor, &variables_, options); } @@ -112,37 +109,37 @@ MapFieldGenerator::~MapFieldGenerator() {} void MapFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, - "::google::protobuf::internal::MapField$lite$<\n" - " $map_classname$,\n" - " $key_cpp$, $val_cpp$,\n" - " $key_wire_type$,\n" - " $val_wire_type$,\n" - " $default_enum_value$ > $name$_;\n"); + 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$,\n" + " $default_enum_value$ > $name$_;\n"); } void MapFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { - printer->Print( - variables_, - "$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" - " $name$() const;\n"); - printer->Annotate("name", descriptor_); - printer->Print(variables_, - "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" - " ${$mutable_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); + Formatter format(printer, variables_); + format( + "$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n" + " ${1$$name$$}$() const;\n" + "$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n" + " ${1$mutable_$name$$}$();\n", + descriptor_); } void MapFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" + Formatter format(printer, variables_); + format( + "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_map:$full_name$)\n" " return $name$_.GetMap();\n" "}\n" - "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" + "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n" "$classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n" " return $name$_.MutableMap();\n" @@ -151,17 +148,20 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { void MapFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); } void MapFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); } void MapFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); + Formatter format(printer, variables_); + format("$name$_.Swap(&other->$name$_);\n"); } void MapFieldGenerator:: @@ -172,8 +172,9 @@ GenerateCopyConstructorCode(io::Printer* printer) const { void MapFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - const FieldDescriptor* key_field = - descriptor_->message_type()->FindFieldByName("key"); + Formatter format(printer, variables_); + const FieldDescriptor* key_field = + descriptor_->message_type()->FindFieldByName("key"); const FieldDescriptor* value_field = descriptor_->message_type()->FindFieldByName("value"); bool using_entry = false; @@ -181,17 +182,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { string value; if (IsProto3Field(descriptor_) || value_field->type() != FieldDescriptor::TYPE_ENUM) { - printer->Print( - variables_, - "$map_classname$::Parser< ::google::protobuf::internal::MapField$lite$<\n" + format( + "$map_classname$::Parser< ::$proto_ns$::internal::MapField$lite$<\n" " $map_classname$,\n" " $key_cpp$, $val_cpp$,\n" - " $key_wire_type$,\n" - " $val_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$,\n" " $default_enum_value$ >,\n" - " ::google::protobuf::Map< $key_cpp$, $val_cpp$ > >" + " ::$proto_ns$::Map< $key_cpp$, $val_cpp$ > >" " parser(&$name$_);\n" - "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" + "DO_(::$proto_ns$::internal::WireFormatLite::ReadMessageNoVirtual(\n" " input, &parser));\n"); key = "parser.key()"; value = "parser.value()"; @@ -199,120 +199,121 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { using_entry = true; key = "entry->key()"; value = "entry->value()"; - printer->Print(variables_, - "::std::unique_ptr<$map_classname$> entry($name$_.NewEntry());\n"); - printer->Print(variables_, + format("::std::unique_ptr<$map_classname$> entry($name$_.NewEntry());\n"); + format( "{\n" " ::std::string data;\n" - " DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n" + " DO_(::$proto_ns$::internal::WireFormatLite::ReadString(input, " + "&data));\n" " DO_(entry->ParseFromString(data));\n" " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n" " (*mutable_$name$())[entry->key()] =\n" " static_cast< $val_cpp$ >(*entry->mutable_value());\n" " } else {\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print(variables_, + format( " mutable_unknown_fields()" "->AddLengthDelimited($number$, data);\n"); } else { - printer->Print(variables_, + format( " unknown_fields_stream.WriteVarint32($tag$u);\n" " unknown_fields_stream.WriteVarint32(\n" " static_cast< ::google::protobuf::uint32>(data.size()));\n" " unknown_fields_stream.WriteString(data);\n"); } - printer->Print(variables_, + format( " }\n" "}\n"); } if (key_field->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - key_field, options_, true, variables_, - StrCat(key, ".data(), static_cast<int>(", key, ".length()),\n").data(), - printer); + key_field, options_, true, + StrCat(key, ".data(), static_cast<int>(", key, ".length()),\n") + .data(), + format); } if (value_field->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - value_field, options_, true, variables_, - StrCat(value, ".data(), static_cast<int>(", value, ".length()),\n") + value_field, options_, true, + StrCat(value, ".data(), static_cast<int>(", value, + ".length()),\n") .data(), - printer); + format); } // If entry is allocated by arena, its desctructor should be avoided. if (using_entry && SupportsArenas(descriptor_)) { - printer->Print(variables_, - "if (entry->GetArena() != NULL) entry.release();\n"); + format("if (entry->GetArena() != NULL) entry.release();\n"); } } -static void GenerateSerializationLoop(io::Printer* printer, - const std::map<string, string>& variables, - bool supports_arenas, - const string& utf8_check, - const string& loop_header, - const string& ptr, - bool loop_via_iterators) { - printer->Print(variables, - StrCat("::std::unique_ptr<$map_classname$> entry;\n", - loop_header, " {\n").c_str()); - printer->Indent(); - - printer->Print(variables, StrCat( - "entry.reset($name$_.New$wrapper$(\n" - " ", ptr, "->first, ", ptr, "->second));\n" - "$write_entry$;\n").c_str()); +static void GenerateSerializationLoop(const Formatter& format, + bool supports_arenas, bool string_key, + bool string_value, bool to_array, + bool is_deterministic) { + format("::std::unique_ptr<$map_classname$> entry;\n"); + string ptr; + if (is_deterministic) { + format("for (size_type i = 0; i < n; i++) {\n"); + ptr = string_key ? "items[static_cast<ptrdiff_t>(i)]" + : "items[static_cast<ptrdiff_t>(i)].second"; + } else { + format( + "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" + " it = this->$name$().begin();\n" + " it != this->$name$().end(); ++it) {\n"); + ptr = "it"; + } + format.Indent(); + + format("entry.reset($name$_.New$wrapper$($1$->first, $1$->second));\n", ptr); + if (to_array) { + format( + "target = ::$proto_ns$::internal::WireFormatLite::InternalWrite" + "$declared_type$NoVirtualToArray($number$, *entry, deterministic, " + "target);\n"); + } else { + format( + "::$proto_ns$::internal::WireFormatLite::Write$stream_writer$($number$," + " " + "*entry, output);\n"); + } // If entry is allocated by arena, its desctructor should be avoided. if (supports_arenas) { - printer->Print( + format( "if (entry->GetArena() != NULL) {\n" " entry.release();\n" "}\n"); } - if (!utf8_check.empty()) { - // If loop_via_iterators is true then ptr is actually an iterator, and we - // create a pointer by prefixing it with "&*". - printer->Print( - StrCat(utf8_check, "(", (loop_via_iterators ? "&*" : ""), ptr, ");\n") - .c_str()); + if (string_key || string_value) { + // ptr is either an actual pointer or an iterator, either way we can + // create a pointer by taking the address after de-referencing it. + format("Utf8Check::Check(&(*$1$));\n", ptr); } - printer->Outdent(); - printer->Print( - "}\n"); + format.Outdent(); + format("}\n"); } void MapFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - std::map<string, string> variables(variables_); - variables["write_entry"] = "::google::protobuf::internal::WireFormatLite::Write" + - variables["stream_writer"] + "(\n " + - variables["number"] + ", *entry, output)"; - variables["deterministic"] = "output->IsSerializationDeterministic()"; - GenerateSerializeWithCachedSizes(printer, variables); + GenerateSerializeWithCachedSizes(printer, false); } void MapFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - std::map<string, string> variables(variables_); - variables["write_entry"] = - "target = ::google::protobuf::internal::WireFormatLite::\n" - " InternalWrite" + variables["declared_type"] + - "NoVirtualToArray(\n " + variables["number"] + - ", *entry, deterministic, target);\n"; - variables["deterministic"] = "deterministic"; - GenerateSerializeWithCachedSizes(printer, variables); + GenerateSerializeWithCachedSizes(printer, true); } -void MapFieldGenerator::GenerateSerializeWithCachedSizes( - io::Printer* printer, const std::map<string, string>& variables) const { - printer->Print(variables, - "if (!this->$name$().empty()) {\n"); - printer->Indent(); +void MapFieldGenerator::GenerateSerializeWithCachedSizes(io::Printer* printer, + bool to_array) const { + Formatter format(printer, variables_); + format("if (!this->$name$().empty()) {\n"); + format.Indent(); const FieldDescriptor* key_field = descriptor_->message_type()->FindFieldByName("key"); const FieldDescriptor* value_field = @@ -320,114 +321,110 @@ void MapFieldGenerator::GenerateSerializeWithCachedSizes( const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING; const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING; - printer->Print(variables, - "typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_pointer\n" + format( + "typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_pointer\n" " ConstPtr;\n"); if (string_key) { - printer->Print(variables, + format( "typedef ConstPtr SortItem;\n" - "typedef ::google::protobuf::internal::" + "typedef ::$proto_ns$::internal::" "CompareByDerefFirst<SortItem> Less;\n"); } else { - printer->Print(variables, - "typedef ::google::protobuf::internal::SortItem< $key_cpp$, ConstPtr > " + format( + "typedef ::$proto_ns$::internal::SortItem< $key_cpp$, ConstPtr > " "SortItem;\n" - "typedef ::google::protobuf::internal::CompareByFirstField<SortItem> Less;\n"); + "typedef ::$proto_ns$::internal::CompareByFirstField<SortItem> " + "Less;\n"); } - string utf8_check; - if (string_key || string_value) { - printer->Print( + bool utf8_check = string_key || string_value; + if (utf8_check) { + format( "struct Utf8Check {\n" " static void Check(ConstPtr p) {\n"); - printer->Indent(); - printer->Indent(); + format.Indent(); + format.Indent(); if (string_key) { GenerateUtf8CheckCodeForString( - key_field, options_, false, variables, - "p->first.data(), static_cast<int>(p->first.length()),\n", printer); + key_field, options_, false, + "p->first.data(), static_cast<int>(p->first.length()),\n", format); } if (string_value) { GenerateUtf8CheckCodeForString( - value_field, options_, false, variables, - "p->second.data(), static_cast<int>(p->second.length()),\n", printer); + value_field, options_, false, + "p->second.data(), static_cast<int>(p->second.length()),\n", format); } - printer->Outdent(); - printer->Outdent(); - printer->Print( + format.Outdent(); + format.Outdent(); + format( " }\n" "};\n"); - utf8_check = "Utf8Check::Check"; } - printer->Print(variables, + format( "\n" - "if ($deterministic$ &&\n" + "if ($1$ &&\n" " this->$name$().size() > 1) {\n" " ::std::unique_ptr<SortItem[]> items(\n" " new SortItem[this->$name$().size()]);\n" - " typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::size_type size_type;\n" + " typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::size_type " + "size_type;\n" " size_type n = 0;\n" - " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" + " for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" " it = this->$name$().begin();\n" " it != this->$name$().end(); ++it, ++n) {\n" " items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n" " }\n" - " ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n"); - printer->Indent(); - GenerateSerializationLoop(printer, variables, SupportsArenas(descriptor_), - utf8_check, "for (size_type i = 0; i < n; i++)", - string_key ? "items[static_cast<ptrdiff_t>(i)]" : - "items[static_cast<ptrdiff_t>(i)].second", false); - printer->Outdent(); - printer->Print( - "} else {\n"); - printer->Indent(); - GenerateSerializationLoop( - printer, variables, SupportsArenas(descriptor_), utf8_check, - "for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = this->$name$().begin();\n" - " it != this->$name$().end(); ++it)", - "it", true); - printer->Outdent(); - printer->Print("}\n"); - printer->Outdent(); - printer->Print("}\n"); + " ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n", + to_array ? "deterministic" : "output->IsSerializationDeterministic()"); + format.Indent(); + GenerateSerializationLoop(format, SupportsArenas(descriptor_), string_key, + string_value, to_array, true); + format.Outdent(); + format("} else {\n"); + format.Indent(); + GenerateSerializationLoop(format, SupportsArenas(descriptor_), string_key, + string_value, to_array, false); + format.Outdent(); + format("}\n"); + format.Outdent(); + format("}\n"); } void MapFieldGenerator:: GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, + Formatter format(printer, variables_); + format( "total_size += $tag_size$ *\n" - " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n" + " ::$proto_ns$::internal::FromIntSize(this->$name$_size());\n" "{\n" " ::std::unique_ptr<$map_classname$> entry;\n" - " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" + " for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" " it = this->$name$().begin();\n" " it != this->$name$().end(); ++it) {\n"); // If entry is allocated by arena, its desctructor should be avoided. if (SupportsArenas(descriptor_)) { - printer->Print(variables_, + format( " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" " entry.release();\n" " }\n"); } - printer->Print(variables_, + format( " entry.reset($name$_.New$wrapper$(it->first, it->second));\n" - " total_size += ::google::protobuf::internal::WireFormatLite::\n" + " total_size += ::$proto_ns$::internal::WireFormatLite::\n" " $declared_type$SizeNoVirtual(*entry);\n" " }\n"); // If entry is allocated by arena, its desctructor should be avoided. if (SupportsArenas(descriptor_)) { - printer->Print(variables_, + format( " if (entry.get() != NULL && entry->GetArena() != NULL) {\n" " entry.release();\n" " }\n"); } - printer->Print("}\n"); + format("}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index 0d54f0ea..95eecc07 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -62,11 +62,8 @@ class MapFieldGenerator : public FieldGenerator { private: // A helper for GenerateSerializeWithCachedSizes{,ToArray}. - void GenerateSerializeWithCachedSizes( - io::Printer* printer, const std::map<string, string>& variables) const; - - const FieldDescriptor* descriptor_; - std::map<string, string> variables_; + void GenerateSerializeWithCachedSizes(io::Printer* printer, + bool to_array) const; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); }; @@ -74,6 +71,6 @@ class MapFieldGenerator : public FieldGenerator { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 778fc406..5e9e1a6d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -35,9 +35,9 @@ #include <google/protobuf/compiler/cpp/cpp_message.h> #include <algorithm> -#include <google/protobuf/stubs/hash.h> #include <map> #include <memory> +#include <unordered_map> #include <utility> #include <vector> @@ -57,6 +57,8 @@ #include <google/protobuf/stubs/substitute.h> +#include <google/protobuf/stubs/hash.h> + namespace google { namespace protobuf { @@ -69,7 +71,7 @@ using internal::WireFormatLite; namespace { template <class T> -void PrintFieldComment(io::Printer* printer, const T* field) { +void PrintFieldComment(const Formatter& format, const T* field) { // Print the field's (or oneof's) proto-syntax definition as a comment. // We don't want to print group bodies so we cut off after the first // line. @@ -77,8 +79,25 @@ void PrintFieldComment(io::Printer* printer, const T* field) { options.elide_group_body = true; options.elide_oneof_body = true; string def = field->DebugStringWithOptions(options); - printer->Print("// $def$\n", - "def", def.substr(0, def.find_first_of('\n'))); + format("// $1$\n", def.substr(0, def.find_first_of('\n'))); +} + +void PrintPresenceCheck(const Formatter& format, const FieldDescriptor* field, + const std::vector<int>& has_bit_indices, + io::Printer* printer, int* cached_has_bit_index) { + if (!field->options().weak()) { + int has_bit_index = has_bit_indices[field->index()]; + if (*cached_has_bit_index != (has_bit_index / 32)) { + *cached_has_bit_index = (has_bit_index / 32); + format("cached_has_bits = _has_bits_[$1$];\n", *cached_has_bit_index); + } + const string mask = + StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + format("if (cached_has_bits & 0x$1$u) {\n", mask); + } else { + format("if (has_$1$()) {\n", FieldName(field)); + } + format.Indent(); } struct FieldOrderingByNumber { @@ -135,9 +154,9 @@ bool CanConstructByZeroing(const FieldDescriptor* field, // Non-repeated, non-lazy message fields are simply raw pointers, so we can // use memset to initialize these in SharedCtor. We cannot use this in // Clear, as we need to potentially delete the existing value. - ret = ret || - (!field->is_repeated() && - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); + ret = ret || (!field->is_repeated() && + !IsLazy(field, options) && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); return ret; } @@ -145,36 +164,27 @@ bool CanConstructByZeroing(const FieldDescriptor* field, // considered non-default (will be sent over the wire), for message types // without true field presence. Should only be called if // !HasFieldPresence(message_descriptor). -bool EmitFieldNonDefaultCondition(io::Printer* printer, - const string& prefix, +bool EmitFieldNonDefaultCondition(io::Printer* printer, const string& prefix, const FieldDescriptor* field) { + Formatter format(printer); + format.Set("prefix", prefix); + format.Set("name", FieldName(field)); // Merge and serialize semantics: primitive fields are merged/serialized only // if non-zero (numeric) or non-empty (string). if (!field->is_repeated() && !field->containing_oneof()) { if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { - printer->Print( - "if ($prefix$$name$().size() > 0) {\n", - "prefix", prefix, - "name", FieldName(field)); + format("if ($prefix$$name$().size() > 0) {\n"); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { // Message fields still have has_$name$() methods. - printer->Print( - "if ($prefix$has_$name$()) {\n", - "prefix", prefix, - "name", FieldName(field)); + format("if ($prefix$has_$name$()) {\n"); } else { - printer->Print( - "if ($prefix$$name$() != 0) {\n", - "prefix", prefix, - "name", FieldName(field)); + format("if ($prefix$$name$() != 0) {\n"); } - printer->Indent(); + format.Indent(); return true; } else if (field->containing_oneof()) { - printer->Print( - "if (has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); + format("if (has_$name$()) {\n"); + format.Indent(); return true; } return false; @@ -192,13 +202,13 @@ bool HasHasMethod(const FieldDescriptor* field) { } // Collects map entry message type information. -void CollectMapInfo(const Descriptor* descriptor, +void CollectMapInfo(const Options& options, const Descriptor* descriptor, std::map<string, string>* variables) { GOOGLE_CHECK(IsMapEntryMessage(descriptor)); std::map<string, string>& vars = *variables; const FieldDescriptor* key = descriptor->FindFieldByName("key"); const FieldDescriptor* val = descriptor->FindFieldByName("value"); - vars["key_cpp"] = PrimitiveTypeName(key->cpp_type()); + vars["key_cpp"] = PrimitiveTypeName(options, key->cpp_type()); switch (val->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: vars["val_cpp"] = FieldMessageTypeName(val); @@ -207,12 +217,12 @@ void CollectMapInfo(const Descriptor* descriptor, vars["val_cpp"] = ClassName(val->enum_type(), true); break; default: - vars["val_cpp"] = PrimitiveTypeName(val->cpp_type()); + vars["val_cpp"] = PrimitiveTypeName(options, val->cpp_type()); } - vars["key_wire_type"] = "::google::protobuf::internal::WireFormatLite::TYPE_" + - ToUpper(DeclaredTypeMethodName(key->type())); - vars["val_wire_type"] = "::google::protobuf::internal::WireFormatLite::TYPE_" + - ToUpper(DeclaredTypeMethodName(val->type())); + vars["key_wire_type"] = + "TYPE_" + ToUpper(DeclaredTypeMethodName(key->type())); + vars["val_wire_type"] = + "TYPE_" + ToUpper(DeclaredTypeMethodName(val->type())); if (descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3 && val->type() == FieldDescriptor::TYPE_ENUM) { const EnumValueDescriptor* default_value = val->default_value_enum(); @@ -231,9 +241,51 @@ bool HasPrivateHasMethod(const FieldDescriptor* field) { field->containing_oneof() != NULL); } +// TODO(ckennelly): Cull these exclusions if/when these protos do not have +// their methods overriden by subclasses. + +bool ShouldMarkClearAsFinal(const Descriptor* descriptor, + const Options& options) { + static std::set<string> exclusions{ + }; + + const string name = ClassName(descriptor, true); + return exclusions.find(name) == exclusions.end() || + options.opensource_runtime; +} -bool TableDrivenParsingEnabled( - const Descriptor* descriptor, const Options& options) { +bool ShouldMarkIsInitializedAsFinal(const Descriptor* descriptor, + const Options& options) { + static std::set<string> exclusions{ + }; + + const string name = ClassName(descriptor, true); + return exclusions.find(name) == exclusions.end() || + options.opensource_runtime; +} + +bool ShouldMarkMergePartialAsFinal(const Descriptor* descriptor, + const Options& options) { + static std::set<string> exclusions{ + }; + + const string name = ClassName(descriptor, true); + return exclusions.find(name) == exclusions.end() || + options.opensource_runtime; +} + +bool ShouldMarkNewAsFinal(const Descriptor* descriptor, + const Options& options) { + static std::set<string> exclusions{ + }; + + const string name = ClassName(descriptor, true); + return exclusions.find(name) == exclusions.end() || + options.opensource_runtime; +} + +bool TableDrivenParsingEnabled(const Descriptor* descriptor, + const Options& options) { if (!options.table_driven_parsing) { return false; } @@ -247,14 +299,18 @@ bool TableDrivenParsingEnabled( const double table_sparseness = 0.5; int max_field_number = 0; - for (int i = 0; i < descriptor->field_count(); i++) { - const FieldDescriptor* field = descriptor->field(i); + for (auto field : FieldRange(descriptor)) { if (max_field_number < field->number()) { max_field_number = field->number(); } // - There are no weak fields. - if (field->options().weak()) { + if (IsWeak(field, options)) { + return false; + } + + // - There are no lazy fields (they require the non-lite library). + if (IsLazy(field, options)) { return false; } } @@ -282,24 +338,16 @@ bool TableDrivenParsingEnabled( void SetUnknkownFieldsVariable(const Descriptor* descriptor, const Options& options, std::map<string, string>* variables) { + string proto_ns = ProtobufNamespace(options); if (UseUnknownFieldSet(descriptor->file(), options)) { - (*variables)["unknown_fields_type"] = "::google::protobuf::UnknownFieldSet"; - } else { - (*variables)["unknown_fields_type"] = "::std::string"; - } - if (AlwaysPreserveUnknownFields(descriptor)) { - (*variables)["have_unknown_fields"] = - "_internal_metadata_.have_unknown_fields()"; - (*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields()"; + (*variables)["unknown_fields_type"] = "::" + proto_ns + "::UnknownFieldSet"; } else { - (*variables)["have_unknown_fields"] = - "(_internal_metadata_.have_unknown_fields() && " - " ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())"; - (*variables)["unknown_fields"] = - "(::google::protobuf::internal::GetProto3PreserveUnknownsDefault()" - " ? _internal_metadata_.unknown_fields()" - " : _internal_metadata_.default_instance())"; + (*variables)["unknown_fields_type"] = + PrimitiveTypeName(options, FieldDescriptor::CPPTYPE_STRING); } + (*variables)["have_unknown_fields"] = + "_internal_metadata_.have_unknown_fields()"; + (*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields()"; (*variables)["mutable_unknown_fields"] = "_internal_metadata_.mutable_unknown_fields()"; } @@ -393,13 +441,13 @@ std::vector<std::vector<const FieldDescriptor*> > CollectFields( const FieldDescriptor* last_field = fields.front(); std::vector<const FieldDescriptor*> chunk; - for (int i = 0; i < fields.size(); i++) { - if (!equivalent(last_field, fields[i]) && !chunk.empty()) { + for (auto field : fields) { + if (!equivalent(last_field, field) && !chunk.empty()) { chunks.push_back(chunk); chunk.clear(); } - chunk.push_back(fields[i]); - last_field = fields[i]; + chunk.push_back(field); + last_field = field; } if (!chunk.empty()) { chunks.push_back(chunk); @@ -415,8 +463,7 @@ uint32 GenChunkMask(const std::vector<const FieldDescriptor*>& fields, GOOGLE_CHECK(!fields.empty()); int first_index_offset = has_bit_indices[fields.front()->index()] / 32; uint32 chunk_mask = 0; - for (int i = 0; i < fields.size(); i++) { - const FieldDescriptor* field = fields[i]; + for (auto field : fields) { // "index" defines where in the _has_bits_ the field appears. int index = has_bit_indices[field->index()]; GOOGLE_CHECK_EQ(first_index_offset, index / 32); @@ -426,32 +473,161 @@ uint32 GenChunkMask(const std::vector<const FieldDescriptor*>& fields, return chunk_mask; } +// Return the number of bits set in n, a non-negative integer. +static int popcnt(uint32 n) { + int result = 0; + while (n != 0) { + result += (n & 1); + n = n / 2; + } + return result; +} + +// For a run of cold chunks, opens and closes an external if statement that +// checks multiple has_bits words to skip bulk of cold fields. +class ColdChunkSkipper { + public: + ColdChunkSkipper( + const Options& options, + const std::vector<std::vector<const FieldDescriptor*>>& chunks, + const std::vector<int>& has_bit_indices, const double cold_threshold, + bool has_field_presence) + : chunks_(chunks), + has_bit_indices_(has_bit_indices), + access_info_map_(options.access_info_map), + cold_threshold_(cold_threshold), + has_field_presence_(has_field_presence) { + SetCommonVars(options, &variables_); + } + + // May open an external if check for a batch of cold fields. "from" is the + // prefix to _has_bits_ to allow MergeFrom to use "from._has_bits_". + // Otherwise, it should be "". + void OnStartChunk(int chunk, int cached_has_bit_index, const string& from, + io::Printer* printer); + bool OnEndChunk(int chunk, io::Printer* printer); + + private: + bool IsColdChunk(int chunk); + + int HasbitWord(int chunk, int offset) { + return has_bit_indices_[chunks_[chunk][offset]->index()] / 32; + } + + const std::vector<std::vector<const FieldDescriptor*> >& chunks_; + const std::vector<int>& has_bit_indices_; + const AccessInfoMap* access_info_map_; + const double cold_threshold_; + std::map<string, string> variables_; + int limit_chunk_ = -1; + bool has_field_presence_; +}; + +// Tuning parameters for ColdChunkSkipper. +const double kColdRatio = 0.005; + +bool ColdChunkSkipper::IsColdChunk(int chunk) { return false; } + +void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_bit_index, + const string& from, io::Printer* printer) { + Formatter format(printer, variables_); + if (!access_info_map_ || !has_field_presence_) { + return; + } else if (chunk < limit_chunk_) { + // We are already inside a run of cold chunks. + return; + } else if (!IsColdChunk(chunk)) { + // We can't start a run of cold chunks. + return; + } + + // Find the end of consecutive cold chunks. + limit_chunk_ = chunk; + while (limit_chunk_ < chunks_.size() && IsColdChunk(limit_chunk_)) { + limit_chunk_++; + } + + if (limit_chunk_ <= chunk + 1) { + // Require at least two chunks to emit external has_bit checks. + limit_chunk_ = -1; + return; + } + + // Emit has_bit check for each has_bit_dword index. + format("if ($GOOGLE_PROTOBUF$_PREDICT_FALSE("); + int first_word = HasbitWord(chunk, 0); + while (chunk < limit_chunk_) { + uint32 mask = 0; + int this_word = HasbitWord(chunk, 0); + // Generate mask for chunks on the same word. + for (; chunk < limit_chunk_ && HasbitWord(chunk, 0) == this_word; chunk++) { + for (auto field : chunks_[chunk]) { + int hasbit_index = has_bit_indices_[field->index()]; + // Fields on a chunk must be in the same word. + GOOGLE_CHECK_EQ(this_word, hasbit_index / 32); + mask |= 1 << (hasbit_index % 32); + } + } + + if (this_word != first_word) { + format(" ||\n "); + } + format.Set("mask", strings::Hex(mask, strings::ZERO_PAD_8)); + if (this_word == cached_has_bit_index) { + format("(cached_has_bits & 0x$mask$u) != 0"); + } else { + format("($1$_has_bits_[$2$] & 0x$mask$u) != 0", from, this_word); + } + } + format(")) {\n"); + format.Indent(); +} + +bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) { + Formatter format(printer, variables_); + if (chunk != limit_chunk_ - 1) { + return false; + } + format.Outdent(); + format("}\n"); + return true; +} + } // anonymous namespace // =================================================================== MessageGenerator::MessageGenerator(const Descriptor* descriptor, + const std::map<string, string>& vars, int index_in_file_messages, const Options& options, - SCCAnalyzer* scc_analyzer) + MessageSCCAnalyzer* scc_analyzer) : descriptor_(descriptor), index_in_file_messages_(index_in_file_messages), classname_(ClassName(descriptor, false)), options_(options), field_generators_(descriptor, options, scc_analyzer), max_has_bit_index_(0), - enum_generators_( - new std::unique_ptr<EnumGenerator>[descriptor->enum_type_count()]), - extension_generators_(new std::unique_ptr< - ExtensionGenerator>[descriptor->extension_count()]), num_weak_fields_(0), - message_layout_helper_(new PaddingOptimizer()), - scc_analyzer_(scc_analyzer) { + scc_analyzer_(scc_analyzer), + variables_(vars) { + if (!message_layout_helper_) { + message_layout_helper_.reset(new PaddingOptimizer()); + } + + // Variables that apply to this class + variables_["classname"] = classname_; + variables_["classtype"] = QualifiedClassName(descriptor_); + string scc_name = + ClassName(scc_analyzer_->GetSCC(descriptor_)->GetRepresentative()); + variables_["scc_name"] = UniqueName(scc_name, descriptor_, options_); + variables_["full_name"] = descriptor_->full_name(); + variables_["superclass"] = SuperClassName(descriptor_, options_); + // Compute optimized field order to be used for layout and initialization // purposes. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - if (field->options().weak()) { + for (auto field : FieldRange(descriptor_)) { + if (IsWeak(field, options_)) { num_weak_fields_++; } else if (!field->containing_oneof()) { optimized_order_.push_back(field); @@ -463,8 +639,7 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, if (HasFieldPresence(descriptor_->file())) { // We use -1 as a sentinel. has_bit_indices_.resize(descriptor_->field_count(), -1); - for (int i = 0; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; + for (auto field : optimized_order_) { // Skip fields that do not have has bits. if (field->is_repeated()) { continue; @@ -472,16 +647,7 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, has_bit_indices_[field->index()] = max_has_bit_index_++; } - } - - for (int i = 0; i < descriptor->enum_type_count(); i++) { - enum_generators_[i].reset( - new EnumGenerator(descriptor->enum_type(i), options)); - } - - for (int i = 0; i < descriptor->extension_count(); i++) { - extension_generators_[i].reset( - new ExtensionGenerator(descriptor->extension(i), options)); + field_generators_.SetHasBitIndices(has_bit_indices_); } num_required_fields_ = 0; @@ -492,12 +658,9 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, } table_driven_ = TableDrivenParsingEnabled(descriptor_, options_); - - scc_name_ = - ClassName(scc_analyzer_->GetSCC(descriptor_)->GetRepresentative(), false); } -MessageGenerator::~MessageGenerator() {} +MessageGenerator::~MessageGenerator() = default; size_t MessageGenerator::HasBitsSize() const { size_t sizeof_has_bits = (max_has_bit_index_ + 31) / 32 * 4; @@ -513,23 +676,22 @@ size_t MessageGenerator::HasBitsSize() const { } void MessageGenerator::AddGenerators( - std::vector<EnumGenerator*>* enum_generators, - std::vector<ExtensionGenerator*>* extension_generators) { + std::vector<std::unique_ptr<EnumGenerator>>* enum_generators, + std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators) { for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators->push_back(enum_generators_[i].get()); + enum_generators->emplace_back( + new EnumGenerator(descriptor_->enum_type(i), variables_, options_)); + enum_generators_.push_back(enum_generators->back().get()); } for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators->push_back(extension_generators_[i].get()); + extension_generators->emplace_back( + new ExtensionGenerator(descriptor_->extension(i), options_)); + extension_generators_.push_back(extension_generators->back().get()); } } -void MessageGenerator::FillMessageForwardDeclarations( - std::map<string, const Descriptor*>* class_names) { - (*class_names)[classname_] = descriptor_; -} - -void MessageGenerator:: -GenerateFieldAccessorDeclarations(io::Printer* printer) { +void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { + Formatter format(printer, variables_); // optimized_fields_ does not contain fields where // field->containing_oneof() != NULL // so we need to iterate over those as well. @@ -540,77 +702,75 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { std::vector<const FieldDescriptor*> ordered_fields; ordered_fields.reserve(descriptor_->field_count()); - ordered_fields.insert( - ordered_fields.begin(), optimized_order_.begin(), optimized_order_.end()); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + ordered_fields.insert(ordered_fields.begin(), optimized_order_.begin(), + optimized_order_.end()); + for (auto field : FieldRange(descriptor_)) { if (field->containing_oneof() == NULL && !field->options().weak()) { continue; } ordered_fields.push_back(field); } - for (int i = 0; i < ordered_fields.size(); i++) { - const FieldDescriptor* field = ordered_fields[i]; + for (auto field : ordered_fields) { + PrintFieldComment(format, field); - PrintFieldComment(printer, field); + Formatter::SaveState save(&format); std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); - vars["constant_name"] = FieldConstantName(field); + format.AddMap(vars); if (field->is_repeated()) { - printer->Print(vars, "$deprecated_attr$int ${$$name$_size$}$() const;\n"); - printer->Annotate("{", "}", field); + format("$deprecated_attr$int ${1$$name$_size$}$() const;\n", field); } else if (HasHasMethod(field)) { - printer->Print(vars, "$deprecated_attr$bool ${$has_$name$$}$() const;\n"); - printer->Annotate("{", "}", field); + format("$deprecated_attr$bool ${1$has_$name$$}$() const;\n", field); } else if (HasPrivateHasMethod(field)) { - printer->Print(vars, - "private:\n" - "bool ${$has_$name$$}$() const;\n" - "public:\n"); - printer->Annotate("{", "}", field); + format( + "private:\n" + "bool ${1$has_$name$$}$() const;\n" + "public:\n", + field); } - printer->Print(vars, "$deprecated_attr$void ${$clear_$name$$}$();\n"); - printer->Annotate("{", "}", field); - printer->Print(vars, - "$deprecated_attr$static const int $constant_name$ = " - "$number$;\n"); - printer->Annotate("constant_name", field); + format( + "$deprecated_attr$void ${1$clear_$name$$}$();\n" + "$deprecated_attr$static const int ${1$$2$$}$ = $number$;\n", + field, FieldConstantName(field)); // Generate type-specific accessor declarations. field_generators_.get(field).GenerateAccessorDeclarations(printer); - printer->Print("\n"); + format("\n"); } 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. - printer->Print( - "GOOGLE_PROTOBUF_EXTENSION_ACCESSORS($classname$)\n", - "classname", classname_); + format("$GOOGLE_PROTOBUF$_EXTENSION_ACCESSORS($classname$)\n"); + // Generate MessageSet specific APIs for proto2 MessageSet. + // For testing purposes we don't check for bridge.MessageSet, so + // we don't use IsProto2MessageSet + if (descriptor_->options().message_set_wire_format() && + !options_.opensource_runtime && !options_.lite_implicit_weak_fields) { + // Special-case MessageSet + format("GOOGLE_PROTOBUF_EXTENSION_MESSAGE_SET_ACCESSORS($classname$)\n"); + } } - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( + for (auto oneof : OneOfRange(descriptor_)) { + Formatter::SaveState saver(&format); + format.Set("oneof_name", oneof->name()); + format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)); + format( "void clear_$oneof_name$();\n" - "$camel_oneof_name$Case $oneof_name$_case() const;\n", - "camel_oneof_name", - UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true), - "oneof_name", descriptor_->oneof_decl(i)->name()); + "$camel_oneof_name$Case $oneof_name$_case() const;\n"); } } -void MessageGenerator:: -GenerateSingularFieldHasBits(const FieldDescriptor* field, - std::map<string, string> vars, - io::Printer* printer) { +void MessageGenerator::GenerateSingularFieldHasBits( + const FieldDescriptor* field, Formatter format) { if (field->options().weak()) { - printer->Print( - vars, + format( "inline bool $classname$::has_$name$() const {\n" " return _weak_field_map_.Has($number$);\n" "}\n"); @@ -622,31 +782,23 @@ GenerateSingularFieldHasBits(const FieldDescriptor* field, int has_bit_index = has_bit_indices_[field->index()]; GOOGLE_CHECK_GE(has_bit_index, 0); - vars["has_array_index"] = SimpleItoa(has_bit_index / 32); - vars["has_mask"] = StrCat(strings::Hex(1u << (has_bit_index % 32), - strings::ZERO_PAD_8)); - printer->Print(vars, - "inline bool $classname$::has_$name$() const {\n" - " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" - "}\n" - "inline void $classname$::set_has_$name$() {\n" - " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" - "}\n" - "inline void $classname$::clear_has_$name$() {\n" - " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n" - "}\n"); + format.Set("has_array_index", has_bit_index / 32); + format.Set("has_mask", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + format( + "inline bool $classname$::has_$name$() const {\n" + " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" + "}\n"); } else { // Message fields have a has_$name$() method. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - bool is_lazy = false; - if (is_lazy) { - printer->Print(vars, - "inline bool $classname$::has_$name$() const {\n" - " return !$name$_.IsCleared();\n" - "}\n"); + if (IsLazy(field, options_)) { + format( + "inline bool $classname$::has_$name$() const {\n" + " return !$name$_.IsCleared();\n" + "}\n"); } else { - printer->Print( - vars, + format( "inline bool $classname$::has_$name$() const {\n" " return this != internal_default_instance() && $name$_ != NULL;\n" "}\n"); @@ -655,17 +807,13 @@ GenerateSingularFieldHasBits(const FieldDescriptor* field, } } -void MessageGenerator:: -GenerateOneofHasBits(io::Printer* printer) { - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - std::map<string, string> vars; - vars["oneof_name"] = descriptor_->oneof_decl(i)->name(); - vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); - vars["cap_oneof_name"] = - ToUpper(descriptor_->oneof_decl(i)->name()); - vars["classname"] = classname_; - printer->Print( - vars, +void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) { + Formatter format(printer, variables_); + for (auto oneof : OneOfRange(descriptor_)) { + format.Set("oneof_name", oneof->name()); + format.Set("oneof_index", oneof->index()); + format.Set("cap_oneof_name", ToUpper(oneof->name())); + format( "inline bool $classname$::has_$oneof_name$() const {\n" " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" "}\n" @@ -675,168 +823,157 @@ GenerateOneofHasBits(io::Printer* printer) { } } -void MessageGenerator:: -GenerateOneofMemberHasBits(const FieldDescriptor* field, - const std::map<string, string>& vars, - io::Printer* printer) { +void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, + const Formatter& format) { // Singular field in a oneof // N.B.: Without field presence, we do not use has-bits or generate // has_$name$() methods, but oneofs still have set_has_$name$(). // Oneofs also have has_$name$() but only as a private helper // method, so that generated code is slightly cleaner (vs. comparing // _oneof_case_[index] against a constant everywhere). - printer->Print(vars, - "inline bool $classname$::has_$name$() const {\n" - " return $oneof_name$_case() == k$field_name$;\n" - "}\n"); - printer->Print(vars, - "inline void $classname$::set_has_$name$() {\n" - " _oneof_case_[$oneof_index$] = k$field_name$;\n" - "}\n"); + format( + "inline bool $classname$::has_$name$() const {\n" + " return $oneof_name$_case() == k$field_name$;\n" + "}\n" + "inline void $classname$::set_has_$name$() {\n" + " _oneof_case_[$oneof_index$] = k$field_name$;\n" + "}\n"); } -void MessageGenerator:: -GenerateFieldClear(const FieldDescriptor* field, - const std::map<string, string>& vars, - bool is_inline, - io::Printer* printer) { +void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, + bool is_inline, + Formatter format) { // Generate clear_$name$(). if (is_inline) { - printer->Print("inline "); + format("inline "); } - printer->Print(vars, - "void $classname$::clear_$name$() {\n"); + format("void $classname$::clear_$name$() {\n"); - printer->Indent(); + format.Indent(); if (field->containing_oneof()) { // Clear this field only if it is the active field in this oneof, // otherwise ignore - printer->Print(vars, - "if (has_$name$()) {\n"); - printer->Indent(); - field_generators_.get(field) - .GenerateClearingCode(printer); - printer->Print(vars, - "clear_has_$oneof_name$();\n"); - printer->Outdent(); - printer->Print("}\n"); + format("if (has_$name$()) {\n"); + format.Indent(); + field_generators_.get(field).GenerateClearingCode(format.printer()); + format("clear_has_$oneof_name$();\n"); + format.Outdent(); + format("}\n"); } else { - field_generators_.get(field) - .GenerateClearingCode(printer); + field_generators_.get(field).GenerateClearingCode(format.printer()); if (HasFieldPresence(descriptor_->file())) { if (!field->is_repeated() && !field->options().weak()) { - printer->Print(vars, "clear_has_$name$();\n"); + int has_bit_index = has_bit_indices_[field->index()]; + GOOGLE_CHECK_GE(has_bit_index, 0); + + format.Set("has_array_index", has_bit_index / 32); + format.Set("has_mask", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + format("_has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"); } } } - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } -void MessageGenerator:: -GenerateFieldAccessorDefinitions(io::Printer* printer) { - printer->Print("// $classname$\n\n", "classname", classname_); - - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); +void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) { + Formatter format(printer, variables_); + format("// $classname$\n\n"); - PrintFieldComment(printer, field); + for (auto field : FieldRange(descriptor_)) { + PrintFieldComment(format, field); std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); + Formatter::SaveState saver(&format); + format.AddMap(vars); + // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { - printer->Print(vars, - "inline int $classname$::$name$_size() const {\n" - " return $name$_.size();\n" - "}\n"); + format( + "inline int $classname$::$name$_size() const {\n" + " return $name$_.size();\n" + "}\n"); } else if (field->containing_oneof()) { - vars["field_name"] = UnderscoresToCamelCase(field->name(), true); - vars["oneof_name"] = field->containing_oneof()->name(); - vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index()); - GenerateOneofMemberHasBits(field, vars, printer); + format.Set("field_name", UnderscoresToCamelCase(field->name(), true)); + format.Set("oneof_name", field->containing_oneof()->name()); + format.Set("oneof_index", + SimpleItoa(field->containing_oneof()->index())); + GenerateOneofMemberHasBits(field, format); } else { // Singular field. - GenerateSingularFieldHasBits(field, vars, printer); + GenerateSingularFieldHasBits(field, format); } if (!IsCrossFileMaybeMap(field)) { - GenerateFieldClear(field, vars, true, printer); + GenerateFieldClear(field, true, format); } // Generate type-specific accessors. field_generators_.get(field).GenerateInlineAccessorDefinitions(printer); - printer->Print("\n"); + format("\n"); } // Generate has_$name$() and clear_has_$name$() functions for oneofs. GenerateOneofHasBits(printer); } -void MessageGenerator:: -GenerateClassDefinition(io::Printer* printer) { +void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { + Formatter format(printer, variables_); if (IsMapEntryMessage(descriptor_)) { std::map<string, string> vars; - vars["classname"] = classname_; - CollectMapInfo(descriptor_, &vars); + CollectMapInfo(options_, descriptor_, &vars); vars["lite"] = HasDescriptorMethods(descriptor_->file(), options_) ? "" : "Lite"; - printer->Print( - vars, + format.AddMap(vars); + format( "class $classname$ : public " - "::google::protobuf::internal::MapEntry$lite$<$classname$, \n" + "::$proto_ns$::internal::MapEntry$lite$<$classname$, \n" " $key_cpp$, $val_cpp$,\n" - " $key_wire_type$,\n" - " $val_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$,\n" " $default_enum_value$ > {\n" "public:\n" - " typedef ::google::protobuf::internal::MapEntry$lite$<$classname$, \n" + "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n" + " static const char* _InternalParse(const char* begin, const char* " + "end, void* object, ::proto2::internal::ParseContext* ctx);\n" + "#endif // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n" + " typedef ::$proto_ns$::internal::MapEntry$lite$<$classname$, \n" " $key_cpp$, $val_cpp$,\n" - " $key_wire_type$,\n" - " $val_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n" + " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$,\n" " $default_enum_value$ > SuperType;\n" " $classname$();\n" - " $classname$(::google::protobuf::Arena* arena);\n" + " $classname$(::$proto_ns$::Arena* arena);\n" " void MergeFrom(const $classname$& other);\n" " static const $classname$* internal_default_instance() { return " "reinterpret_cast<const " "$classname$*>(&_$classname$_default_instance_); }\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print( - " void MergeFrom(const ::google::protobuf::Message& other) final;\n" - " ::google::protobuf::Metadata GetMetadata() const;\n" + format( + " void MergeFrom(const ::$proto_ns$::Message& other) final;\n" + " ::$proto_ns$::Metadata GetMetadata() const;\n" "};\n"); } else { - printer->Print("};\n"); + format("};\n"); } return; } - std::map<string, string> vars; - vars["classname"] = classname_; - vars["full_name"] = descriptor_->full_name(); - vars["field_count"] = SimpleItoa(descriptor_->field_count()); - vars["oneof_decl_count"] = SimpleItoa(descriptor_->oneof_decl_count()); - if (options_.dllexport_decl.empty()) { - vars["dllexport"] = ""; - } else { - vars["dllexport"] = options_.dllexport_decl + " "; - } - vars["superclass"] = SuperClassName(descriptor_, options_); - printer->Print(vars, - "class $dllexport$$classname$ : public $superclass$ " - "/* @@protoc_insertion_point(class_definition:$full_name$) */ " - "{\n"); - printer->Annotate("classname", descriptor_); - printer->Print(" public:\n"); - printer->Indent(); - - printer->Print( - vars, + format( + "class $dllexport_decl $${1$$classname$$}$ : public $superclass$ " + "/* @@protoc_insertion_point(class_definition:$full_name$) */ " + "{\n", + descriptor_); + format(" public:\n"); + format.Indent(); + + format( "$classname$();\n" "virtual ~$classname$();\n" "\n" @@ -848,34 +985,36 @@ GenerateClassDefinition(io::Printer* printer) { "}\n"); if (options_.table_driven_serialization) { - printer->Print( - "private:\n" - "const void* InternalGetTable() const;\n" - "public:\n" - "\n"); + format( + "private:\n" + "const void* InternalGetTable() const;\n" + "public:\n" + "\n"); } // Generate move constructor and move assignment operator. - printer->Print(vars, - "#if LANG_CXX11\n" - "$classname$($classname$&& from) noexcept\n" - " : $classname$() {\n" - " *this = ::std::move(from);\n" - "}\n" - "\n" - "inline $classname$& operator=($classname$&& from) noexcept {\n" - " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n" - " if (this != &from) InternalSwap(&from);\n" - " } else {\n" - " CopyFrom(from);\n" - " }\n" - " return *this;\n" - "}\n" - "#endif\n"); + format( + "#if LANG_CXX11\n" + "$classname$($classname$&& from) noexcept\n" + " : $classname$() {\n" + " *this = ::std::move(from);\n" + "}\n" + "\n" + "inline $classname$& operator=($classname$&& from) noexcept {\n" + " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n" + " if (this != &from) InternalSwap(&from);\n" + " } else {\n" + " CopyFrom(from);\n" + " }\n" + " return *this;\n" + "}\n" + "#endif\n"); + std::map<string, string> vars; SetUnknkownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); if (PublicUnknownFieldsAccessors(descriptor_)) { - printer->Print(vars, + format( "inline const $unknown_fields_type$& unknown_fields() const {\n" " return $unknown_fields$;\n" "}\n" @@ -889,10 +1028,10 @@ GenerateClassDefinition(io::Printer* printer) { // MessageLite's implementation which returns NULL rather than generating our // own method which returns NULL, in order to reduce code size. if (SupportsArenas(descriptor_)) { - // virtual method version of GetArenaNoVirtual(), required for generic dispatch given a - // MessageLite* (e.g., in RepeatedField::AddAllocated()). - printer->Print( - "inline ::google::protobuf::Arena* GetArena() const final {\n" + // virtual method version of GetArenaNoVirtual(), required for generic + // dispatch given a MessageLite* (e.g., in RepeatedField::AddAllocated()). + format( + "inline ::$proto_ns$::Arena* GetArena() const final {\n" " return GetArenaNoVirtual();\n" "}\n" "inline void* GetMaybeArenaPointer() const final {\n" @@ -903,229 +1042,239 @@ GenerateClassDefinition(io::Printer* printer) { // Only generate this member if it's not disabled. if (HasDescriptorMethods(descriptor_->file(), options_) && !descriptor_->options().no_standard_descriptor_accessor()) { - printer->Print(vars, - "static const ::google::protobuf::Descriptor* descriptor();\n"); + format( + "static const ::$proto_ns$::Descriptor* descriptor() {\n" + " return default_instance().GetDescriptor();\n" + "}\n"); } - printer->Print(vars, - "static const $classname$& default_instance();\n" - "\n"); + format( + "static const $classname$& default_instance();\n" + "\n"); // Generate enum values for every field in oneofs. One list is generated for // each oneof with an additional *_NOT_SET value. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "enum $camel_oneof_name$Case {\n", - "camel_oneof_name", - UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true)); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - printer->Print( - "k$field_name$ = $field_number$,\n", - "field_name", - UnderscoresToCamelCase( - descriptor_->oneof_decl(i)->field(j)->name(), true), - "field_number", - SimpleItoa(descriptor_->oneof_decl(i)->field(j)->number())); + for (auto oneof : OneOfRange(descriptor_)) { + format("enum $1$Case {\n", UnderscoresToCamelCase(oneof->name(), true)); + format.Indent(); + for (auto field : FieldRange(oneof)) { + string oneof_enum_case_field_name = + UnderscoresToCamelCase(field->name(), true); + format("k$1$ = $2$,\n", oneof_enum_case_field_name, // 1 + field->number()); // 2 } - printer->Print( - "$cap_oneof_name$_NOT_SET = 0,\n", - "cap_oneof_name", - ToUpper(descriptor_->oneof_decl(i)->name())); - printer->Outdent(); - printer->Print( + format("$1$_NOT_SET = 0,\n", ToUpper(oneof->name())); + format.Outdent(); + format( "};\n" "\n"); } // TODO(gerbens) make this private, while still granting other protos access. - vars["message_index"] = SimpleItoa(index_in_file_messages_); - printer->Print( - vars, + format( "static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY\n" "static inline const $classname$* internal_default_instance() {\n" " return reinterpret_cast<const $classname$*>(\n" " &_$classname$_default_instance_);\n" "}\n" "static constexpr int kIndexInFileMessages =\n" - " $message_index$;\n" - "\n"); + " $1$;\n" + "\n", index_in_file_messages_); if (SupportsArenas(descriptor_)) { - printer->Print(vars, - "void UnsafeArenaSwap($classname$* other);\n"); + format("void UnsafeArenaSwap($classname$* other);\n"); } if (IsAnyMessage(descriptor_)) { - printer->Print(vars, - "// implements Any -----------------------------------------------\n" - "\n" - "void PackFrom(const ::google::protobuf::Message& message);\n" - "void PackFrom(const ::google::protobuf::Message& message,\n" - " const ::std::string& type_url_prefix);\n" - "bool UnpackTo(::google::protobuf::Message* message) const;\n" - "template<typename T> bool Is() const {\n" - " return _any_metadata_.Is<T>();\n" - "}\n" - "static bool ParseAnyTypeUrl(const string& type_url,\n" - " string* full_type_name);\n" - "\n"); + format( + "// implements Any -----------------------------------------------\n" + "\n" + "void PackFrom(const ::$proto_ns$::Message& message);\n" + "void PackFrom(const ::$proto_ns$::Message& message,\n" + " const $string$& type_url_prefix);\n" + "bool UnpackTo(::$proto_ns$::Message* message) const;\n" + "template<typename T> bool Is() const {\n" + " return _any_metadata_.Is<T>();\n" + "}\n" + "static bool ParseAnyTypeUrl(const string& type_url,\n" + " string* full_type_name);\n" + "static bool GetAnyFieldDescriptors(\n" + " const ::$proto_ns$::Message& message,\n" + " const ::$proto_ns$::FieldDescriptor** type_url_field,\n" + " const ::$proto_ns$::FieldDescriptor** value_field);\n"); } - vars["new_final"] = " final"; - - printer->Print(vars, - "void Swap($classname$* other);\n" - "friend void swap($classname$& a, $classname$& b) {\n" - " a.Swap(&b);\n" - "}\n" - "\n" - "// implements Message ----------------------------------------------\n" - "\n" - "inline $classname$* New() const$new_final$ {\n" - " return CreateMaybeMessage<$classname$>(NULL);\n" - "}\n" - "\n" - "$classname$* New(::google::protobuf::Arena* arena) const$new_final$ {\n" - " return CreateMaybeMessage<$classname$>(arena);\n" - "}\n"); + format.Set("new_final", + ShouldMarkNewAsFinal(descriptor_, options_) ? "final" : ""); + + format( + "void Swap($classname$* other);\n" + "friend void swap($classname$& a, $classname$& b) {\n" + " a.Swap(&b);\n" + "}\n" + "\n" + "// implements Message ----------------------------------------------\n" + "\n" + "inline $classname$* New() const$ new_final$ {\n" + " return CreateMaybeMessage<$classname$>(NULL);\n" + "}\n" + "\n" + "$classname$* New(::$proto_ns$::Arena* arena) const$ new_final$ {\n" + " return CreateMaybeMessage<$classname$>(arena);\n" + "}\n"); // For instances that derive from Message (rather than MessageLite), some // methods are virtual and should be marked as final. - string use_final = HasDescriptorMethods(descriptor_->file(), options_) ? - " final" : ""; + format.Set("full_final", HasDescriptorMethods(descriptor_->file(), options_) + ? "final" + : ""); if (HasGeneratedMethods(descriptor_->file(), options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print(vars, - "void CopyFrom(const ::google::protobuf::Message& from) final;\n" - "void MergeFrom(const ::google::protobuf::Message& from) final;\n"); + format( + "void CopyFrom(const ::$proto_ns$::Message& from) final;\n" + "void MergeFrom(const ::$proto_ns$::Message& from) final;\n"); } else { - printer->Print(vars, - "void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)\n" - " final;\n"); + format( + "void CheckTypeAndMergeFrom(const ::$proto_ns$::MessageLite& from)\n" + " final;\n"); } - vars["clear_final"] = " final"; - vars["is_initialized_final"] = " final"; - vars["merge_partial_final"] = " final"; + format.Set("clear_final", + ShouldMarkClearAsFinal(descriptor_, options_) ? "final" : ""); + format.Set( + "is_initialized_final", + ShouldMarkIsInitializedAsFinal(descriptor_, options_) ? "final" : ""); + format.Set( + "merge_partial_final", + ShouldMarkMergePartialAsFinal(descriptor_, options_) ? "final" : ""); - printer->Print( - vars, + format( "void CopyFrom(const $classname$& from);\n" "void MergeFrom(const $classname$& from);\n" - "void Clear()$clear_final$;\n" - "bool IsInitialized() const$is_initialized_final$;\n" + "void Clear()$ clear_final$;\n" + "bool IsInitialized() const$ is_initialized_final$;\n" "\n" "size_t ByteSizeLong() const final;\n" + "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n" + "static const char* _InternalParse(const char* begin, const char* end, " + "void* object, ::proto2::internal::ParseContext* ctx);\n" + "::$proto_ns$::internal::ParseFunc _ParseFunc() const final { return " + "_InternalParse; }\n" + "#else\n" "bool MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n"); + " ::$proto_ns$::io::CodedInputStream* input)$ " + "merge_partial_final$;\n" + "#endif // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"); + if (descriptor_->options().message_set_wire_format()) { + format( + "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n" + "static const char* InternalParseMessageSetItem(const char* begin, " + "const char* end, void* object, ::proto2::internal::ParseContext* " + "ctx);\n" + "#endif // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"); + } + if (!options_.table_driven_serialization || descriptor_->options().message_set_wire_format()) { - printer->Print( + format( "void SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const " - "final;\n"); + " ::$proto_ns$::io::CodedOutputStream* output) 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_)) { - printer->Print( - "void DiscardUnknownFields()$final$;\n", - "final", use_final); + format("void DiscardUnknownFields()$ full_final$;\n"); } if (HasFastArraySerialization(descriptor_->file(), options_)) { - printer->Print( - "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n" - " bool deterministic, ::google::protobuf::uint8* target) const final;\n"); + format( + "$uint8$* InternalSerializeWithCachedSizesToArray(\n" + " bool deterministic, $uint8$* target) const final;\n"); } } - printer->Print( + format( "int GetCachedSize() const final { return _cached_size_.Get(); }" "\n\nprivate:\n" "void SharedCtor();\n" "void SharedDtor();\n" - "void SetCachedSize(int size) const$final$;\n" - "void InternalSwap($classname$* other);\n", - "classname", classname_, "final", use_final); + "void SetCachedSize(int size) const$ full_final$;\n" + "void InternalSwap($classname$* other);\n"); if (SupportsArenas(descriptor_)) { - printer->Print( - // TODO(gerbens) Make this private! Currently people are deriving from - // protos to give access to this constructor, breaking the invariants - // we rely on. - "protected:\n" - "explicit $classname$(::google::protobuf::Arena* arena);\n" - "private:\n" - "static void ArenaDtor(void* object);\n" - "inline void RegisterArenaDtor(::google::protobuf::Arena* arena);\n", - "classname", classname_); + format( + // TODO(gerbens) Make this private! Currently people are deriving from + // protos to give access to this constructor, breaking the invariants + // we rely on. + "protected:\n" + "explicit $classname$(::$proto_ns$::Arena* arena);\n" + "private:\n" + "static void ArenaDtor(void* object);\n" + "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n"); } if (SupportsArenas(descriptor_)) { - printer->Print( - "private:\n" - "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n" - " return _internal_metadata_.arena();\n" - "}\n" - "inline void* MaybeArenaPtr() const {\n" - " return _internal_metadata_.raw_arena_ptr();\n" - "}\n"); + format( + "private:\n" + "inline ::$proto_ns$::Arena* GetArenaNoVirtual() const {\n" + " return _internal_metadata_.arena();\n" + "}\n" + "inline void* MaybeArenaPtr() const {\n" + " return _internal_metadata_.raw_arena_ptr();\n" + "}\n"); } else { - printer->Print( - "private:\n" - "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n" - " return NULL;\n" - "}\n" - "inline void* MaybeArenaPtr() const {\n" - " return NULL;\n" - "}\n"); + format( + "private:\n" + "inline ::$proto_ns$::Arena* GetArenaNoVirtual() const {\n" + " return NULL;\n" + "}\n" + "inline void* MaybeArenaPtr() const {\n" + " return NULL;\n" + "}\n"); } - printer->Print( + format( "public:\n" "\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print( - "::google::protobuf::Metadata GetMetadata() const final;\n" - "\n"); + format( + "::$proto_ns$::Metadata GetMetadata() const final;\n" + "\n"); } else { - printer->Print( - "::std::string GetTypeName() const final;\n" - "\n"); + format( + "$string$ GetTypeName() const final;\n" + "\n"); } - printer->Print( - "// nested types ----------------------------------------------------\n" - "\n"); + format( + "// nested types ----------------------------------------------------\n" + "\n"); // Import all nested message classes into this class's scope with typedefs. for (int i = 0; i < descriptor_->nested_type_count(); i++) { const Descriptor* nested_type = descriptor_->nested_type(i); if (!IsMapEntryMessage(nested_type)) { - printer->Print("typedef $nested_full_name$ $nested_name$;\n", - "nested_name", nested_type->name(), - "nested_full_name", ClassName(nested_type, false)); - printer->Annotate("nested_full_name", nested_type); - printer->Annotate("nested_name", nested_type); + format.Set("nested_full_name", ClassName(nested_type, false)); + format.Set("nested_name", nested_type->name()); + format("typedef ${1$$nested_full_name$$}$ ${1$$nested_name$$}$;\n", + nested_type); } } if (descriptor_->nested_type_count() > 0) { - printer->Print("\n"); + format("\n"); } // Import all nested enums and their values into this class's scope with // typedefs and constants. for (int i = 0; i < descriptor_->enum_type_count(); i++) { enum_generators_[i]->GenerateSymbolImports(printer); - printer->Print("\n"); + format("\n"); } - printer->Print( - "// accessors -------------------------------------------------------\n" - "\n"); + format( + "// accessors -------------------------------------------------------\n" + "\n"); // Generate accessor methods for all fields. GenerateFieldAccessorDeclarations(printer); @@ -1136,49 +1285,37 @@ GenerateClassDefinition(io::Printer* printer) { } - printer->Print( - "// @@protoc_insertion_point(class_scope:$full_name$)\n", - "full_name", descriptor_->full_name()); + format("// @@protoc_insertion_point(class_scope:$full_name$)\n"); // Generate private members. - printer->Outdent(); - printer->Print(" private:\n"); - printer->Indent(); - - - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->is_repeated() && - !descriptor_->field(i)->options().weak()) { - // set_has_***() generated in all proto1/2 code and in oneofs (only) for - // messages without true field presence. - if (HasFieldPresence(descriptor_->file()) || - descriptor_->field(i)->containing_oneof()) { - printer->Print("void set_has_$name$();\n", "name", - FieldName(descriptor_->field(i))); - } - // clear_has_***() generated only for non-oneof fields - // in proto1/2. - if (!descriptor_->field(i)->containing_oneof() && - HasFieldPresence(descriptor_->file())) { - printer->Print("void clear_has_$name$();\n", "name", - FieldName(descriptor_->field(i))); - } + format.Outdent(); + format(" private:\n"); + format.Indent(); + // TODO(seongkim): Remove hack to track field access and remove this class. + format("class HasBitSetters;\n"); + + + for (auto field : FieldRange(descriptor_)) { + // set_has_***() generated in all oneofs. + if (!field->is_repeated() && !field->options().weak() && + field->containing_oneof()) { + format("void set_has_$1$();\n", FieldName(field)); } } - printer->Print("\n"); + format("\n"); // Generate oneof function declarations - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); + for (auto oneof : OneOfRange(descriptor_)) { + format( + "inline bool has_$1$() const;\n" + "inline void clear_has_$1$();\n\n", + oneof->name()); } if (HasGeneratedMethods(descriptor_->file(), options_) && !descriptor_->options().message_set_wire_format() && num_required_fields_ > 1) { - printer->Print( + format( "// helper for ByteSizeLong()\n" "size_t RequiredFieldsByteSizeFallback() const;\n\n"); } @@ -1187,14 +1324,15 @@ GenerateClassDefinition(io::Printer* printer) { // output will be determined later. bool need_to_emit_cached_size = true; - // TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it. const string cached_size_decl = - "mutable ::google::protobuf::internal::CachedSize _cached_size_;\n"; + "mutable ::$proto_ns$::internal::CachedSize _cached_size_;\n"; const size_t sizeof_has_bits = HasBitsSize(); - const string has_bits_decl = sizeof_has_bits == 0 ? "" : - "::google::protobuf::internal::HasBits<" + SimpleItoa(sizeof_has_bits / 4) + - "> _has_bits_;\n"; + const string has_bits_decl = + sizeof_has_bits == 0 + ? "" + : "::$proto_ns$::internal::HasBits<" + + SimpleItoa(sizeof_has_bits / 4) + "> _has_bits_;\n"; // To minimize padding, data members are divided into three sections: // (1) members assumed to align to 8 bytes @@ -1205,154 +1343,142 @@ GenerateClassDefinition(io::Printer* printer) { // Members assumed to align to 8 bytes: if (descriptor_->extension_range_count() > 0) { - printer->Print( - "::google::protobuf::internal::ExtensionSet _extensions_;\n" - "\n"); + format( + "::$proto_ns$::internal::ExtensionSet _extensions_;\n" + "\n"); } if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n"); + format( + "::$proto_ns$::internal::InternalMetadataWithArena " + "_internal_metadata_;\n"); } else { - printer->Print( - "::google::protobuf::internal::InternalMetadataWithArenaLite " + format( + "::$proto_ns$::internal::InternalMetadataWithArenaLite " "_internal_metadata_;\n"); } if (SupportsArenas(descriptor_)) { - printer->Print( - "template <typename T> friend class ::google::protobuf::Arena::InternalHelper;\n" - "typedef void InternalArenaConstructable_;\n" - "typedef void DestructorSkippable_;\n"); + if (!options_.opensource_runtime) { + format( + "template <typename T> friend struct " + "::proto::internal::EmbeddedMessageHolder;\n"); + } + format( + "template <typename T> friend class " + "::$proto_ns$::Arena::InternalHelper;\n" + "typedef void InternalArenaConstructable_;\n" + "typedef void DestructorSkippable_;\n"); } if (HasFieldPresence(descriptor_->file())) { // _has_bits_ is frequently accessed, so to reduce code size and improve - // speed, it should be close to the start of the object. But, try not to - // waste space:_has_bits_ by itself always makes sense if its size is a - // multiple of 8, but, otherwise, maybe _has_bits_ and cached_size_ together - // will work well. - printer->Print(has_bits_decl.c_str()); - if ((sizeof_has_bits % 8) != 0) { - printer->Print(cached_size_decl.c_str()); - need_to_emit_cached_size = false; - } + // speed, it should be close to the start of the object. Placing + // _cached_size_ together with _has_bits_ improves cache locality despite + // potential alignment padding. + format(has_bits_decl.c_str()); + format(cached_size_decl.c_str()); + need_to_emit_cached_size = false; } // Field members: // Emit some private and static members - for (int i = 0; i < optimized_order_.size(); ++i) { - const FieldDescriptor* field = optimized_order_[i]; + for (auto field : optimized_order_) { const FieldGenerator& generator = field_generators_.get(field); generator.GenerateStaticMembers(printer); generator.GeneratePrivateMembers(printer); } // For each oneof generate a union - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "union $camel_oneof_name$Union {\n" + for (auto oneof : OneOfRange(descriptor_)) { + string camel_oneof_name = UnderscoresToCamelCase(oneof->name(), true); + format( + "union $1$Union {\n" // explicit empty constructor is needed when union contains // ArenaStringPtr members for string fields. - " $camel_oneof_name$Union() {}\n", - "camel_oneof_name", - UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true)); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - field_generators_.get(descriptor_->oneof_decl(i)-> - field(j)).GeneratePrivateMembers(printer); + " $1$Union() {}\n", + camel_oneof_name); + format.Indent(); + for (auto field : FieldRange(oneof)) { + field_generators_.get(field).GeneratePrivateMembers(printer); } - printer->Outdent(); - printer->Print( - "} $oneof_name$_;\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - field_generators_.get(descriptor_->oneof_decl(i)-> - field(j)).GenerateStaticMembers(printer); + format.Outdent(); + format("} $1$_;\n", oneof->name()); + for (auto field : FieldRange(oneof)) { + field_generators_.get(field).GenerateStaticMembers(printer); } } // Members assumed to align to 4 bytes: if (need_to_emit_cached_size) { - printer->Print(cached_size_decl.c_str()); + format(cached_size_decl.c_str()); need_to_emit_cached_size = false; } // Generate _oneof_case_. if (descriptor_->oneof_decl_count() > 0) { - printer->Print(vars, - "::google::protobuf::uint32 _oneof_case_[$oneof_decl_count$];\n" - "\n"); + format( + "$uint32$ _oneof_case_[$1$];\n" + "\n", + descriptor_->oneof_decl_count()); } if (num_weak_fields_) { - printer->Print( - "::google::protobuf::internal::WeakFieldMap _weak_field_map_;\n"); + format("::$proto_ns$::internal::WeakFieldMap _weak_field_map_;\n"); } // Generate _any_metadata_ for the Any type. if (IsAnyMessage(descriptor_)) { - printer->Print(vars, - "::google::protobuf::internal::AnyMetadata _any_metadata_;\n"); + format("::$proto_ns$::internal::AnyMetadata _any_metadata_;\n"); } // The TableStruct struct needs access to the private parts, in order to // construct the offsets of all members. - printer->Print("friend struct ::$file_namespace$::TableStruct;\n", - // Vars. - "scc_name", scc_name_, "file_namespace", - FileLevelNamespace(descriptor_)); + format("friend struct ::$tablename$;\n"); - printer->Outdent(); - printer->Print("};"); + format.Outdent(); + format("};"); GOOGLE_DCHECK(!need_to_emit_cached_size); } -void MessageGenerator:: -GenerateInlineMethods(io::Printer* printer) { +void MessageGenerator::GenerateInlineMethods(io::Printer* printer) { if (IsMapEntryMessage(descriptor_)) return; GenerateFieldAccessorDefinitions(printer); // Generate oneof_case() functions. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - std::map<string, string> vars; - vars["class_name"] = classname_; - vars["camel_oneof_name"] = UnderscoresToCamelCase( - descriptor_->oneof_decl(i)->name(), true); - vars["oneof_name"] = descriptor_->oneof_decl(i)->name(); - vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); - printer->Print( - vars, - "inline $class_name$::$camel_oneof_name$Case $class_name$::" + for (auto oneof : OneOfRange(descriptor_)) { + Formatter format(printer, variables_); + format.Set("camel_oneof_name", UnderscoresToCamelCase(oneof->name(), true)); + format.Set("oneof_name", oneof->name()); + format.Set("oneof_index", oneof->index()); + format( + "inline $classname$::$camel_oneof_name$Case $classname$::" "$oneof_name$_case() const {\n" - " return $class_name$::$camel_oneof_name$Case(" + " return $classname$::$camel_oneof_name$Case(" "_oneof_case_[$oneof_index$]);\n" "}\n"); } } -void MessageGenerator:: -GenerateExtraDefaultFields(io::Printer* printer) { +void MessageGenerator::GenerateExtraDefaultFields(io::Printer* printer) { // Generate oneof default instance and weak field instances for reflection // usage. + Formatter format(printer, variables_); if (descriptor_->oneof_decl_count() > 0 || num_weak_fields_ > 0) { - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + for (auto oneof : OneOfRange(descriptor_)) { + for (auto field : FieldRange(oneof)) { if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && - EffectiveStringCType(field) != FieldOptions::STRING)) { - printer->Print("const "); + EffectiveStringCType(field, options_) != FieldOptions::STRING)) { + format("const "); } field_generators_.get(field).GeneratePrivateMembers(printer); } } - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + for (auto field : FieldRange(descriptor_)) { if (field->options().weak()) { - printer->Print( - " const ::google::protobuf::Message* $name$_;\n", "name", FieldName(field)); + format(" const ::$proto_ns$::Message* $1$_;\n", FieldName(field)); } } } @@ -1360,130 +1486,85 @@ GenerateExtraDefaultFields(io::Printer* printer) { bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset, size_t aux_offset) { + Formatter format(printer, variables_); + if (!table_driven_) { - printer->Print("{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },\n"); + format("{ NULL, NULL, 0, -1, -1, -1, -1, NULL, false },\n"); return false; } - std::map<string, string> vars; - - vars["classname"] = ClassName(descriptor_); - vars["classtype"] = QualifiedClassName(descriptor_); - vars["offset"] = SimpleItoa(offset); - vars["aux_offset"] = SimpleItoa(aux_offset); - int max_field_number = 0; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + for (auto field : FieldRange(descriptor_)) { if (max_field_number < field->number()) { max_field_number = field->number(); } } - vars["max_field_number"] = SimpleItoa(max_field_number); - - printer->Print("{\n"); - printer->Indent(); + format("{\n"); + format.Indent(); - printer->Print(vars, - "TableStruct::entries + $offset$,\n" - "TableStruct::aux + $aux_offset$,\n" - "$max_field_number$,\n"); + format( + "$tablename$::entries + $1$,\n" + "$tablename$::aux + $2$,\n" + "$3$,\n", + offset, aux_offset, max_field_number); if (!HasFieldPresence(descriptor_->file())) { // If we don't have field presence, then _has_bits_ does not exist. - printer->Print(vars, "-1,\n"); + format("-1,\n"); } else { - printer->Print(vars, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" - " $classtype$, _has_bits_),\n"); + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET(\n" + " $classtype$, _has_bits_),\n"); } if (descriptor_->oneof_decl_count() > 0) { - printer->Print(vars, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" - " $classtype$, _oneof_case_),\n"); + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET(\n" + " $classtype$, _oneof_case_),\n"); } else { - printer->Print("-1, // no _oneof_case_\n"); + format("-1, // no _oneof_case_\n"); } if (descriptor_->extension_range_count() > 0) { - printer->Print(vars, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " - "_extensions_),\n"); + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "_extensions_),\n"); } else { - printer->Print("-1, // no _extensions_\n"); + format("-1, // no _extensions_\n"); } // TODO(ckennelly): Consolidate this with the calculation for // AuxillaryParseTableField. - vars["ns"] = Namespace(descriptor_); - - printer->Print(vars, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" - " $classtype$, _internal_metadata_),\n" - "&$ns$::_$classname$_default_instance_,\n"); + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET(\n" + " $classtype$, _internal_metadata_),\n" + "&$package_ns$::_$classname$_default_instance_,\n"); if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(vars, "true,\n"); + format("true,\n"); } else { - printer->Print(vars, "false,\n"); + format("false,\n"); } - printer->Outdent(); - printer->Print("},\n"); + format.Outdent(); + format("},\n"); return true; } void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, int has_offset) { - std::map<string, string> vars; - - vars["classname"] = QualifiedClassName(descriptor_); - vars["offset"] = SimpleItoa(offset); - vars["has_bits_offsets"] = + Formatter format(printer, variables_); + has_offset = HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_) - ? SimpleItoa(offset + has_offset) - : "-1"; + ? offset + has_offset + : -1; - printer->Print(vars, - "{ $offset$, $has_bits_offsets$, sizeof($classname$)},\n"); + format("{ $1$, $2$, sizeof($classtype$)},\n", offset, has_offset); } namespace { -// TODO(gerbens) remove this after the next sync with GitHub code base. -// Then the opensource testing has gained the functionality to compile -// the CalcFieldNum given the symbols defined in generated-message-util. -#ifdef OPENSOURCE_PROTOBUF_CPP_BOOTSTRAP -// We need a clean version of CalcFieldNum that doesn't use new functionality -// in the runtime, because this functionality is not yet in the opensource -// runtime - -uint32 CalculateType(uint32 type, uint32 type_class) { - return (type - 1) + type_class * 20; -} - -uint32 CalcFieldNum(const FieldGenerator&, const FieldDescriptor* field, - const Options& options) { - bool is_a_map = IsMapEntryMessage(field->containing_type()); - int type = field->type(); - if (field->containing_oneof()) { - return CalculateType(type, 4); - } - if (field->is_packed()) { - return CalculateType(type, 3); - } else if (field->is_repeated()) { - return CalculateType(type, 2); - } else if (!HasFieldPresence(field->file()) && - field->containing_oneof() == NULL && !is_a_map) { - return CalculateType(type, 1); - } else { - return CalculateType(type, 0); - } -} - -#else // We need to calculate for each field what function the table driven code // should use to serialize it. This returns the index in a lookup table. uint32 CalcFieldNum(const FieldGenerator& generator, @@ -1495,6 +1576,12 @@ uint32 CalcFieldNum(const FieldGenerator& generator, if (generator.IsInlined()) { type = internal::FieldMetadata::kInlinedType; } + // string field + if (IsCord(field, options)) { + type = internal::FieldMetadata::kCordType; + } else if (IsStringPiece(field, options)) { + type = internal::FieldMetadata::kStringPieceType; + } } if (field->containing_oneof()) { return internal::FieldMetadata::CalculateType( @@ -1515,7 +1602,6 @@ uint32 CalcFieldNum(const FieldGenerator& generator, type, internal::FieldMetadata::kPresence); } } -#endif int FindMessageIndexInFile(const Descriptor* descriptor) { std::vector<const Descriptor*> flatten = @@ -1527,12 +1613,11 @@ int FindMessageIndexInFile(const Descriptor* descriptor) { } // namespace int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { + Formatter format(printer, variables_); if (!options_.table_driven_serialization) { return 0; } - string full_classname = QualifiedClassName(descriptor_); - std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_); if (IsMapEntryMessage(descriptor_)) { for (int i = 0; i < 2; i++) { @@ -1543,36 +1628,40 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { field->number(), WireFormat::WireTypeForFieldType(field->type())); std::map<string, string> vars; - vars["classname"] = QualifiedClassName(descriptor_); + vars["classtype"] = QualifiedClassName(descriptor_); vars["field_name"] = FieldName(field); vars["tag"] = SimpleItoa(tag); vars["hasbit"] = SimpleItoa(i); - vars["type"] = SimpleItoa(CalcFieldNum(generator, field, options_)); + vars["type"] = + SimpleItoa(CalcFieldNum(generator, field, options_)); vars["ptr"] = "NULL"; if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { GOOGLE_CHECK(!IsMapEntryMessage(field->message_type())); - { + if (!IsProto1(field->message_type()->file(), options_)) { vars["ptr"] = - "::" + FileLevelNamespace(field->message_type()) + - "::TableStruct::serialization_table + " + - SimpleItoa(FindMessageIndexInFile(field->message_type())); + "::" + + UniqueName("TableStruct", field->message_type(), options_) + + "::serialization_table + " + + SimpleItoa( + FindMessageIndexInFile(field->message_type())); } } - printer->Print(vars, - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "::google::protobuf::internal::MapEntryHelper<$classname$::" - "SuperType>, $field_name$_), $tag$," - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "::google::protobuf::internal::MapEntryHelper<$classname$::" - "SuperType>, _has_bits_) * 8 + $hasbit$, $type$, " - "$ptr$},\n"); + Formatter::SaveState saver(&format); + format.AddMap(vars); + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET(" + "::$proto_ns$::internal::MapEntryHelper<$classtype$::" + "SuperType>, $field_name$_), $tag$," + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET(" + "::$proto_ns$::internal::MapEntryHelper<$classtype$::" + "SuperType>, _has_bits_) * 8 + $hasbit$, $type$, " + "$ptr$},\n"); } return 2; } - printer->Print( - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " - "_cached_size_), 0, 0, 0, NULL},\n", - "classname", full_classname); + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "_cached_size_), 0, 0, 0, NULL},\n"); std::vector<const Descriptor::ExtensionRange*> sorted_extensions; for (int i = 0; i < descriptor_->extension_range_count(); ++i) { sorted_extensions.push_back(descriptor_->extension_range(i)); @@ -1586,14 +1675,13 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { extension_idx++) { const Descriptor::ExtensionRange* range = sorted_extensions[extension_idx]; - printer->Print( - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " - "_extensions_), $start$, $end$, " - "::google::protobuf::internal::FieldMetadata::kSpecial, " + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "_extensions_), " + "$1$, $2$, ::$proto_ns$::internal::FieldMetadata::kSpecial, " "reinterpret_cast<const " - "void*>(::google::protobuf::internal::ExtensionSerializer)},\n", - "classname", full_classname, "start", SimpleItoa(range->start), "end", - SimpleItoa(range->end)); + "void*>(::$proto_ns$::internal::ExtensionSerializer)},\n", + range->start, range->end); } if (i == sorted.size()) break; const FieldDescriptor* field = sorted[i]; @@ -1609,105 +1697,121 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { if (field->containing_oneof()) { classfieldname = field->containing_oneof()->name(); } - std::map<string, string> vars; - vars["classname"] = full_classname; - vars["field_name"] = classfieldname; - vars["tag"] = SimpleItoa(tag); - vars["ptr"] = "NULL"; + format.Set("field_name", classfieldname); + string ptr = "NULL"; if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (IsMapEntryMessage(field->message_type())) { - vars["idx"] = SimpleItoa(FindMessageIndexInFile(field->message_type())); - vars["fieldclassname"] = QualifiedClassName(field->message_type()); - printer->Print(vars, - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" - "classname$, $field_name$_), $tag$, $idx$, " - "::google::protobuf::internal::FieldMetadata::kSpecial, " - "reinterpret_cast<const void*>(static_cast< " - "::google::protobuf::internal::SpecialSerializer>(" - "::google::protobuf::internal::MapFieldSerializer< " - "::google::protobuf::internal::MapEntryToMapField<" - "$fieldclassname$>::MapFieldType, " - "TableStruct::serialization_table>))},\n"); + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($" + "classtype$, $field_name$_), $1$, $2$, " + "::$proto_ns$::internal::FieldMetadata::kSpecial, " + "reinterpret_cast<const void*>(static_cast< " + "::$proto_ns$::internal::SpecialSerializer>(" + "::$proto_ns$::internal::MapFieldSerializer< " + "::$proto_ns$::internal::MapEntryToMapField<" + "$3$>::MapFieldType, " + "$tablename$::serialization_table>))},\n", + tag, FindMessageIndexInFile(field->message_type()), + QualifiedClassName(field->message_type())); continue; - } else { - vars["ptr"] = - "::" + FileLevelNamespace(field->message_type()) + - "::TableStruct::serialization_table + " + + } else if (!IsProto1(field->message_type()->file(), options_) && + !field->message_type()->options().message_set_wire_format()) { + // Proto1 or message_set don't have the usual table and we need to + // dispatch to generated serializer, hence ptr stays zero. + ptr = + "::" + UniqueName("TableStruct", field->message_type(), options_) + + "::serialization_table + " + SimpleItoa(FindMessageIndexInFile(field->message_type())); } } const FieldGenerator& generator = field_generators_.get(field); - vars["type"] = SimpleItoa(CalcFieldNum(generator, field, options_)); + int type = CalcFieldNum(generator, field, options_); + if (IsLazy(field, options_)) { + type = internal::FieldMetadata::kSpecial; + ptr = "reinterpret_cast<const void*>(::" + variables_["proto_ns"] + + "::internal::LazyFieldSerializer"; + if (field->containing_oneof()) { + ptr += "OneOf"; + } else if (!HasFieldPresence(descriptor_->file()) || + has_bit_indices_[field->index()] == -1) { + ptr += "NoPresence"; + } + ptr += ")"; + } if (field->options().weak()) { // TODO(gerbens) merge weak fields into ranges - printer->Print(vars, - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" - "classname$, _weak_field_map_), $tag$, $tag$, " - "::google::protobuf::internal::FieldMetadata::kSpecial, " - "reinterpret_cast<const " - "void*>(::google::protobuf::internal::WeakFieldSerializer)},\n"); + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classtype$, _weak_field_map_), $1$, $1$, " + "::$proto_ns$::internal::FieldMetadata::kSpecial, " + "reinterpret_cast<const " + "void*>(::$proto_ns$::internal::WeakFieldSerializer)},\n", + tag); } else if (field->containing_oneof()) { - vars["oneofoffset"] = - SimpleItoa(sizeof(uint32) * field->containing_oneof()->index()); - printer->Print(vars, - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" - "classname$, $field_name$_), $tag$, " - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" - "classname$, _oneof_case_) + $oneofoffset$, " - "$type$, $ptr$},\n"); + format.Set("oneofoffset", + sizeof(uint32) * field->containing_oneof()->index()); + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "$field_name$_), " + "$1$, $GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "_oneof_case_) + $oneofoffset$, $2$, $3$},\n", + tag, type, ptr); } else if (HasFieldPresence(descriptor_->file()) && has_bit_indices_[field->index()] != -1) { - vars["hasbitsoffset"] = SimpleItoa(has_bit_indices_[field->index()]); - printer->Print(vars, - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" - "classname$, $field_name$_), $tag$, " - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" - "classname$, _has_bits_) * 8 + $hasbitsoffset$, $type$, " - "$ptr$},\n"); + format.Set("hasbitsoffset", has_bit_indices_[field->index()]); + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "$field_name$_), " + "$1$, $GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "_has_bits_) * 8 + $hasbitsoffset$, $2$, $3$},\n", + tag, type, ptr); } else { - printer->Print(vars, - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" - "classname$, $field_name$_), $tag$, ~0u, $type$, " - "$ptr$},\n"); + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "$field_name$_), " + "$1$, ~0u, $2$, $3$},\n", + tag, type, ptr); } } int num_field_metadata = 1 + sorted.size() + sorted_extensions.size(); num_field_metadata++; string serializer = UseUnknownFieldSet(descriptor_->file(), options_) - ? "::google::protobuf::internal::UnknownFieldSetSerializer" - : "::google::protobuf::internal::UnknownFieldSerializerLite"; - printer->Print( - "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " + ? "UnknownFieldSetSerializer" + : "UnknownFieldSerializerLite"; + format( + "{$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " "_internal_metadata_), 0, ~0u, " - "::google::protobuf::internal::FieldMetadata::kSpecial, reinterpret_cast<const " - "void*>($serializer$)},\n", - "classname", full_classname, "serializer", serializer); + "::$proto_ns$::internal::FieldMetadata::kSpecial, reinterpret_cast<const " + "void*>(::$proto_ns$::internal::$1$)},\n", + serializer); return num_field_metadata; } void MessageGenerator::GenerateFieldDefaultInstances(io::Printer* printer) { // Construct the default instances for all fields that need one. - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateDefaultInstanceAllocator(printer); + for (auto field : FieldRange(descriptor_)) { + field_generators_.get(field).GenerateDefaultInstanceAllocator(printer); } } -void MessageGenerator:: -GenerateDefaultInstanceInitializer(io::Printer* printer) { +void MessageGenerator::GenerateDefaultInstanceInitializer( + io::Printer* printer) { + Formatter format(printer, variables_); + // The default instance needs all of its embedded message pointers // cross-linked to other default instances. We can't do this initialization // in the constructor because some other default instances may not have been // constructed yet at that time. // TODO(kenton): Maybe all message fields (even for non-default messages) // should be initialized to point at default instances rather than NULL? - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + for (auto field : FieldRange(descriptor_)) { + Formatter::SaveState saver(&format); if (!field->is_repeated() && + !IsLazy(field, options_) && field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && (field->containing_oneof() == NULL || HasDescriptorMethods(descriptor_->file(), options_))) { @@ -1719,201 +1823,244 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) { "_" + classname_ + "_default_instance_._instance.get_mutable()->"; } name += FieldName(field); - printer->Print( - "$ns$::$name$_ = const_cast< $type$*>(\n" - " $type$::internal_default_instance());\n", - // Vars. - "name", name, "type", FieldMessageTypeName(field), "ns", - Namespace(descriptor_)); + format.Set("name", name); + if (IsWeak(field, options_)) { + const FileDescriptor* dependency = field->message_type()->file(); + string default_instance = QualifiedFileLevelSymbol( + dependency->package(), + "_" + ClassName(field->message_type()) + "_default_instance_"); + format( + "$package_ns$::$name$_ = reinterpret_cast<const " + "::$proto_ns$::Message*>(&$1$);\n" + "if ($package_ns$::$name$_ == NULL) {\n" + " $package_ns$::$name$_ = " + "::$proto_ns$::Empty::internal_default_instance();\n" + "}\n", + default_instance); // 1 + continue; + } + format( + "$package_ns$::$name$_ = const_cast< $1$*>(\n" + " $1$::internal_default_instance());\n", + FieldMessageTypeName(field)); } else if (field->containing_oneof() && HasDescriptorMethods(descriptor_->file(), options_)) { - field_generators_.get(descriptor_->field(i)) - .GenerateConstructorCode(printer); + field_generators_.get(field).GenerateConstructorCode(printer); } } } -void MessageGenerator:: -GenerateClassMethods(io::Printer* printer) { +void MessageGenerator::GenerateClassMethods(io::Printer* printer) { + Formatter format(printer, variables_); if (IsMapEntryMessage(descriptor_)) { - printer->Print( + format( "$classname$::$classname$() {}\n" - "$classname$::$classname$(::google::protobuf::Arena* arena) : " - "SuperType(arena) {}\n" + "$classname$::$classname$(::$proto_ns$::Arena* arena)\n" + " : SuperType(arena) {}\n" "void $classname$::MergeFrom(const $classname$& other) {\n" " MergeFromInternal(other);\n" - "}\n", - "classname", classname_); + "}\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print( - "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" - " ::$file_namespace$::protobuf_AssignDescriptorsOnce();\n" - " return ::$file_namespace$::file_level_metadata[$index$];\n" - "}\n" + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + " " + "::$proto_ns$::internal::AssignDescriptors(&::$assign_desc_table$);\n" + " return ::$file_level_metadata$[$1$];\n" + "}\n", + index_in_file_messages_); + format( "void $classname$::MergeFrom(\n" - " const ::google::protobuf::Message& other) {\n" - " ::google::protobuf::Message::MergeFrom(other);\n" + " const ::$proto_ns$::Message& other) {\n" + " ::$proto_ns$::Message::MergeFrom(other);\n" "}\n" - "\n", - "file_namespace", FileLevelNamespace(descriptor_), - "classname", classname_, "index", - SimpleItoa(index_in_file_messages_)); + "\n"); } + // TODO(gerbens) make maps parse :( + format( + "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n" + "const char* $classname$::_InternalParse(const char* begin, const " + "char* end, void* object, ::proto2::internal::ParseContext* ctx) { " + "return end; }\n" + "#endif // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"); + format("\n"); return; } // TODO(gerbens) Remove this function. With a little bit of cleanup and // refactoring this is superfluous. - printer->Print("void $classname$::InitAsDefaultInstance() {\n", "classname", - classname_); - printer->Indent(); + format("void $classname$::InitAsDefaultInstance() {\n"); + format.Indent(); GenerateDefaultInstanceInitializer(printer); - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); if (IsAnyMessage(descriptor_)) { - printer->Print( - "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n" - " _any_metadata_.PackFrom(message);\n" - "}\n" - "\n" - "void $classname$::PackFrom(const ::google::protobuf::Message& message,\n" - " const ::std::string& type_url_prefix) {\n" - " _any_metadata_.PackFrom(message, type_url_prefix);\n" - "}\n" - "\n" - "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n" - " return _any_metadata_.UnpackTo(message);\n" - "}\n" - "bool $classname$::ParseAnyTypeUrl(const string& type_url,\n" - " string* full_type_name) {\n" - " return ::google::protobuf::internal::ParseAnyTypeUrl(type_url,\n" - " full_type_name);\n" - "}\n" - "\n", - "classname", classname_); + format( + "void $classname$::PackFrom(const ::$proto_ns$::Message& message) {\n" + " _any_metadata_.PackFrom(message);\n" + "}\n" + "\n" + "void $classname$::PackFrom(const ::$proto_ns$::Message& message,\n" + " const $string$& type_url_prefix) {\n" + " _any_metadata_.PackFrom(message, type_url_prefix);\n" + "}\n" + "\n" + "bool $classname$::UnpackTo(::$proto_ns$::Message* message) const {\n" + " return _any_metadata_.UnpackTo(message);\n" + "}\n" + "bool $classname$::ParseAnyTypeUrl(const string& type_url,\n" + " string* full_type_name) {\n" + " return ::$proto_ns$::internal::ParseAnyTypeUrl(type_url,\n" + " full_type_name);\n" + "}\n" + "bool $classname$::GetAnyFieldDescriptors(\n" + " const ::$proto_ns$::Message& message,\n" + " const ::$proto_ns$::FieldDescriptor** type_url_field,\n" + " const ::$proto_ns$::FieldDescriptor** value_field) {\n" + " return ::$proto_ns$::internal::GetAnyFieldDescriptors(\n" + " message, type_url_field, value_field);\n" + "}\n" + "\n"); + } + + format( + "class $classname$::HasBitSetters {\n" + " public:\n"); + format.Indent(); + for (auto field : FieldRange(descriptor_)) { + field_generators_.get(field).GenerateInternalAccessorDeclarations(printer); + if (HasFieldPresence(descriptor_->file()) && !field->is_repeated() && + !field->options().weak() && !field->containing_oneof()) { + int has_bit_index = has_bit_indices_[field->index()]; + GOOGLE_CHECK_GE(has_bit_index, 0); + + format.Set("has_array_index", has_bit_index / 32); + format.Set("has_mask", + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); + format( + "static void set_has_$1$($classname$* msg) {\n" + " msg->_has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" + "}\n", + FieldName(field)); + } + } + format.Outdent(); + format("};\n\n"); + for (auto field : FieldRange(descriptor_)) { + field_generators_.get(field).GenerateInternalAccessorDefinitions(printer); } // Generate non-inline field definitions. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - field_generators_.get(field) - .GenerateNonInlineAccessorDefinitions(printer); + for (auto field : FieldRange(descriptor_)) { + field_generators_.get(field).GenerateNonInlineAccessorDefinitions(printer); if (IsCrossFileMaybeMap(field)) { + Formatter::SaveState saver(&format); std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); if (field->containing_oneof()) { SetCommonOneofFieldVariables(field, &vars); } - GenerateFieldClear(field, vars, false, printer); + format.AddMap(vars); + GenerateFieldClear(field, false, format); } } // Generate field number constants. - printer->Print("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor *field = descriptor_->field(i); - printer->Print( - "const int $classname$::$constant_name$;\n", - "classname", ClassName(FieldScope(field), false), - "constant_name", FieldConstantName(field)); - } - printer->Print( - "#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n" - "\n"); + format("#if !defined(_MSC_VER) || _MSC_VER >= 1900\n"); + for (auto field : FieldRange(descriptor_)) { + format("const int $classname$::$1$;\n", FieldConstantName(field)); + } + format( + "#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n" + "\n"); GenerateStructors(printer); - printer->Print("\n"); + format("\n"); if (descriptor_->oneof_decl_count() > 0) { GenerateOneofClear(printer); - printer->Print("\n"); + format("\n"); } if (HasGeneratedMethods(descriptor_->file(), options_)) { GenerateClear(printer); - printer->Print("\n"); + format("\n"); GenerateMergeFromCodedStream(printer); - printer->Print("\n"); + format("\n"); GenerateSerializeWithCachedSizes(printer); - printer->Print("\n"); + format("\n"); if (HasFastArraySerialization(descriptor_->file(), options_)) { GenerateSerializeWithCachedSizesToArray(printer); - printer->Print("\n"); + format("\n"); } GenerateByteSize(printer); - printer->Print("\n"); + format("\n"); GenerateMergeFrom(printer); - printer->Print("\n"); + format("\n"); GenerateCopyFrom(printer); - printer->Print("\n"); + format("\n"); GenerateIsInitialized(printer); - printer->Print("\n"); + format("\n"); } GenerateSwap(printer); - printer->Print("\n"); + format("\n"); if (options_.table_driven_serialization) { - printer->Print( + format( "const void* $classname$::InternalGetTable() const {\n" - " return ::$file_namespace$::TableStruct::serialization_table + " - "$index$;\n" + " return ::$tablename$::serialization_table + $1$;\n" "}\n" "\n", - "classname", classname_, "index", SimpleItoa(index_in_file_messages_), - "file_namespace", FileLevelNamespace(descriptor_)); + index_in_file_messages_); } if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print( - "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" - " $file_namespace$::protobuf_AssignDescriptorsOnce();\n" - " return ::" - "$file_namespace$::file_level_metadata[kIndexInFileMessages];\n" + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + " ::$proto_ns$::internal::AssignDescriptors(&::$assign_desc_table$);\n" + " return ::$file_level_metadata$[kIndexInFileMessages];\n" "}\n" - "\n", - "classname", classname_, "file_namespace", - FileLevelNamespace(descriptor_)); + "\n"); } else { - printer->Print( - "::std::string $classname$::GetTypeName() const {\n" - " return \"$type_name$\";\n" - "}\n" - "\n", - "classname", classname_, - "type_name", descriptor_->full_name()); + format( + "$string$ $classname$::GetTypeName() const {\n" + " return \"$full_name$\";\n" + "}\n" + "\n"); } } size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { + Formatter format(printer, variables_); + if (!table_driven_) { return 0; } // Field "0" is special: We use it in our switch statement of processing // types to handle the successful end tag case. - printer->Print("{0, 0, 0, ::google::protobuf::internal::kInvalidMask, 0, 0},\n"); + format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n"); int last_field_number = 1; std::vector<const FieldDescriptor*> ordered_fields = SortFieldsByNumber(descriptor_); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = ordered_fields[i]; + for (auto field : ordered_fields) { + Formatter::SaveState saver(&format); GOOGLE_CHECK_GE(field->number(), last_field_number); for (; last_field_number < field->number(); last_field_number++) { - printer->Print( - "{ 0, 0, ::google::protobuf::internal::kInvalidMask,\n" - " ::google::protobuf::internal::kInvalidMask, 0, 0 },\n"); + format( + "{ 0, 0, ::$proto_ns$::internal::kInvalidMask,\n" + " ::$proto_ns$::internal::kInvalidMask, 0, 0 },\n"); } last_field_number++; @@ -1929,30 +2076,39 @@ 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)) { + switch (EffectiveStringCType(field, options_)) { case FieldOptions::STRING: - default: { if (generator.IsInlined()) { processing_type = internal::TYPE_STRING_INLINED; break; } break; - } + case FieldOptions::CORD: + processing_type = internal::TYPE_STRING_CORD; + break; + case FieldOptions::STRING_PIECE: + processing_type = internal::TYPE_STRING_STRING_PIECE; + break; } } else if (field->type() == FieldDescriptor::TYPE_BYTES) { - switch (EffectiveStringCType(field)) { + switch (EffectiveStringCType(field, options_)) { case FieldOptions::STRING: - default: if (generator.IsInlined()) { processing_type = internal::TYPE_BYTES_INLINED; break; } break; + case FieldOptions::CORD: + processing_type = internal::TYPE_BYTES_CORD; + break; + case FieldOptions::STRING_PIECE: + processing_type = internal::TYPE_BYTES_STRING_PIECE; + break; } } processing_type |= static_cast<unsigned>( - field->is_repeated() ? internal::kRepeatedMask : 0); + field->is_repeated() ? internal::kRepeatedMask : 0); processing_type |= static_cast<unsigned>( field->containing_oneof() ? internal::kOneofMask : 0); @@ -1961,13 +2117,13 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { } const unsigned char tag_size = - WireFormat::TagSize(field->number(), field->type()); + WireFormat::TagSize(field->number(), field->type()); std::map<string, string> vars; - vars["classname"] = QualifiedClassName(descriptor_); if (field->containing_oneof() != NULL) { vars["name"] = field->containing_oneof()->name(); - vars["presence"] = SimpleItoa(field->containing_oneof()->index()); + vars["presence"] = + SimpleItoa(field->containing_oneof()->index()); } else { vars["name"] = FieldName(field); vars["presence"] = SimpleItoa(has_bit_indices_[field->index()]); @@ -1977,19 +2133,23 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { vars["ptype"] = SimpleItoa(processing_type); vars["tag_size"] = SimpleItoa(tag_size); - printer->Print(vars, - "{\n" - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" - " $classname$, $name$_),\n" - " static_cast<::google::protobuf::uint32>($presence$),\n" - " $nwtype$, $pwtype$, $ptype$, $tag_size$\n" - "},\n"); + format.AddMap(vars); + + format( + "{\n" + " $GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET(\n" + " $classtype$, $name$_),\n" + " static_cast<$uint32$>($presence$),\n" + " $nwtype$, $pwtype$, $ptype$, $tag_size$\n" + "},\n"); } return last_field_number; } size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { + Formatter format(printer, variables_); + if (!table_driven_) { return 0; } @@ -1997,74 +2157,71 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { std::vector<const FieldDescriptor*> ordered_fields = SortFieldsByNumber(descriptor_); - printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n"); + format("::$proto_ns$::internal::AuxillaryParseTableField(),\n"); int last_field_number = 1; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = ordered_fields[i]; + for (auto field : ordered_fields) { + Formatter::SaveState saver(&format); GOOGLE_CHECK_GE(field->number(), last_field_number); for (; last_field_number < field->number(); last_field_number++) { - printer->Print("::google::protobuf::internal::AuxillaryParseTableField(),\n"); + format("::$proto_ns$::internal::AuxillaryParseTableField(),\n"); } std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); + format.AddMap(vars); switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_ENUM: - vars["type"] = ClassName(field->enum_type(), true); - printer->Print( - vars, - "{::google::protobuf::internal::AuxillaryParseTableField::enum_aux{" - "$type$_IsValid}},\n"); + format( + "{::$proto_ns$::internal::AuxillaryParseTableField::enum_aux{" + "$1$_IsValid}},\n", + ClassName(field->enum_type(), true)); last_field_number++; break; case FieldDescriptor::CPPTYPE_MESSAGE: { if (field->is_map()) { - vars["classname"] = QualifiedClassName(field->message_type()); - printer->Print(vars, - "{::google::protobuf::internal::AuxillaryParseTableField::map_" - "aux{&::google::protobuf::internal::ParseMap<$classname$>}},\n"); + format( + "{::$proto_ns$::internal::AuxillaryParseTableField::map_" + "aux{&::$proto_ns$::internal::ParseMap<$1$>}},\n", + QualifiedClassName(field->message_type())); last_field_number++; break; - } else { - vars["classname"] = ClassName(field->message_type(), false); } - vars["ns"] = Namespace(field->message_type()); - vars["type"] = FieldMessageTypeName(field); - vars["file_namespace"] = - FileLevelNamespace(field->message_type()); - - printer->Print( - vars, - "{::google::protobuf::internal::AuxillaryParseTableField::message_aux{\n" - " &$ns$::_$classname$_default_instance_}},\n"); + format.Set("field_classname", ClassName(field->message_type(), false)); + format.Set("ns", Namespace(field->message_type())); + + format( + "{::$proto_ns$::internal::AuxillaryParseTableField::message_aux{\n" + " &$ns$::_$field_classname$_default_instance_}},\n"); last_field_number++; break; } - case FieldDescriptor::CPPTYPE_STRING: - switch (EffectiveStringCType(field)) { + case FieldDescriptor::CPPTYPE_STRING: { + string default_val; + switch (EffectiveStringCType(field, options_)) { case FieldOptions::STRING: - vars["default"] = - field->default_value_string().empty() - ? "&::google::protobuf::internal::fixed_address_empty_string" - : "&" + Namespace(field) + " ::" + classname_ + - "::" + MakeDefaultName(field); + default_val = field->default_value_string().empty() + ? "&::" + variables_["proto_ns"] + + "::internal::fixed_address_empty_string" + : "&" + Namespace(field) + " ::" + classname_ + + "::" + MakeDefaultName(field); break; case FieldOptions::CORD: case FieldOptions::STRING_PIECE: - vars["default"] = + default_val = "\"" + CEscape(field->default_value_string()) + "\""; break; } - vars["full_name"] = field->full_name(); - printer->Print(vars, - "{::google::protobuf::internal::AuxillaryParseTableField::string_aux{\n" - " $default$,\n" - " \"$full_name$\"\n" - "}},\n"); + format( + "{::$proto_ns$::internal::AuxillaryParseTableField::string_aux{\n" + " $1$,\n" + " \"$2$\"\n" + "}},\n", + default_val, field->full_name()); last_field_number++; break; + } default: break; } @@ -2075,171 +2232,163 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( io::Printer* printer) { - std::map<string, string> variables; - string full_classname = QualifiedClassName(descriptor_); - variables["classname"] = full_classname; + Formatter format(printer, variables_); if (HasFieldPresence(descriptor_->file()) || IsMapEntryMessage(descriptor_)) { - printer->Print( - variables, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " "_has_bits_),\n"); } else { - printer->Print("~0u, // no _has_bits_\n"); + format("~0u, // no _has_bits_\n"); } - printer->Print(variables, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " - "_internal_metadata_),\n"); + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " + "_internal_metadata_),\n"); if (descriptor_->extension_range_count() > 0) { - printer->Print( - variables, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, " "_extensions_),\n"); } else { - printer->Print("~0u, // no _extensions_\n"); + format("~0u, // no _extensions_\n"); } if (descriptor_->oneof_decl_count() > 0) { - printer->Print(variables, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _oneof_case_[0]),\n"); + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classtype$, _oneof_case_[0]),\n"); } else { - printer->Print("~0u, // no _oneof_case_\n"); + format("~0u, // no _oneof_case_\n"); } if (num_weak_fields_ > 0) { - printer->Print(variables, - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$," - " _weak_field_map_),\n"); + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$," + " _weak_field_map_),\n"); } else { - printer->Print("~0u, // no _weak_field_map_\n"); + format("~0u, // no _weak_field_map_\n"); } const int kNumGenericOffsets = 5; // the number of fixed offsets above - const size_t offsets = kNumGenericOffsets + - descriptor_->field_count() + + const size_t offsets = kNumGenericOffsets + descriptor_->field_count() + descriptor_->oneof_decl_count(); size_t entries = offsets; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + for (auto field : FieldRange(descriptor_)) { if (field->containing_oneof() || field->options().weak()) { - printer->Print("offsetof($classname$DefaultTypeInternal, $name$_)", - "classname", full_classname, "name", FieldName(field)); + format("offsetof($classtype$DefaultTypeInternal, $1$_)", + FieldName(field)); } else { - printer->Print( - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_)", - "classname", full_classname, "name", FieldName(field)); + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, $1$_)", + FieldName(field)); } uint32 tag = field_generators_.get(field).CalculateFieldTag(); if (tag != 0) { - printer->Print(" | $tag$", "tag", SimpleItoa(tag)); + format(" | $1$", tag); } - printer->Print(",\n"); + format(",\n"); } - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - const OneofDescriptor* oneof = descriptor_->oneof_decl(i); - printer->Print( - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_),\n", - "classname", full_classname, "name", oneof->name()); + for (auto oneof : OneOfRange(descriptor_)) { + format( + "$GOOGLE_PROTOBUF$_GENERATED_MESSAGE_FIELD_OFFSET($classtype$, $1$_),\n", + oneof->name()); } if (IsMapEntryMessage(descriptor_)) { entries += 2; - printer->Print( + format( "0,\n" "1,\n"); } else if (HasFieldPresence(descriptor_->file())) { entries += has_bit_indices_.size(); for (int i = 0; i < has_bit_indices_.size(); i++) { - const string index = has_bit_indices_[i] >= 0 ? - SimpleItoa(has_bit_indices_[i]) : "~0u"; - printer->Print("$index$,\n", "index", index); + const string index = has_bit_indices_[i] >= 0 + ? SimpleItoa(has_bit_indices_[i]) + : "~0u"; + format("$1$,\n", index); } } return std::make_pair(entries, offsets); } -void MessageGenerator:: -GenerateSharedConstructorCode(io::Printer* printer) { - printer->Print( - "void $classname$::SharedCtor() {\n", - "classname", classname_); - printer->Indent(); +void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { + Formatter format(printer, variables_); + + format("void $classname$::SharedCtor() {\n"); + if (scc_analyzer_ + ->GetSCCAnalysis(scc_analyzer_->GetSCC(descriptor_)) + .constructor_requires_initialization) { + format( + " ::$proto_ns$::internal::InitSCC(\n" + " &scc_info_$scc_name$.base);\n"); + } + + format.Indent(); std::vector<bool> processed(optimized_order_.size(), false); GenerateConstructorBody(printer, processed, false); - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "clear_has_$oneof_name$();\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); + for (auto oneof : OneOfRange(descriptor_)) { + format("clear_has_$1$();\n", oneof->name()); } - printer->Outdent(); - printer->Print("}\n\n"); + format.Outdent(); + format("}\n\n"); } -void MessageGenerator:: -GenerateSharedDestructorCode(io::Printer* printer) { - printer->Print( - "void $classname$::SharedDtor() {\n", - "classname", classname_); - printer->Indent(); +void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { + Formatter format(printer, variables_); + + format("void $classname$::SharedDtor() {\n"); + format.Indent(); if (SupportsArenas(descriptor_)) { - printer->Print( - "GOOGLE_DCHECK(GetArenaNoVirtual() == NULL);\n"); + format("$DCHK$(GetArenaNoVirtual() == NULL);\n"); } // Write the destructors for each field except oneof members. // optimized_order_ does not contain oneof fields. - for (int i = 0; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; + for (auto field : optimized_order_) { field_generators_.get(field).GenerateDestructorCode(printer); } // Generate code to destruct oneofs. Clearing should do the work. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "if (has_$oneof_name$()) {\n" - " clear_$oneof_name$();\n" + for (auto oneof : OneOfRange(descriptor_)) { + format( + "if (has_$1$()) {\n" + " clear_$1$();\n" "}\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); + oneof->name()); } if (num_weak_fields_) { - printer->Print("_weak_field_map_.ClearAll();\n"); + format("_weak_field_map_.ClearAll();\n"); } - printer->Outdent(); - printer->Print( - "}\n" - "\n"); + format.Outdent(); + format( + "}\n" + "\n"); } -void MessageGenerator:: -GenerateArenaDestructorCode(io::Printer* printer) { +void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { + Formatter format(printer, variables_); + // Generate the ArenaDtor() method. Track whether any fields actually produced // code that needs to be called. - printer->Print( - "void $classname$::ArenaDtor(void* object) {\n", - "classname", classname_); - printer->Indent(); + format("void $classname$::ArenaDtor(void* object) {\n"); + format.Indent(); // This code is placed inside a static method, rather than an ordinary one, // since that simplifies Arena's destructor list (ordinary function pointers // rather than member function pointers). _this is the object being // destructed. - printer->Print( + format( "$classname$* _this = reinterpret_cast< $classname$* >(object);\n" // avoid an "unused variable" warning in case no fields have dtor code. - "(void)_this;\n", - "classname", classname_); + "(void)_this;\n"); bool need_registration = false; // Process non-oneof fields first. - for (int i = 0; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (field_generators_.get(field) - .GenerateArenaDestructorCode(printer)) { + for (auto field : optimized_order_) { + if (field_generators_.get(field).GenerateArenaDestructorCode(printer)) { need_registration = true; } } @@ -2248,13 +2397,9 @@ GenerateArenaDestructorCode(io::Printer* printer) { // // Note: As of 10/5/2016, GenerateArenaDestructorCode does not emit anything // and returns false for oneof fields. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - const OneofDescriptor* oneof = descriptor_->oneof_decl(i); - - for (int j = 0; j < oneof->field_count(); j++) { - const FieldDescriptor* field = oneof->field(j); - if (field_generators_.get(field) - .GenerateArenaDestructorCode(printer)) { + for (auto oneof : OneOfRange(descriptor_)) { + for (auto field : FieldRange(oneof)) { + if (field_generators_.get(field).GenerateArenaDestructorCode(printer)) { need_registration = true; } } @@ -2262,42 +2407,40 @@ GenerateArenaDestructorCode(io::Printer* printer) { if (num_weak_fields_) { // _this is the object being destructed (we are inside a static method // here). - printer->Print("_this->_weak_field_map_.ClearAll();\n"); + format("_this->_weak_field_map_.ClearAll();\n"); need_registration = true; } - printer->Outdent(); - printer->Print( - "}\n"); + format.Outdent(); + format("}\n"); if (need_registration) { - printer->Print( - "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n" + format( + "inline void $classname$::RegisterArenaDtor(::$proto_ns$::Arena* " + "arena) {\n" " if (arena != NULL) {\n" " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" " }\n" - "}\n", - "classname", classname_); + "}\n"); } else { - printer->Print( - "void $classname$::RegisterArenaDtor(::google::protobuf::Arena*) {\n" - "}\n", - "classname", classname_); + format( + "void $classname$::RegisterArenaDtor(::$proto_ns$::Arena*) {\n" + "}\n"); } } void MessageGenerator::GenerateConstructorBody(io::Printer* printer, std::vector<bool> processed, bool copy_constructor) const { + Formatter format(printer, variables_); const FieldDescriptor* last_start = NULL; // 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 // a message and that most of the eligible fields appear together. - typedef hash_map<const FieldDescriptor*, size_t> RunMap; + typedef std::unordered_map<const FieldDescriptor*, size_t> RunMap; RunMap runs; - for (int i = 0; i < optimized_order_.size(); ++i) { - const FieldDescriptor* field = optimized_order_[i]; + for (auto field : optimized_order_) { if ((copy_constructor && IsPOD(field)) || (!copy_constructor && CanConstructByZeroing(field, options_))) { if (last_start == NULL) { @@ -2340,9 +2483,10 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, const string last_field_name = FieldName(optimized_order_[i + run_length - 1]); - printer->Print(pod_template.c_str(), - "first", first_field_name, - "last", last_field_name); + format.Set("first", first_field_name); + format.Set("last", last_field_name); + + format(pod_template.c_str()); i += run_length - 1; // ++i at the top of the loop. @@ -2356,8 +2500,9 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, } } -void MessageGenerator:: -GenerateStructors(io::Printer* printer) { +void MessageGenerator::GenerateStructors(io::Printer* printer) { + Formatter format(printer, variables_); + string superclass; superclass = SuperClassName(descriptor_, options_); string initializer_with_arena = superclass + "()"; @@ -2369,13 +2514,15 @@ GenerateStructors(io::Printer* printer) { initializer_with_arena += ",\n _internal_metadata_(arena)"; // Initialize member variables with arena constructor. - for (int i = 0; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - + for (auto field : optimized_order_) { bool has_arena_constructor = field->is_repeated(); + if (field->containing_oneof() == NULL && + (IsLazy(field, options_) || IsStringPiece(field, options_))) { + has_arena_constructor = true; + } if (has_arena_constructor) { - initializer_with_arena += string(",\n ") + - FieldName(field) + string("_(arena)"); + initializer_with_arena += + string(",\n ") + FieldName(field) + string("_(arena)"); } } @@ -2394,33 +2541,23 @@ GenerateStructors(io::Printer* printer) { initializer_null += ", _weak_field_map_(nullptr)"; } - printer->Print( + format( "$classname$::$classname$()\n" - " : $initializer$ {\n" - " ::google::protobuf::internal::InitSCC(\n" - " &$file_namespace$::scc_info_$scc_name$.base);\n" + " : $1$ {\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", - "classname", classname_, "full_name", descriptor_->full_name(), - "scc_name", scc_name_, "initializer", initializer_null, "file_namespace", - FileLevelNamespace(descriptor_)); + initializer_null); if (SupportsArenas(descriptor_)) { - printer->Print( - "$classname$::$classname$(::google::protobuf::Arena* arena)\n" - " : $initializer$ {\n" - " " - "::google::protobuf::internal::InitSCC(&$file_namespace$::scc_info_$scc_name$." - "base);\n" + format( + "$classname$::$classname$(::$proto_ns$::Arena* arena)\n" + " : $1$ {\n" " SharedCtor();\n" " RegisterArenaDtor(arena);\n" " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" "}\n", - "initializer", initializer_with_arena, "classname", classname_, - "superclass", superclass, "full_name", descriptor_->full_name(), - "scc_name", scc_name_, "file_namespace", - FileLevelNamespace(descriptor_)); + initializer_with_arena); } // Generate the copy constructor. @@ -2429,117 +2566,98 @@ GenerateStructors(io::Printer* printer) { // one-liner copy constructor that delegates to MergeFrom. This saves some // code size and also cuts down on the complexity of implicit weak fields. // We might eventually want to do this for all lite protos. - printer->Print( - "$classname$::$classname$(const $classname$& from)\n" - " : $classname$() {\n" - " MergeFrom(from);\n" - "}\n", - "classname", classname_); + format( + "$classname$::$classname$(const $classname$& from)\n" + " : $classname$() {\n" + " MergeFrom(from);\n" + "}\n"); } else { - printer->Print( - "$classname$::$classname$(const $classname$& from)\n" - " : $superclass$()", - "classname", classname_, - "superclass", superclass, - "full_name", descriptor_->full_name()); - printer->Indent(); - printer->Indent(); - printer->Indent(); - - printer->Print( - ",\n_internal_metadata_(NULL)"); + format( + "$classname$::$classname$(const $classname$& from)\n" + " : $superclass$()"); + format.Indent(); + format.Indent(); + format.Indent(); + format(",\n_internal_metadata_(NULL)"); if (HasFieldPresence(descriptor_->file())) { - printer->Print(",\n_has_bits_(from._has_bits_)"); + if (!IsProto2MessageSet(descriptor_, options_)) { + format(",\n_has_bits_(from._has_bits_)"); + } } std::vector<bool> processed(optimized_order_.size(), false); - for (int i = 0; i < optimized_order_.size(); ++i) { - const FieldDescriptor* field = optimized_order_[i]; - - if (!(field->is_repeated() && !(field->is_map())) - ) { + for (int i = 0; i < optimized_order_.size(); i++) { + auto field = optimized_order_[i]; + if (!(field->is_repeated() && !(field->is_map())) && + !IsCord(field, options_)) { continue; } processed[i] = true; - printer->Print(",\n$name$_(from.$name$_)", - "name", FieldName(field)); + format(",\n$1$_(from.$1$_)", FieldName(field)); } if (IsAnyMessage(descriptor_)) { - printer->Print(",\n_any_metadata_(&type_url_, &value_)"); + format(",\n_any_metadata_(&type_url_, &value_)"); } if (num_weak_fields_ > 0) { - printer->Print(",\n_weak_field_map_(from._weak_field_map_)"); + format(",\n_weak_field_map_(from._weak_field_map_)"); } - printer->Outdent(); - printer->Outdent(); - printer->Print(" {\n"); + format.Outdent(); + format.Outdent(); + format(" {\n"); - printer->Print( - "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"); + format("_internal_metadata_.MergeFrom(from._internal_metadata_);\n"); if (descriptor_->extension_range_count() > 0) { - printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); + format("_extensions_.MergeFrom(from._extensions_);\n"); } GenerateConstructorBody(printer, processed, true); // Copy oneof fields. Oneof field requires oneof case check. - for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { - printer->Print( - "clear_has_$oneofname$();\n" - "switch (from.$oneofname$_case()) {\n", - "oneofname", descriptor_->oneof_decl(i)->name()); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); - printer->Print( - "case k$field_name$: {\n", - "field_name", UnderscoresToCamelCase(field->name(), true)); - printer->Indent(); + for (auto oneof : OneOfRange(descriptor_)) { + format( + "clear_has_$1$();\n" + "switch (from.$1$_case()) {\n", + oneof->name()); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); field_generators_.get(field).GenerateMergingCode(printer); - printer->Print( - "break;\n"); - printer->Outdent(); - printer->Print( - "}\n"); + format("break;\n"); + format.Outdent(); + format("}\n"); } - printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" + format( + "case $1$_NOT_SET: {\n" " break;\n" "}\n", - "oneof_index", - SimpleItoa(descriptor_->oneof_decl(i)->index()), - "cap_oneof_name", - ToUpper(descriptor_->oneof_decl(i)->name())); - printer->Outdent(); - printer->Print( - "}\n"); + ToUpper(oneof->name())); + format.Outdent(); + format("}\n"); } - printer->Outdent(); - printer->Print( - " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" - "}\n" - "\n", - "full_name", descriptor_->full_name()); + format.Outdent(); + format( + " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" + "}\n" + "\n"); } // Generate the shared constructor code. GenerateSharedConstructorCode(printer); // Generate the destructor. - printer->Print( - "$classname$::~$classname$() {\n" - " // @@protoc_insertion_point(destructor:$full_name$)\n" - " SharedDtor();\n" - "}\n" - "\n", - "classname", classname_, - "full_name", descriptor_->full_name()); + format( + "$classname$::~$classname$() {\n" + " // @@protoc_insertion_point(destructor:$full_name$)\n" + " SharedDtor();\n" + "}\n" + "\n"); // Generate the shared destructor code. GenerateSharedDestructorCode(printer); @@ -2550,90 +2668,60 @@ GenerateStructors(io::Printer* printer) { } // Generate SetCachedSize. - printer->Print( + format( "void $classname$::SetCachedSize(int size) const {\n" " _cached_size_.Set(size);\n" - "}\n", - "classname", classname_); - - // Only generate this member if it's not disabled. - if (HasDescriptorMethods(descriptor_->file(), options_) && - !descriptor_->options().no_standard_descriptor_accessor()) { - printer->Print( - "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" - " ::$file_namespace$::protobuf_AssignDescriptorsOnce();\n" - " return ::" - "$file_namespace$::file_level_metadata[kIndexInFileMessages]." - "descriptor;\n" - "}\n" - "\n", - "classname", classname_, "file_namespace", - FileLevelNamespace(descriptor_)); - } + "}\n"); - printer->Print( + format( "const $classname$& $classname$::default_instance() {\n" " " - "::google::protobuf::internal::InitSCC(&$file_namespace$::scc_info_$scc_name$.base)" + "::$proto_ns$::internal::InitSCC(&::scc_info_$scc_name$.base)" ";\n" " return *internal_default_instance();\n" - "}\n\n", - "classname", classname_, "scc_name", scc_name_, "file_namespace", - FileLevelNamespace(descriptor_)); + "}\n\n"); } void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { - printer->Print( + Formatter format(printer, variables_); + format( "template<> " - "GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE " - "$classname$* Arena::CreateMaybeMessage< $classname$ >(Arena* arena) {\n" - " return Arena::$create_func$Internal< $classname$ >(arena);\n" + "$GOOGLE_PROTOBUF$_ATTRIBUTE_NOINLINE " + "$classtype$* Arena::CreateMaybeMessage< $classtype$ >(Arena* arena) {\n" + " return Arena::$1$Internal< $classtype$ >(arena);\n" "}\n", - "classname", QualifiedClassName(descriptor_), - "create_func", MessageCreateFunction(descriptor_)); -} - -// Return the number of bits set in n, a non-negative integer. -static int popcnt(uint32 n) { - int result = 0; - while (n != 0) { - result += (n & 1); - n = n / 2; - } - return result; + MessageCreateFunction(descriptor_)); } bool MessageGenerator::MaybeGenerateOptionalFieldCondition( io::Printer* printer, const FieldDescriptor* field, int expected_has_bits_index) { + Formatter format(printer, variables_); int has_bit_index = has_bit_indices_[field->index()]; if (!field->options().weak() && expected_has_bits_index == has_bit_index / 32) { const string mask = StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); - printer->Print( - "if (cached_has_bits & 0x$mask$u) {\n", - "mask", mask); + format("if (cached_has_bits & 0x$1$u) {\n", mask); return true; } return false; } -void MessageGenerator:: -GenerateClear(io::Printer* printer) { +void MessageGenerator::GenerateClear(io::Printer* printer) { + Formatter format(printer, variables_); // Performance tuning parameters const int kMaxUnconditionalPrimitiveBytesClear = 4; - printer->Print( + format( "void $classname$::Clear() {\n" - "// @@protoc_insertion_point(message_clear_start:$full_name$)\n", - "classname", classname_, "full_name", descriptor_->full_name()); - printer->Indent(); + "// @@protoc_insertion_point(message_clear_start:$full_name$)\n"); + format.Indent(); - printer->Print( + format( // TODO(jwb): It would be better to avoid emitting this if it is not used, // rather than emitting a workaround for the resulting warning. - "::google::protobuf::uint32 cached_has_bits = 0;\n" + "$uint32$ cached_has_bits = 0;\n" "// Prevent compiler warnings about cached_has_bits being unused\n" "(void) cached_has_bits;\n\n"); @@ -2641,7 +2729,7 @@ GenerateClear(io::Printer* printer) { // Step 1: Extensions if (descriptor_->extension_range_count() > 0) { - printer->Print("_extensions_.Clear();\n"); + format("_extensions_.Clear();\n"); } int unconditional_budget = kMaxUnconditionalPrimitiveBytesClear; @@ -2687,6 +2775,8 @@ GenerateClear(io::Printer* printer) { } } + ColdChunkSkipper cold_skipper(options_, chunks, has_bit_indices_, kColdRatio, + HasFieldPresence(descriptor_->file())); for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; GOOGLE_CHECK(!chunk.empty()); @@ -2703,6 +2793,8 @@ GenerateClear(io::Printer* printer) { continue; } + cold_skipper.OnStartChunk(chunk_index, cached_has_bit_index, "", printer); + // Step 3: Non-repeated fields that can be cleared by memset-to-0, then // non-repeated, non-zero initializable fields. int last_chunk = HasFieldPresence(descriptor_->file()) @@ -2738,12 +2830,11 @@ GenerateClear(io::Printer* printer) { if (cached_has_bit_index != last_chunk / 4) { cached_has_bit_index = last_chunk / 4; - printer->Print("cached_has_bits = _has_bits_[$idx$];\n", "idx", - SimpleItoa(cached_has_bit_index)); + format("cached_has_bits = _has_bits_[$1$];\n", cached_has_bit_index); } - printer->Print("if (cached_has_bits & $mask$u) {\n", "mask", - SimpleItoa(last_chunk_mask)); - printer->Indent(); + format("if (cached_has_bits & 0x$1$u) {\n", + StrCat(strings::Hex(last_chunk_mask, strings::ZERO_PAD_8))); + format.Indent(); } if (memset_run_start != -1) { @@ -2756,11 +2847,11 @@ GenerateClear(io::Printer* printer) { const string first_field_name = FieldName(chunk[memset_run_start]); const string last_field_name = FieldName(chunk[memset_run_end]); - printer->Print( - "::memset(&$first$_, 0, static_cast<size_t>(\n" - " reinterpret_cast<char*>(&$last$_) -\n" - " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n", - "first", first_field_name, "last", last_field_name); + format( + "::memset(&$1$_, 0, static_cast<size_t>(\n" + " reinterpret_cast<char*>(&$2$_) -\n" + " reinterpret_cast<char*>(&$1$_)) + sizeof($2$_));\n", + first_field_name, last_field_name); } // Advance last_chunk_start to skip over the fields we zeroed/memset. @@ -2770,7 +2861,6 @@ GenerateClear(io::Printer* printer) { // Go back and emit clears for each of the fields we processed. for (int j = last_chunk_start; j < chunk.size(); j++) { const FieldDescriptor* field = chunk[j]; - const string fieldname = FieldName(field); const FieldGenerator& generator = field_generators_.get(field); // It's faster to just overwrite primitive types, but we should only @@ -2785,121 +2875,101 @@ GenerateClear(io::Printer* printer) { if (should_check_bit && // If no field presence, then always clear strings/messages as well. HasFieldPresence(descriptor_->file())) { - if (!field->options().weak() && - cached_has_bit_index != (has_bit_indices_[field->index()] / 32)) { - cached_has_bit_index = (has_bit_indices_[field->index()] / 32); - printer->Print("cached_has_bits = _has_bits_[$new_index$];\n", - "new_index", SimpleItoa(cached_has_bit_index)); - } - if (!MaybeGenerateOptionalFieldCondition(printer, field, - cached_has_bit_index)) { - printer->Print("if (has_$name$()) {\n", "name", fieldname); - } - printer->Indent(); + PrintPresenceCheck(format, field, has_bit_indices_, printer, + &cached_has_bit_index); have_enclosing_if = true; } generator.GenerateMessageClearingCode(printer); if (have_enclosing_if) { - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } } if (have_outer_if) { - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); + } + + if (cold_skipper.OnEndChunk(chunk_index, printer)) { + // Reset here as it may have been updated in just closed if statement. + cached_has_bit_index = -1; } } // Step 4: Unions. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "clear_$oneof_name$();\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); + for (auto oneof : OneOfRange(descriptor_)) { + format("clear_$1$();\n", oneof->name()); } if (num_weak_fields_) { - printer->Print("_weak_field_map_.ClearAll();\n"); + format("_weak_field_map_.ClearAll();\n"); } if (HasFieldPresence(descriptor_->file())) { // Step 5: Everything else. - printer->Print("_has_bits_.Clear();\n"); + format("_has_bits_.Clear();\n"); } - printer->Print("_internal_metadata_.Clear();\n"); + format("_internal_metadata_.Clear();\n"); - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } -void MessageGenerator:: -GenerateOneofClear(io::Printer* printer) { +void MessageGenerator::GenerateOneofClear(io::Printer* printer) { // Generated function clears the active field and union case (e.g. foo_case_). for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - std::map<string, string> oneof_vars; - oneof_vars["classname"] = classname_; - oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); - oneof_vars["full_name"] = descriptor_->full_name(); - string message_class; - - printer->Print(oneof_vars, - "void $classname$::clear_$oneofname$() {\n" - "// @@protoc_insertion_point(one_of_clear_start:" - "$full_name$)\n"); - printer->Indent(); - printer->Print(oneof_vars, - "switch ($oneofname$_case()) {\n"); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); - printer->Print( - "case k$field_name$: {\n", - "field_name", UnderscoresToCamelCase(field->name(), true)); - printer->Indent(); + auto oneof = descriptor_->oneof_decl(i); + Formatter format(printer, variables_); + format.Set("oneofname", oneof->name()); + + format( + "void $classname$::clear_$oneofname$() {\n" + "// @@protoc_insertion_point(one_of_clear_start:$full_name$)\n"); + format.Indent(); + format("switch ($oneofname$_case()) {\n"); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); // We clear only allocated objects in oneofs if (!IsStringOrMessage(field)) { - printer->Print( - "// No need to clear\n"); + format("// No need to clear\n"); } else { field_generators_.get(field).GenerateClearingCode(printer); } - printer->Print( - "break;\n"); - printer->Outdent(); - printer->Print( - "}\n"); + format("break;\n"); + format.Outdent(); + format("}\n"); } - printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" + format( + "case $1$_NOT_SET: {\n" " break;\n" "}\n", - "cap_oneof_name", - ToUpper(descriptor_->oneof_decl(i)->name())); - printer->Outdent(); - printer->Print( + ToUpper(oneof->name())); + format.Outdent(); + format( "}\n" - "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n", - "oneof_index", SimpleItoa(i), - "cap_oneof_name", - ToUpper(descriptor_->oneof_decl(i)->name())); - printer->Outdent(); - printer->Print( + "_oneof_case_[$1$] = $2$_NOT_SET;\n", + i, ToUpper(oneof->name())); + format.Outdent(); + format( "}\n" "\n"); } } -void MessageGenerator:: -GenerateSwap(io::Printer* printer) { +void MessageGenerator::GenerateSwap(io::Printer* printer) { + Formatter format(printer, variables_); if (SupportsArenas(descriptor_)) { // Generate the Swap member function. This is a lightweight wrapper around // UnsafeArenaSwap() / MergeFrom() with temporaries, depending on the memory // ownership situation: swapping across arenas or between an arena and a // heap requires copying. - printer->Print( + format( "void $classname$::Swap($classname$* other) {\n" " if (other == this) return;\n" " if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {\n" @@ -2916,26 +2986,35 @@ GenerateSwap(io::Printer* printer) { "}\n" "void $classname$::UnsafeArenaSwap($classname$* other) {\n" " if (other == this) return;\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());\n" + " $DCHK$(GetArenaNoVirtual() == other->GetArenaNoVirtual());\n" " InternalSwap(other);\n" - "}\n", - "classname", classname_); + "}\n"); } else { - printer->Print( + format( "void $classname$::Swap($classname$* other) {\n" " if (other == this) return;\n" " InternalSwap(other);\n" - "}\n", - "classname", classname_); + "}\n"); } // Generate the UnsafeArenaSwap member function. - printer->Print("void $classname$::InternalSwap($classname$* other) {\n", - "classname", classname_); - printer->Indent(); - printer->Print("using std::swap;\n"); + format("void $classname$::InternalSwap($classname$* other) {\n"); + format.Indent(); + format("using std::swap;\n"); if (HasGeneratedMethods(descriptor_->file(), options_)) { + if (descriptor_->extension_range_count() > 0) { + format("_extensions_.Swap(&other->_extensions_);\n"); + } + + format("_internal_metadata_.Swap(&other->_internal_metadata_);\n"); + + if (HasFieldPresence(descriptor_->file())) { + for (int i = 0; i < HasBitsSize() / 4; ++i) { + format("swap(_has_bits_[$1$], other->_has_bits_[$1$]);\n", i); + } + } + for (int i = 0; i < optimized_order_.size(); i++) { // optimized_order_ does not contain oneof fields, but the field // generators for these fields do not emit swapping code on their own. @@ -2943,163 +3022,125 @@ GenerateSwap(io::Printer* printer) { field_generators_.get(field).GenerateSwappingCode(printer); } - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "swap($oneof_name$_, other->$oneof_name$_);\n" - "swap(_oneof_case_[$i$], other->_oneof_case_[$i$]);\n", - "oneof_name", descriptor_->oneof_decl(i)->name(), - "i", SimpleItoa(i)); + for (auto oneof : OneOfRange(descriptor_)) { + format("swap($1$_, other->$1$_);\n", oneof->name()); } - if (HasFieldPresence(descriptor_->file())) { - for (int i = 0; i < HasBitsSize() / 4; ++i) { - printer->Print("swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", - "i", SimpleItoa(i)); - } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + format( + "swap(_oneof_case_[$1$], other->_oneof_case_[$1$]);\n", i); } - printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - - if (descriptor_->extension_range_count() > 0) { - printer->Print("_extensions_.Swap(&other->_extensions_);\n"); - } if (num_weak_fields_) { - printer->Print( - "_weak_field_map_.UnsafeArenaSwap(&other->_weak_field_map_);\n"); + format("_weak_field_map_.UnsafeArenaSwap(&other->_weak_field_map_);\n"); } } else { - printer->Print("GetReflection()->Swap(this, other);"); + format("GetReflection()->Swap(this, other);"); } - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } -void MessageGenerator:: -GenerateMergeFrom(io::Printer* printer) { +void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { + Formatter format(printer, variables_); if (HasDescriptorMethods(descriptor_->file(), options_)) { // Generate the generalized MergeFrom (aka that which takes in the Message // base class as a parameter). - printer->Print( - "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n" + format( + "void $classname$::MergeFrom(const ::$proto_ns$::Message& from) {\n" "// @@protoc_insertion_point(generalized_merge_from_start:" "$full_name$)\n" - " GOOGLE_DCHECK_NE(&from, this);\n", - "classname", classname_, "full_name", descriptor_->full_name()); - printer->Indent(); + " $DCHK$_NE(&from, this);\n"); + format.Indent(); // Cast the message to the proper type. If we find that the message is // *not* of the proper type, we can still call Merge via the reflection // system, as the GOOGLE_CHECK above ensured that we have the same descriptor // for each message. - printer->Print( - "const $classname$* source =\n" - " ::google::protobuf::internal::DynamicCastToGenerated<const $classname$>(\n" - " &from);\n" - "if (source == NULL) {\n" - "// @@protoc_insertion_point(generalized_merge_from_cast_fail:" - "$full_name$)\n" - " ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n" - "} else {\n" - "// @@protoc_insertion_point(generalized_merge_from_cast_success:" - "$full_name$)\n" - " MergeFrom(*source);\n" - "}\n", - "classname", classname_, "full_name", descriptor_->full_name()); + format( + "const $classname$* source =\n" + " ::$proto_ns$::DynamicCastToGenerated<$classname$>(\n" + " &from);\n" + "if (source == NULL) {\n" + "// @@protoc_insertion_point(generalized_merge_from_cast_fail:" + "$full_name$)\n" + " ::$proto_ns$::internal::ReflectionOps::Merge(from, this);\n" + "} else {\n" + "// @@protoc_insertion_point(generalized_merge_from_cast_success:" + "$full_name$)\n" + " MergeFrom(*source);\n" + "}\n"); - printer->Outdent(); - printer->Print("}\n\n"); + format.Outdent(); + format("}\n\n"); } else { // Generate CheckTypeAndMergeFrom(). - printer->Print( - "void $classname$::CheckTypeAndMergeFrom(\n" - " const ::google::protobuf::MessageLite& from) {\n" - " MergeFrom(*::google::protobuf::down_cast<const $classname$*>(&from));\n" - "}\n" - "\n", - "classname", classname_); + format( + "void $classname$::CheckTypeAndMergeFrom(\n" + " const ::$proto_ns$::MessageLite& from) {\n" + " MergeFrom(*::google::protobuf::down_cast<const $classname$*>(&from));\n" + "}\n" + "\n"); } // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. - printer->Print( + format( "void $classname$::MergeFrom(const $classname$& from) {\n" "// @@protoc_insertion_point(class_specific_merge_from_start:" "$full_name$)\n" - " GOOGLE_DCHECK_NE(&from, this);\n", - "classname", classname_, "full_name", descriptor_->full_name()); - printer->Indent(); + " $DCHK$_NE(&from, this);\n"); + format.Indent(); if (descriptor_->extension_range_count() > 0) { - printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); + format("_extensions_.MergeFrom(from._extensions_);\n"); } - printer->Print( - "_internal_metadata_.MergeFrom(from._internal_metadata_);\n" - "::google::protobuf::uint32 cached_has_bits = 0;\n" - "(void) cached_has_bits;\n\n"); + format( + "_internal_metadata_.MergeFrom(from._internal_metadata_);\n" + "$uint32$ cached_has_bits = 0;\n" + "(void) cached_has_bits;\n\n"); - // cached_has_bit_index maintains that: - // cached_has_bits = from._has_bits_[cached_has_bit_index] - // for cached_has_bit_index >= 0 - int cached_has_bit_index = -1; + if (HasFieldPresence(descriptor_->file())) { + std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields( + optimized_order_, MatchRepeatedAndHasByte(&has_bit_indices_, true)); - int last_i = -1; - for (int i = 0; i < optimized_order_.size(); ) { - // Detect infinite loops. - GOOGLE_CHECK_NE(i, last_i); - last_i = i; + ColdChunkSkipper cold_skipper(options_, chunks, has_bit_indices_, + kColdRatio, true); - // Merge Repeated fields. These fields do not require a - // check as we can simply iterate over them. - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (!field->is_repeated()) { - break; - } + // cached_has_bit_index maintains that: + // cached_has_bits = from._has_bits_[cached_has_bit_index] + // for cached_has_bit_index >= 0 + int cached_has_bit_index = -1; - const FieldGenerator& generator = field_generators_.get(field); - generator.GenerateMergingCode(printer); - } + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; + GOOGLE_CHECK(!chunk.empty()); - // Merge Optional and Required fields (after a _has_bit_ check). - int last_chunk = -1; - int last_chunk_start = -1; - int last_chunk_end = -1; - uint32 last_chunk_mask = 0; - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (field->is_repeated()) { - break; - } + // Merge Repeated fields. These fields do not require a + // check as we can simply iterate over them. + if (chunk.front()->is_repeated()) { + for (int i = 0; i < chunk.size(); i++) { + const FieldDescriptor* field = chunk[i]; - // "index" defines where in the _has_bits_ the field appears. - // "i" is our loop counter within optimized_order_. - int index = HasFieldPresence(descriptor_->file()) ? - has_bit_indices_[field->index()] : 0; - int chunk = index / 8; - - if (last_chunk == -1) { - last_chunk = chunk; - last_chunk_start = i; - } else if (chunk != last_chunk) { - // Emit the fields for this chunk so far. - break; + const FieldGenerator& generator = field_generators_.get(field); + generator.GenerateMergingCode(printer); + } + continue; } - last_chunk_end = i; - last_chunk_mask |= static_cast<uint32>(1) << (index % 32); - } - - if (last_chunk != -1) { - GOOGLE_DCHECK_NE(-1, last_chunk_start); - GOOGLE_DCHECK_NE(-1, last_chunk_end); - GOOGLE_DCHECK_NE(0, last_chunk_mask); + // Merge Optional and Required fields (after a _has_bit_ check). + cold_skipper.OnStartChunk(chunk_index, cached_has_bit_index, "from.", + printer); - const int count = popcnt(last_chunk_mask); - const bool have_outer_if = HasFieldPresence(descriptor_->file()) && - (last_chunk_start != last_chunk_end); + int last_chunk = has_bit_indices_[chunk.front()->index()] / 8; + GOOGLE_DCHECK_NE(-1, last_chunk); + const bool have_outer_if = chunk.size() > 1; if (have_outer_if) { + uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_); + const int count = popcnt(last_chunk_mask); + // Check (up to) 8 has_bits at a time if we have more than one field in // this chunk. Due to field layout ordering, we may check // _has_bits_[last_chunk * 8 / 32] multiple times. @@ -3107,50 +3148,32 @@ GenerateMergeFrom(io::Printer* printer) { GOOGLE_DCHECK_GE(8, count); if (cached_has_bit_index != last_chunk / 4) { - int new_index = last_chunk / 4; - printer->Print("cached_has_bits = from._has_bits_[$new_index$];\n", - "new_index", SimpleItoa(new_index)); - cached_has_bit_index = new_index; + cached_has_bit_index = last_chunk / 4; + format("cached_has_bits = from._has_bits_[$1$];\n", + cached_has_bit_index); } - - printer->Print( - "if (cached_has_bits & $mask$u) {\n", - "mask", SimpleItoa(last_chunk_mask)); - printer->Indent(); + format("if (cached_has_bits & 0x$1$u) {\n", + StrCat(strings::Hex(last_chunk_mask, strings::ZERO_PAD_8))); + format.Indent(); } - // Go back and emit clears for each of the fields we processed. + // Go back and emit merging code for each of the fields we processed. bool deferred_has_bit_changes = false; - for (int j = last_chunk_start; j <= last_chunk_end; j++) { - const FieldDescriptor* field = optimized_order_[j]; + for (const auto field : chunk) { const FieldGenerator& generator = field_generators_.get(field); - bool have_enclosing_if = false; - if (HasFieldPresence(descriptor_->file())) { - // Attempt to use the state of cached_has_bits, if possible. - int has_bit_index = has_bit_indices_[field->index()]; - if (!field->options().weak() && - cached_has_bit_index == has_bit_index / 32) { - const string mask = StrCat( - strings::Hex(1u << (has_bit_index % 32), - strings::ZERO_PAD_8)); - - printer->Print( - "if (cached_has_bits & 0x$mask$u) {\n", "mask", mask); - } else { - printer->Print( - "if (from.has_$name$()) {\n", - "name", FieldName(field)); - } + // Attempt to use the state of cached_has_bits, if possible. + int has_bit_index = has_bit_indices_[field->index()]; + if (!field->options().weak() && + cached_has_bit_index == has_bit_index / 32) { + const string mask = StrCat( + strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); - printer->Indent(); - have_enclosing_if = true; + format("if (cached_has_bits & 0x$1$u) {\n", mask); } else { - // Merge semantics without true field presence: primitive fields are - // merged only if non-zero (numeric) or non-empty (string). - have_enclosing_if = EmitFieldNonDefaultCondition( - printer, "from.", field); + format("if (from.has_$1$()) {\n", FieldName(field)); } + format.Indent(); if (have_outer_if && IsPOD(field)) { // GenerateCopyConstructorCode for enum and primitive scalar fields @@ -3164,181 +3187,233 @@ GenerateMergeFrom(io::Printer* printer) { generator.GenerateMergingCode(printer); } - if (have_enclosing_if) { - printer->Outdent(); - printer->Print("}\n"); - } + format.Outdent(); + format("}\n"); } if (have_outer_if) { if (deferred_has_bit_changes) { // Flush the has bits for the primitives we deferred. GOOGLE_CHECK_LE(0, cached_has_bit_index); - printer->Print( - "_has_bits_[$index$] |= cached_has_bits;\n", - "index", SimpleItoa(cached_has_bit_index)); + format("_has_bits_[$1$] |= cached_has_bits;\n", cached_has_bit_index); } - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); + } + + if (cold_skipper.OnEndChunk(chunk_index, printer)) { + // Reset here as it may have been updated in just closed if statement. + cached_has_bit_index = -1; + } + } + } else { + // proto3 + for (const auto field : optimized_order_) { + const FieldGenerator& generator = field_generators_.get(field); + // Merge semantics without true field presence: primitive fields are + // merged only if non-zero (numeric) or non-empty (string). + bool have_enclosing_if = + EmitFieldNonDefaultCondition(printer, "from.", field); + + generator.GenerateMergingCode(printer); + + if (have_enclosing_if) { + format.Outdent(); + format("}\n"); } } } // Merge oneof fields. Oneof field requires oneof case check. - for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { - printer->Print( - "switch (from.$oneofname$_case()) {\n", - "oneofname", descriptor_->oneof_decl(i)->name()); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); - printer->Print( - "case k$field_name$: {\n", - "field_name", UnderscoresToCamelCase(field->name(), true)); - printer->Indent(); + for (auto oneof : OneOfRange(descriptor_)) { + format("switch (from.$1$_case()) {\n", oneof->name()); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); field_generators_.get(field).GenerateMergingCode(printer); - printer->Print( - "break;\n"); - printer->Outdent(); - printer->Print( - "}\n"); + format("break;\n"); + format.Outdent(); + format("}\n"); } - printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" + format( + "case $1$_NOT_SET: {\n" " break;\n" "}\n", - "cap_oneof_name", - ToUpper(descriptor_->oneof_decl(i)->name())); - printer->Outdent(); - printer->Print( - "}\n"); + ToUpper(oneof->name())); + format.Outdent(); + format("}\n"); } if (num_weak_fields_) { - printer->Print("_weak_field_map_.MergeFrom(from._weak_field_map_);\n"); + format("_weak_field_map_.MergeFrom(from._weak_field_map_);\n"); } - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } -void MessageGenerator:: -GenerateCopyFrom(io::Printer* printer) { +void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { + Formatter format(printer, variables_); if (HasDescriptorMethods(descriptor_->file(), options_)) { // Generate the generalized CopyFrom (aka that which takes in the Message // base class as a parameter). - printer->Print( - "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n" + format( + "void $classname$::CopyFrom(const ::$proto_ns$::Message& from) {\n" "// @@protoc_insertion_point(generalized_copy_from_start:" - "$full_name$)\n", - "classname", classname_, "full_name", descriptor_->full_name()); - printer->Indent(); - - printer->Print( - "if (&from == this) return;\n" - "Clear();\n" - "MergeFrom(from);\n"); + "$full_name$)\n"); + format.Indent(); + + format("if (&from == this) return;\n"); + + if (!options_.opensource_runtime) { + // This check is disabled in the opensource release because we're + // concerned that many users do not define NDEBUG in their release + // builds. + format( + "#ifndef NDEBUG\n" + "size_t from_size = from.ByteSizeLong();\n" + "#endif\n" + "Clear();\n" + "#ifndef NDEBUG\n" + "$CHK$_EQ(from_size, from.ByteSizeLong())\n" + " << \"Source of CopyFrom changed when clearing target. Either \"\n" + " << \"source is a nested message in target (not allowed), or \"\n" + " << \"another thread is modifying the source.\";\n" + "#endif\n"); + } else { + format("Clear();\n"); + } + format("MergeFrom(from);\n"); - printer->Outdent(); - printer->Print("}\n\n"); + format.Outdent(); + format("}\n\n"); } // Generate the class-specific CopyFrom. - printer->Print( + format( "void $classname$::CopyFrom(const $classname$& from) {\n" "// @@protoc_insertion_point(class_specific_copy_from_start:" - "$full_name$)\n", - "classname", classname_, "full_name", descriptor_->full_name()); - printer->Indent(); - - printer->Print( - "if (&from == this) return;\n" - "Clear();\n" - "MergeFrom(from);\n"); + "$full_name$)\n"); + format.Indent(); + + format("if (&from == this) return;\n"); + + if (!options_.opensource_runtime) { + // This check is disabled in the opensource release because we're + // concerned that many users do not define NDEBUG in their release builds. + format( + "#ifndef NDEBUG\n" + "size_t from_size = from.ByteSizeLong();\n" + "#endif\n" + "Clear();\n" + "#ifndef NDEBUG\n" + "$CHK$_EQ(from_size, from.ByteSizeLong())\n" + " << \"Source of CopyFrom changed when clearing target. Either \"\n" + " << \"source is a nested message in target (not allowed), or \"\n" + " << \"another thread is modifying the source.\";\n" + "#endif\n"); + } else { + format("Clear();\n"); + } + format("MergeFrom(from);\n"); - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } -void MessageGenerator:: -GenerateMergeFromCodedStream(io::Printer* printer) { - std::map<string, string> vars; +void MessageGenerator::GenerateMergeFromCodedStream(io::Printer* printer) { + std::map<string, string> vars = variables_; SetUnknkownFieldsVariable(descriptor_, options_, &vars); + Formatter format(printer, vars); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. - vars["classname"] = classname_; - printer->Print(vars, - "bool $classname$::MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input) {\n" - " return _extensions_.ParseMessageSet(input,\n" - " internal_default_instance(), $mutable_unknown_fields$);\n" - "}\n"); + format( + "#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n" + "const char* $classname$::_InternalParse(const char* begin, const " + "char* end, void* object,\n" + " ::$proto_ns$::internal::ParseContext* ctx) {\n" + " return ::$proto_ns$::internal::ParseMessageSet(begin, end, " + "static_cast<$classname$*>(object), ctx);\n" + "}\n" + "const char* $classname$::InternalParseMessageSetItem(const char* " + "begin, const char* end, void* object,\n" + " ::$proto_ns$::internal::ParseContext* ctx) {\n" + " auto msg = static_cast<$classname$*>(object);\n" + " return " + "msg->_extensions_.ParseMessageSetItem({InternalParseMessageSetItem, " + "msg}, begin, end, internal_default_instance(), " + "&msg->_internal_metadata_, ctx);\n" + "}\n" + "#else\n" + "bool $classname$::MergePartialFromCodedStream(\n" + " ::$proto_ns$::io::CodedInputStream* input) {\n" + " return _extensions_.ParseMessageSet(input,\n" + " internal_default_instance(), $mutable_unknown_fields$);\n" + "}\n" + "#endif // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"); return; } + format("#if $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"); + GenerateParserLoop(descriptor_, options_, scc_analyzer_, printer); + format("#else // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"); std::vector<const FieldDescriptor*> ordered_fields = SortFieldsByNumber(descriptor_); - printer->Print( - "bool $classname$::MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input) {\n", - "classname", classname_); + format( + "bool $classname$::MergePartialFromCodedStream(\n" + " ::$proto_ns$::io::CodedInputStream* input) {\n"); if (table_driven_) { - printer->Indent(); + format.Indent(); - const string lite = UseUnknownFieldSet(descriptor_->file(), options_) ? - "" : "Lite"; + const string lite = + UseUnknownFieldSet(descriptor_->file(), options_) ? "" : "Lite"; - printer->Print( - "return ::google::protobuf::internal::MergePartialFromCodedStream$lite$(\n" - " this,\n" - " ::$file_namespace$::TableStruct::schema[\n" - " $classname$::kIndexInFileMessages],\n" - " input);\n", - "classname", classname_, "file_namespace", - FileLevelNamespace(descriptor_), "lite", lite); + format( + "return ::$proto_ns$::internal::MergePartialFromCodedStream$1$(\n" + " this, ::$tablename$::schema[\n" + " $classname$::kIndexInFileMessages], input);\n", + lite); - printer->Outdent(); + format.Outdent(); - printer->Print("}\n"); + format("}\n"); + format("#endif // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"); return; } if (SupportsArenas(descriptor_)) { - for (int i = 0; i < ordered_fields.size(); i++) { - const FieldDescriptor* field = ordered_fields[i]; + for (auto field : ordered_fields) { const FieldGenerator& field_generator = field_generators_.get(field); if (field_generator.MergeFromCodedStreamNeedsArena()) { - printer->Print( - " ::google::protobuf::Arena* arena = GetArenaNoVirtual();\n"); + format(" ::$proto_ns$::Arena* arena = GetArenaNoVirtual();\n"); break; } } } - printer->Print( - "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto " - "failure\n" - " ::google::protobuf::uint32 tag;\n"); + format( + "#define DO_(EXPRESSION) if " + "(!$GOOGLE_PROTOBUF$_PREDICT_TRUE(EXPRESSION)) goto failure\n" + " $uint32$ tag;\n"); if (!UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - " ::google::protobuf::internal::LiteUnknownFieldSetter unknown_fields_setter(\n" + format( + " ::$proto_ns$::internal::LiteUnknownFieldSetter " + "unknown_fields_setter(\n" " &_internal_metadata_);\n" - " ::google::protobuf::io::StringOutputStream unknown_fields_output(\n" + " ::$proto_ns$::io::StringOutputStream unknown_fields_output(\n" " unknown_fields_setter.buffer());\n" - " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" - " &unknown_fields_output, false);\n", - "classname", classname_); + " ::$proto_ns$::io::CodedOutputStream unknown_fields_stream(\n" + " &unknown_fields_output, false);\n"); } - printer->Print( - " // @@protoc_insertion_point(parse_start:$full_name$)\n", - "full_name", descriptor_->full_name()); + format(" // @@protoc_insertion_point(parse_start:$full_name$)\n"); - printer->Indent(); - printer->Print("for (;;) {\n"); - printer->Indent(); + format.Indent(); + format("for (;;) {\n"); + format.Indent(); // To calculate the maximum tag to expect, we look at the highest-numbered // field. We need to be prepared to handle more than one wire type if that @@ -3355,8 +3430,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { bool capture_last_tag = false; const Descriptor* parent = descriptor_->containing_type(); if (parent) { - for (int i = 0; i < parent->field_count(); i++) { - const FieldDescriptor* field = parent->field(i); + for (auto field : FieldRange(parent)) { if (field->type() == FieldDescriptor::TYPE_GROUP && field->message_type() == descriptor_) { capture_last_tag = true; @@ -3383,13 +3457,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } } - printer->Print("::std::pair<::google::protobuf::uint32, bool> p = " - "input->ReadTagWithCutoffNoLastTag($max$u);\n" - "tag = p.first;\n" - "if (!p.second) goto handle_unusual;\n", - "max", SimpleItoa(maxtag <= kCutoff0 ? kCutoff0 : - (maxtag <= kCutoff1 ? kCutoff1 : - maxtag))); + format( + "::std::pair<$uint32$, bool> p = " + "input->ReadTagWithCutoffNoLastTag($1$u);\n" + "tag = p.first;\n" + "if (!p.second) goto handle_unusual;\n", + maxtag <= kCutoff0 ? kCutoff0 : (maxtag <= kCutoff1 ? kCutoff1 : maxtag)); if (descriptor_->field_count() > 0) { // We don't even want to print the switch() if we have no fields because @@ -3407,182 +3480,189 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // inserts branches that may fail (especially for real world protos that // interleave--in field number order--hot and cold fields). Loadtests // confirmed that removing this optimization is performance neutral. - printer->Print("switch (::google::protobuf::internal::WireFormatLite::" - "GetTagFieldNumber(tag)) {\n"); - - printer->Indent(); - - for (int i = 0; i < ordered_fields.size(); i++) { - const FieldDescriptor* field = ordered_fields[i]; - - PrintFieldComment(printer, field); + if (num_weak_fields_ > 0) { + format("uint32 weak_offset;\n"); + } + format( + "switch (::$proto_ns$::internal::WireFormatLite::" + "GetTagFieldNumber(tag)) {\n"); + + format.Indent(); + + for (auto field : ordered_fields) { + PrintFieldComment(format, field); + if (IsWeak(field, options_)) { + format( + "case $1$:\n" + " weak_offset = offsetof($classname$DefaultTypeInternal, $2$_);\n" + " goto handle_weak_field_map;\n", + field->number(), FieldName(field)); + continue; + } - printer->Print( - "case $number$: {\n", - "number", SimpleItoa(field->number())); - printer->Indent(); + format("case $1$: {\n", field->number()); + format.Indent(); const FieldGenerator& field_generator = field_generators_.get(field); // Emit code to parse the common, expected case. - printer->Print( - "if (static_cast< ::google::protobuf::uint8>(tag) ==\n" - " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n", - "truncated", SimpleItoa(WireFormat::MakeTag(field) & 0xFF), - "full", SimpleItoa(WireFormat::MakeTag(field))); + // MSVC is warning about truncating constant in the static_cast so + // we truncate the tag explicitly. + format( + "if (static_cast< $uint8$>(tag) == ($1$ & 0xFF)) {\n", + WireFormat::MakeTag(field)); - printer->Indent(); + format.Indent(); if (field->is_packed()) { field_generator.GenerateMergeFromCodedStreamWithPacking(printer); } else { field_generator.GenerateMergeFromCodedStream(printer); } - printer->Outdent(); + format.Outdent(); // Emit code to parse unexpectedly packed or unpacked values. if (field->is_packed()) { internal::WireFormatLite::WireType wiretype = WireFormat::WireTypeForFieldType(field->type()); - const uint32 tag = internal::WireFormatLite::MakeTag( - field->number(), wiretype); - printer->Print( - "} else if (\n" - " static_cast< ::google::protobuf::uint8>(tag) ==\n" - " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n", - "truncated", SimpleItoa(tag & 0xFF), - "full", SimpleItoa(tag)); - - printer->Indent(); + const uint32 tag = + internal::WireFormatLite::MakeTag(field->number(), wiretype); + format( + "} else if (static_cast< $uint8$>(tag) == ($1$ & 0xFF)) {\n", + tag); + + format.Indent(); field_generator.GenerateMergeFromCodedStream(printer); - printer->Outdent(); + format.Outdent(); } else if (field->is_packable() && !field->is_packed()) { internal::WireFormatLite::WireType wiretype = internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED; - const uint32 tag = internal::WireFormatLite::MakeTag( - field->number(), wiretype); - - printer->Print( - "} else if (\n" - " static_cast< ::google::protobuf::uint8>(tag) ==\n" - " static_cast< ::google::protobuf::uint8>($truncated$u /* $full$ & 0xFF */)) {\n", - "truncated", SimpleItoa(tag & 0xFF), - "full", SimpleItoa(tag)); - printer->Indent(); + const uint32 tag = + internal::WireFormatLite::MakeTag(field->number(), wiretype); + format( + "} else if (static_cast< $uint8$>(tag) == ($1$ & 0xFF)) {\n", + tag); + format.Indent(); field_generator.GenerateMergeFromCodedStreamWithPacking(printer); - printer->Outdent(); + format.Outdent(); } - printer->Print( - "} else {\n" - " goto handle_unusual;\n" - "}\n"); + format( + "} else {\n" + " goto handle_unusual;\n" + "}\n"); - printer->Print( - "break;\n"); + format("break;\n"); - printer->Outdent(); - printer->Print("}\n\n"); + format.Outdent(); + format("}\n\n"); + } + if (num_weak_fields_ > 0) { + format("handle_weak_field_map: {\n"); + format.Indent(); + + format( + "if ((tag & 0x7) != 2) goto handle_unusual;\n" + "DO_(_weak_field_map_.ReadMessage(input, tag >> 3,\n" + " &_$classname$_default_instance_, weak_offset));\n"); + format("break;\n"); + format.Outdent(); + format("}\n\n"); } - printer->Print("default: {\n"); - printer->Indent(); + format("default: {\n"); + format.Indent(); } - printer->Outdent(); - printer->Print("handle_unusual:\n"); - printer->Indent(); + format.Outdent(); + format("handle_unusual:\n"); + format.Indent(); // If tag is 0 or an end-group tag then this must be the end of the message. if (capture_last_tag) { - printer->Print( - "if (tag == 0 ||\n" - " ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n" - " ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n" - " input->SetLastTag(tag);\n" - " goto success;\n" - "}\n"); + format( + "if (tag == 0 ||\n" + " ::$proto_ns$::internal::WireFormatLite::GetTagWireType(tag) ==\n" + " ::$proto_ns$::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n" + " input->SetLastTag(tag);\n" + " goto success;\n" + "}\n"); } else { - printer->Print( - "if (tag == 0) {\n" - " goto success;\n" - "}\n"); + format( + "if (tag == 0) {\n" + " goto success;\n" + "}\n"); } // Handle extension ranges. if (descriptor_->extension_range_count() > 0) { - printer->Print( - "if ("); + format("if ("); for (int i = 0; i < descriptor_->extension_range_count(); i++) { - const Descriptor::ExtensionRange* range = - descriptor_->extension_range(i); - if (i > 0) printer->Print(" ||\n "); + const Descriptor::ExtensionRange* range = descriptor_->extension_range(i); + if (i > 0) format(" ||\n "); uint32 start_tag = WireFormatLite::MakeTag( - range->start, static_cast<WireFormatLite::WireType>(0)); + range->start, static_cast<WireFormatLite::WireType>(0)); uint32 end_tag = WireFormatLite::MakeTag( - range->end, static_cast<WireFormatLite::WireType>(0)); + range->end, static_cast<WireFormatLite::WireType>(0)); if (range->end > FieldDescriptor::kMaxNumber) { - printer->Print( - "($start$u <= tag)", - "start", SimpleItoa(start_tag)); + format("($1$u <= tag)", start_tag); } else { - printer->Print( - "($start$u <= tag && tag < $end$u)", - "start", SimpleItoa(start_tag), - "end", SimpleItoa(end_tag)); + format("($1$u <= tag && tag < $2$u)", start_tag, end_tag); } } - printer->Print(") {\n"); + format(") {\n"); if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(vars, - " DO_(_extensions_.ParseField(tag, input,\n" - " internal_default_instance(),\n" - " $mutable_unknown_fields$));\n"); + format( + " DO_(_extensions_.ParseField(tag, input,\n" + " internal_default_instance(),\n" + " $mutable_unknown_fields$));\n"); } else { - printer->Print( - " DO_(_extensions_.ParseField(tag, input,\n" - " internal_default_instance(),\n" - " &unknown_fields_stream));\n"); + format( + " DO_(_extensions_.ParseField(tag, input,\n" + " internal_default_instance(),\n" + " &unknown_fields_stream));\n"); } - printer->Print( - " continue;\n" - "}\n"); + format( + " continue;\n" + "}\n"); } // We really don't recognize this tag. Skip it. if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(vars, - "DO_(::google::protobuf::internal::WireFormat::SkipField(\n" + format( + "DO_(::$proto_ns$::internal::WireFormat::SkipField(\n" " input, tag, $mutable_unknown_fields$));\n"); } else { - printer->Print( - "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n" + format( + "DO_(::$proto_ns$::internal::WireFormatLite::SkipField(\n" " input, tag, &unknown_fields_stream));\n"); } if (descriptor_->field_count() > 0) { - printer->Print("break;\n"); - printer->Outdent(); - printer->Print("}\n"); // default: - printer->Outdent(); - printer->Print("}\n"); // switch - } - - printer->Outdent(); - printer->Outdent(); - printer->Print( - " }\n" // for (;;) - "success:\n" - " // @@protoc_insertion_point(parse_success:$full_name$)\n" - " return true;\n" - "failure:\n" - " // @@protoc_insertion_point(parse_failure:$full_name$)\n" - " return false;\n" - "#undef DO_\n" - "}\n", "full_name", descriptor_->full_name()); + format("break;\n"); + format.Outdent(); + format("}\n"); // default: + format.Outdent(); + format("}\n"); // switch + } + + format.Outdent(); + format.Outdent(); + format( + " }\n" // for (;;) + "success:\n" + " // @@protoc_insertion_point(parse_success:$full_name$)\n" + " return true;\n" + "failure:\n" + " // @@protoc_insertion_point(parse_failure:$full_name$)\n" + " return false;\n" + "#undef DO_\n" + "}\n"); + format("#endif // $GOOGLE_PROTOBUF$_ENABLE_EXPERIMENTAL_PARSER\n"); } void MessageGenerator::GenerateSerializeOneofFields( io::Printer* printer, const std::vector<const FieldDescriptor*>& fields, bool to_array) { + Formatter format(printer, variables_); GOOGLE_CHECK(!fields.empty()); if (fields.size() == 1) { GenerateSerializeOneField(printer, fields[0], to_array, -1); @@ -3590,39 +3670,35 @@ void MessageGenerator::GenerateSerializeOneofFields( } // We have multiple mutually exclusive choices. Emit a switch statement. const OneofDescriptor* oneof = fields[0]->containing_oneof(); - printer->Print( - "switch ($oneofname$_case()) {\n", - "oneofname", oneof->name()); - printer->Indent(); - for (int i = 0; i < fields.size(); i++) { - const FieldDescriptor* field = fields[i]; - printer->Print( - "case k$field_name$:\n", - "field_name", UnderscoresToCamelCase(field->name(), true)); - printer->Indent(); + format("switch ($1$_case()) {\n", oneof->name()); + format.Indent(); + for (auto field : fields) { + format("case k$1$:\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); if (to_array) { field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( printer); } else { field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); } - printer->Print( - "break;\n"); - printer->Outdent(); + format("break;\n"); + format.Outdent(); } - printer->Outdent(); + format.Outdent(); // Doing nothing is an option. - printer->Print( - " default: ;\n" - "}\n"); + format( + " default: ;\n" + "}\n"); } -void MessageGenerator::GenerateSerializeOneField( - io::Printer* printer, const FieldDescriptor* field, bool to_array, - int cached_has_bits_index) { +void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, + const FieldDescriptor* field, + bool to_array, + int cached_has_bits_index) { + Formatter format(printer, variables_); if (!field->options().weak()) { // For weakfields, PrintFieldComment is called during iteration. - PrintFieldComment(printer, field); + PrintFieldComment(format, field); } bool have_enclosing_if = false; @@ -3631,19 +3707,15 @@ void MessageGenerator::GenerateSerializeOneField( // Attempt to use the state of cached_has_bits, if possible. int has_bit_index = has_bit_indices_[field->index()]; if (cached_has_bits_index == has_bit_index / 32) { - const string mask = StrCat( - strings::Hex(1u << (has_bit_index % 32), - strings::ZERO_PAD_8)); + const string mask = + StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); - printer->Print( - "if (cached_has_bits & 0x$mask$u) {\n", "mask", mask); + format("if (cached_has_bits & 0x$1$u) {\n", mask); } else { - printer->Print( - "if (has_$name$()) {\n", - "name", FieldName(field)); + format("if (has_$1$()) {\n", FieldName(field)); } - printer->Indent(); + format.Indent(); have_enclosing_if = true; } else if (!HasFieldPresence(descriptor_->file())) { have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field); @@ -3657,10 +3729,10 @@ void MessageGenerator::GenerateSerializeOneField( } if (have_enclosing_if) { - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } - printer->Print("\n"); + format("\n"); } void MessageGenerator::GenerateSerializeOneExtensionRange( @@ -3669,110 +3741,99 @@ void MessageGenerator::GenerateSerializeOneExtensionRange( std::map<string, string> vars; vars["start"] = SimpleItoa(range->start); vars["end"] = SimpleItoa(range->end); - printer->Print(vars, - "// Extension range [$start$, $end$)\n"); + Formatter format(printer, vars); + format("// Extension range [$start$, $end$)\n"); if (to_array) { - printer->Print(vars, - "target = _extensions_.InternalSerializeWithCachedSizesToArray(\n" - " $start$, $end$, deterministic, target);\n\n"); + format( + "target = _extensions_.InternalSerializeWithCachedSizesToArray(\n" + " $start$, $end$, deterministic, target);\n\n"); } else { - printer->Print(vars, - "_extensions_.SerializeWithCachedSizes(\n" - " $start$, $end$, output);\n\n"); + format( + "_extensions_.SerializeWithCachedSizes($start$, $end$, output);\n" + "\n"); } } -void MessageGenerator:: -GenerateSerializeWithCachedSizes(io::Printer* printer) { +void MessageGenerator::GenerateSerializeWithCachedSizes(io::Printer* printer) { + Formatter format(printer, variables_); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. - printer->Print( - "void $classname$::SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const {\n" - " _extensions_.SerializeMessageSetWithCachedSizes(output);\n", - "classname", classname_); - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); + format( + "void $classname$::SerializeWithCachedSizes(\n" + " ::$proto_ns$::io::CodedOutputStream* output) const {\n" + " _extensions_.SerializeMessageSetWithCachedSizes(output);\n"); std::map<string, string> vars; SetUnknkownFieldsVariable(descriptor_, options_, &vars); - printer->Print(vars, - " ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n" - " $unknown_fields$, output);\n"); - printer->Print( - "}\n"); + format.AddMap(vars); + format( + " " + "::$proto_ns$::internal::SerializeUnknownMessageSetItems(\n" + " $unknown_fields$, output);\n"); + format("}\n"); return; } if (options_.table_driven_serialization) return; - printer->Print( - "void $classname$::SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const {\n", - "classname", classname_); - printer->Indent(); + format( + "void $classname$::SerializeWithCachedSizes(\n" + " ::$proto_ns$::io::CodedOutputStream* output) const {\n"); + format.Indent(); - printer->Print( - "// @@protoc_insertion_point(serialize_start:$full_name$)\n", - "full_name", descriptor_->full_name()); + format("// @@protoc_insertion_point(serialize_start:$full_name$)\n"); GenerateSerializeWithCachedSizesBody(printer, false); - printer->Print( - "// @@protoc_insertion_point(serialize_end:$full_name$)\n", - "full_name", descriptor_->full_name()); + format("// @@protoc_insertion_point(serialize_end:$full_name$)\n"); - printer->Outdent(); - printer->Print( - "}\n"); + format.Outdent(); + format("}\n"); } -void MessageGenerator:: -GenerateSerializeWithCachedSizesToArray(io::Printer* printer) { +void MessageGenerator::GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) { + Formatter format(printer, variables_); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. - printer->Print( - "::google::protobuf::uint8* $classname$::InternalSerializeWithCachedSizesToArray(\n" - " bool deterministic, ::google::protobuf::uint8* target) const {\n" - " target = _extensions_." - "InternalSerializeMessageSetWithCachedSizesToArray(\n" - " deterministic, target);\n", - "classname", classname_); - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); + format( + "$uint8$* $classname$::InternalSerializeWithCachedSizesToArray(\n" + " bool deterministic, $uint8$* target) const {\n" + " target = _extensions_." + "InternalSerializeMessageSetWithCachedSizesToArray(\n" + " deterministic, target);\n"); std::map<string, string> vars; SetUnknkownFieldsVariable(descriptor_, options_, &vars); - printer->Print(vars, - " target = ::google::protobuf::internal::WireFormat::\n" - " SerializeUnknownMessageSetItemsToArray(\n" - " $unknown_fields$, target);\n"); - printer->Print( - " return target;\n" - "}\n"); + format.AddMap(vars); + format( + " target = ::$proto_ns$::internal::\n" + " SerializeUnknownMessageSetItemsToArray(\n" + " $unknown_fields$, target);\n"); + format( + " return target;\n" + "}\n"); return; } - printer->Print( - "::google::protobuf::uint8* $classname$::InternalSerializeWithCachedSizesToArray(\n" - " bool deterministic, ::google::protobuf::uint8* target) const {\n", - "classname", classname_); - printer->Indent(); + format( + "$uint8$* $classname$::InternalSerializeWithCachedSizesToArray(\n" + " bool deterministic, $uint8$* target) const {\n"); + format.Indent(); - printer->Print("(void)deterministic; // Unused\n"); - printer->Print( - "// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n", - "full_name", descriptor_->full_name()); + format("(void)deterministic; // Unused\n"); + format("// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n"); GenerateSerializeWithCachedSizesBody(printer, true); - printer->Print( - "// @@protoc_insertion_point(serialize_to_array_end:$full_name$)\n", - "full_name", descriptor_->full_name()); + format("// @@protoc_insertion_point(serialize_to_array_end:$full_name$)\n"); - printer->Outdent(); - printer->Print( - " return target;\n" - "}\n"); + format.Outdent(); + format( + " return target;\n" + "}\n"); } -void MessageGenerator:: -GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { +void MessageGenerator::GenerateSerializeWithCachedSizesBody( + io::Printer* printer, bool to_array) { + 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 // because it lets the C++ compiler know this is a "at most one can happen" @@ -3783,7 +3844,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer, bool to_array) : mg_(mg), - printer_(printer), + format_(printer), to_array_(to_array), eager_(!HasFieldPresence(mg->descriptor_->file())), cached_has_bit_index_(-1) {} @@ -3808,16 +3869,14 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { // Reload. int new_index = has_bit_index / 32; - printer_->Print( - "cached_has_bits = _has_bits_[$new_index$];\n", - "new_index", SimpleItoa(new_index)); + format_("cached_has_bits = _has_bits_[$1$];\n", new_index); cached_has_bit_index_ = new_index; } } - mg_->GenerateSerializeOneField( - printer_, field, to_array_, cached_has_bit_index_); + mg_->GenerateSerializeOneField(format_.printer(), field, to_array_, + cached_has_bit_index_); } else { v_.push_back(field); } @@ -3825,7 +3884,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { void Flush() { if (!v_.empty()) { - mg_->GenerateSerializeOneofFields(printer_, v_, to_array_); + mg_->GenerateSerializeOneofFields(format_.printer(), v_, to_array_); v_.clear(); } } @@ -3839,7 +3898,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { } MessageGenerator* mg_; - io::Printer* printer_; + Formatter format_; const bool to_array_; const bool eager_; std::vector<const FieldDescriptor*> v_; @@ -3860,13 +3919,13 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { std::sort(sorted_extensions.begin(), sorted_extensions.end(), ExtensionRangeSorter()); if (num_weak_fields_) { - printer->Print( - "::google::protobuf::internal::WeakFieldMap::FieldWriter field_writer(" + format( + "::$proto_ns$::internal::WeakFieldMap::FieldWriter field_writer(" "_weak_field_map_);\n"); } - printer->Print( - "::google::protobuf::uint32 cached_has_bits = 0;\n" + format( + "$uint32$ cached_has_bits = 0;\n" "(void) cached_has_bits;\n\n"); // Merge the fields and the extension ranges, both sorted by field number. @@ -3882,7 +3941,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { const FieldDescriptor* field = ordered_fields[i++]; if (field->options().weak()) { last_weak_field = field; - PrintFieldComment(printer, field); + PrintFieldComment(format, field); } else { if (last_weak_field != nullptr) { e.Emit(last_weak_field); @@ -3890,14 +3949,13 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { } e.Emit(field); } - } else { + } else { if (last_weak_field != nullptr) { e.Emit(last_weak_field); last_weak_field = nullptr; } e.Flush(); - GenerateSerializeOneExtensionRange(printer, - sorted_extensions[j++], + GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++], to_array); } } @@ -3908,27 +3966,27 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { std::map<string, string> vars; SetUnknkownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(vars, - "if ($have_unknown_fields$) {\n"); - printer->Indent(); + format("if ($have_unknown_fields$) {\n"); + format.Indent(); if (to_array) { - printer->Print(vars, - "target = " - "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n" - " $unknown_fields$, target);\n"); + format( + "target = " + "::$proto_ns$::internal::WireFormat::SerializeUnknownFieldsToArray(\n" + " $unknown_fields$, target);\n"); } else { - printer->Print(vars, - "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" - " $unknown_fields$, output);\n"); + format( + "::$proto_ns$::internal::WireFormat::SerializeUnknownFields(\n" + " $unknown_fields$, output);\n"); } - printer->Outdent(); + format.Outdent(); - printer->Print("}\n"); + format("}\n"); } else { - printer->Print(vars, - "output->WriteRaw($unknown_fields$.data(),\n" - " static_cast<int>($unknown_fields$.size()));\n"); + format( + "output->WriteRaw($unknown_fields$.data(),\n" + " static_cast<int>($unknown_fields$.size()));\n"); } } @@ -3936,15 +3994,13 @@ std::vector<uint32> MessageGenerator::RequiredFieldsBitMask() const { const int array_size = HasBitsSize(); std::vector<uint32> masks(array_size, 0); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + for (auto field : FieldRange(descriptor_)) { if (!field->is_required()) { continue; } const int has_bit_index = has_bit_indices_[field->index()]; - masks[has_bit_index / 32] |= - static_cast<uint32>(1) << (has_bit_index % 32); + masks[has_bit_index / 32] |= static_cast<uint32>(1) << (has_bit_index % 32); } return masks; } @@ -3959,35 +4015,36 @@ static string ConditionalToCheckBitmasks(const std::vector<uint32>& masks) { if (masks[i] == 0) continue; string m = StrCat("0x", strings::Hex(masks[i], strings::ZERO_PAD_8)); // Each xor evaluates to 0 if the expected bits are present. - parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")")); + parts.push_back( + StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")")); } GOOGLE_CHECK(!parts.empty()); // If we have multiple parts, each expected to be 0, then bitwise-or them. - string result = parts.size() == 1 - ? parts[0] - : StrCat("(", Join(parts, "\n | "), ")"); + string result = + parts.size() == 1 + ? parts[0] + : StrCat("(", Join(parts, "\n | "), ")"); return result + " == 0"; } -void MessageGenerator:: -GenerateByteSize(io::Printer* printer) { +void MessageGenerator::GenerateByteSize(io::Printer* printer) { + Formatter format(printer, variables_); + if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); std::map<string, string> vars; SetUnknkownFieldsVariable(descriptor_, options_, &vars); - vars["classname"] = classname_; - vars["full_name"] = descriptor_->full_name(); - printer->Print( - vars, + format.AddMap(vars); + format( "size_t $classname$::ByteSizeLong() const {\n" "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" " size_t total_size = _extensions_.MessageSetByteSize();\n" " if ($have_unknown_fields$) {\n" - " total_size += ::google::protobuf::internal::WireFormat::\n" + " total_size += ::$proto_ns$::internal::\n" " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" " }\n" - " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" + " int cached_size = " + "::$proto_ns$::internal::ToCachedSize(total_size);\n" " SetCachedSize(cached_size);\n" " return total_size;\n" "}\n"); @@ -3997,60 +4054,60 @@ GenerateByteSize(io::Printer* printer) { if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) { // Emit a function (rarely used, we hope) that handles the required fields // by checking for each one individually. - printer->Print( + format( "size_t $classname$::RequiredFieldsByteSizeFallback() const {\n" "// @@protoc_insertion_point(required_fields_byte_size_fallback_start:" - "$full_name$)\n", - "classname", classname_, "full_name", descriptor_->full_name()); - printer->Indent(); - printer->Print("size_t total_size = 0;\n"); - for (int i = 0; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; + "$full_name$)\n"); + format.Indent(); + format("size_t total_size = 0;\n"); + for (auto field : optimized_order_) { if (field->is_required()) { - printer->Print("\n" - "if (has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); - PrintFieldComment(printer, field); + format( + "\n" + "if (has_$1$()) {\n", + FieldName(field)); + format.Indent(); + PrintFieldComment(format, field); field_generators_.get(field).GenerateByteSize(printer); - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } } - printer->Print("\n" - "return total_size;\n"); - printer->Outdent(); - printer->Print("}\n"); + format( + "\n" + "return total_size;\n"); + format.Outdent(); + format("}\n"); } - printer->Print( + format( "size_t $classname$::ByteSizeLong() const {\n" - "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n", - "classname", classname_, "full_name", descriptor_->full_name()); - printer->Indent(); - printer->Print( - "size_t total_size = 0;\n" - "\n"); + "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n"); + format.Indent(); + format( + "size_t total_size = 0;\n" + "\n"); if (descriptor_->extension_range_count() > 0) { - printer->Print( - "total_size += _extensions_.ByteSize();\n" - "\n"); + format( + "total_size += _extensions_.ByteSize();\n" + "\n"); } std::map<string, string> vars; SetUnknkownFieldsVariable(descriptor_, options_, &vars); + format.AddMap(vars); if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(vars, - "if ($have_unknown_fields$) {\n" - " total_size +=\n" - " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" - " $unknown_fields$);\n" - "}\n"); + format( + "if ($have_unknown_fields$) {\n" + " total_size +=\n" + " ::$proto_ns$::internal::WireFormat::ComputeUnknownFieldsSize(\n" + " $unknown_fields$);\n" + "}\n"); } else { - printer->Print(vars, - "total_size += $unknown_fields$.size();\n" - "\n"); + format( + "total_size += $unknown_fields$.size();\n" + "\n"); } // Handle required fields (if any). We expect all of them to be @@ -4059,35 +4116,32 @@ GenerateByteSize(io::Printer* printer) { if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) { // The fast path works if all required fields are present. const std::vector<uint32> masks_for_has_bits = RequiredFieldsBitMask(); - printer->Print((string("if (") + - ConditionalToCheckBitmasks(masks_for_has_bits) + - ") { // All required fields are present.\n").c_str()); - printer->Indent(); + 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 (int i = 0; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; + for (auto field : optimized_order_) { if (!field->is_required()) continue; - PrintFieldComment(printer, field); + PrintFieldComment(format, field); field_generators_.get(field).GenerateByteSize(printer); - printer->Print("\n"); + format("\n"); } - printer->Outdent(); - printer->Print("} else {\n" // the slow path - " total_size += RequiredFieldsByteSizeFallback();\n" - "}\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 (int i = 0; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; + for (auto field : optimized_order_) { if (!field->is_required()) continue; - PrintFieldComment(printer, field); - printer->Print("if (has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); + PrintFieldComment(format, field); + format("if (has_$1$()) {\n", FieldName(field)); + format.Indent(); field_generators_.get(field).GenerateByteSize(printer); - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } } @@ -4100,6 +4154,16 @@ GenerateByteSize(io::Printer* printer) { chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired), chunks.end()); + ColdChunkSkipper cold_skipper(options_, chunks, has_bit_indices_, kColdRatio, + HasFieldPresence(descriptor_->file())); + + format( + "$uint32$ cached_has_bits = 0;\n" + "// Prevent compiler warnings about cached_has_bits being unused\n" + "(void) cached_has_bits;\n\n"); + + int cached_has_bit_index = -1; + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; GOOGLE_CHECK(!chunk.empty()); @@ -4109,14 +4173,16 @@ GenerateByteSize(io::Printer* printer) { for (int i = 0; i < chunk.size(); i++) { const FieldDescriptor* field = chunk[i]; - PrintFieldComment(printer, field); + PrintFieldComment(format, field); const FieldGenerator& generator = field_generators_.get(field); generator.GenerateByteSize(printer); - printer->Print("\n"); + format("\n"); } continue; } + cold_skipper.OnStartChunk(chunk_index, cached_has_bit_index, "", printer); + // Handle optional (non-repeated/oneof) fields. // // These are handled in chunks of 8. The first chunk is @@ -4144,10 +4210,13 @@ GenerateByteSize(io::Printer* printer) { GOOGLE_DCHECK_LE(2, count); GOOGLE_DCHECK_GE(8, count); - printer->Print("if (_has_bits_[$index$ / 32] & $mask$u) {\n", "index", - SimpleItoa(last_chunk * 8), "mask", - SimpleItoa(last_chunk_mask)); - printer->Indent(); + if (cached_has_bit_index != last_chunk / 4) { + cached_has_bit_index = last_chunk / 4; + format("cached_has_bits = _has_bits_[$1$];\n", cached_has_bit_index); + } + format("if (cached_has_bits & 0x$1$u) {\n", + StrCat(strings::Hex(last_chunk_mask, strings::ZERO_PAD_8))); + format.Indent(); } // Go back and emit checks for each of the fields we processed. @@ -4155,12 +4224,12 @@ GenerateByteSize(io::Printer* printer) { const FieldDescriptor* field = chunk[j]; const FieldGenerator& generator = field_generators_.get(field); - PrintFieldComment(printer, field); + PrintFieldComment(format, field); bool have_enclosing_if = false; if (HasFieldPresence(descriptor_->file())) { - printer->Print("if (has_$name$()) {\n", "name", FieldName(field)); - printer->Indent(); + PrintPresenceCheck(format, field, has_bit_indices_, printer, + &cached_has_bit_index); have_enclosing_if = true; } else { // Without field presence: field is serialized only if it has a @@ -4172,54 +4241,50 @@ GenerateByteSize(io::Printer* printer) { generator.GenerateByteSize(printer); if (have_enclosing_if) { - printer->Outdent(); - printer->Print( + format.Outdent(); + format( "}\n" "\n"); } } if (have_outer_if) { - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); + } + + if (cold_skipper.OnEndChunk(chunk_index, printer)) { + // Reset here as it may have been updated in just closed if statement. + cached_has_bit_index = -1; } } // Fields inside a oneof don't use _has_bits_ so we count them in a separate // pass. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "switch ($oneofname$_case()) {\n", - "oneofname", descriptor_->oneof_decl(i)->name()); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); - PrintFieldComment(printer, field); - printer->Print( - "case k$field_name$: {\n", - "field_name", UnderscoresToCamelCase(field->name(), true)); - printer->Indent(); + for (auto oneof : OneOfRange(descriptor_)) { + format("switch ($1$_case()) {\n", oneof->name()); + format.Indent(); + for (auto field : FieldRange(oneof)) { + PrintFieldComment(format, field); + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); field_generators_.get(field).GenerateByteSize(printer); - printer->Print( - "break;\n"); - printer->Outdent(); - printer->Print( - "}\n"); + format("break;\n"); + format.Outdent(); + format("}\n"); } - printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" + format( + "case $1$_NOT_SET: {\n" " break;\n" "}\n", - "cap_oneof_name", - ToUpper(descriptor_->oneof_decl(i)->name())); - printer->Outdent(); - printer->Print( - "}\n"); + ToUpper(oneof->name())); + format.Outdent(); + format("}\n"); } if (num_weak_fields_) { // TagSize + MessageSize - printer->Print("total_size += _weak_field_map_.ByteSizeLong();\n"); + format("total_size += _weak_field_map_.ByteSizeLong();\n"); } // We update _cached_size_ even though this is a const method. Because @@ -4230,27 +4295,25 @@ GenerateByteSize(io::Printer* printer) { // 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. - printer->Print( - "int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" + format( + "int cached_size = ::$proto_ns$::internal::ToCachedSize(total_size);\n" "SetCachedSize(cached_size);\n" "return total_size;\n"); - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } -void MessageGenerator:: -GenerateIsInitialized(io::Printer* printer) { - printer->Print( - "bool $classname$::IsInitialized() const {\n", - "classname", classname_); - printer->Indent(); +void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { + Formatter format(printer, variables_); + format("bool $classname$::IsInitialized() const {\n"); + format.Indent(); if (descriptor_->extension_range_count() > 0) { - printer->Print( - "if (!_extensions_.IsInitialized()) {\n" - " return false;\n" - "}\n\n"); + format( + "if (!_extensions_.IsInitialized()) {\n" + " return false;\n" + "}\n\n"); } if (HasFieldPresence(descriptor_->file())) { @@ -4267,57 +4330,51 @@ GenerateIsInitialized(io::Printer* printer) { // TODO(ckennelly): Consider doing something similar to ByteSizeLong(), // where we check all of the required fields in a single branch (assuming // that we aren't going to benefit from early termination). - printer->Print( - "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n", - "i", SimpleItoa(i), - "mask", StrCat(strings::Hex(mask, strings::ZERO_PAD_8))); + format("if ((_has_bits_[$1$] & 0x$2$) != 0x$2$) return false;\n", + i, // 1 + StrCat(strings::Hex(mask, strings::ZERO_PAD_8))); // 2 } } // Now check that all non-oneof embedded messages are initialized. - for (int i = 0; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; + for (auto field : optimized_order_) { // TODO(ckennelly): Push this down into a generator? if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && !ShouldIgnoreRequiredFieldCheck(field, options_) && scc_analyzer_->HasRequiredFields(field->message_type())) { if (field->is_repeated()) { if (IsImplicitWeakField(field, options_, scc_analyzer_)) { - printer->Print( - "if (!::google::protobuf::internal::AllAreInitializedWeak(this->$name$_))" - " return false;\n", - "name", FieldName(field)); + format( + "if (!::$proto_ns$::internal::AllAreInitializedWeak(this->$1$_))" + " return false;\n", + FieldName(field)); } else { - printer->Print( - "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))" - " return false;\n", - "name", FieldName(field)); + format( + "if (!::$proto_ns$::internal::AllAreInitialized(this->$1$()))" + " return false;\n", + FieldName(field)); } } else if (field->options().weak()) { continue; } else { GOOGLE_CHECK(!field->containing_oneof()); - printer->Print( - "if (has_$name$()) {\n" - " if (!this->$name$_->IsInitialized()) return false;\n" + format( + "if (has_$1$()) {\n" + " if (!this->$1$_->IsInitialized()) return false;\n" "}\n", - "name", FieldName(field)); + FieldName(field)); } } } if (num_weak_fields_) { // For Weak fields. - printer->Print("if (!_weak_field_map_.IsInitialized()) return false;\n"); + format("if (!_weak_field_map_.IsInitialized()) return false;\n"); } // Go through the oneof fields, emitting a switch if any might have required // fields. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - const OneofDescriptor* oneof = descriptor_->oneof_decl(i); - + for (auto oneof : OneOfRange(descriptor_)) { bool has_required_fields = false; - for (int j = 0; j < oneof->field_count(); j++) { - const FieldDescriptor* field = oneof->field(j); - + for (auto field : FieldRange(oneof)) { if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && !ShouldIgnoreRequiredFieldCheck(field, options_) && scc_analyzer_->HasRequiredFields(field->message_type())) { @@ -4330,16 +4387,11 @@ GenerateIsInitialized(io::Printer* printer) { continue; } - printer->Print( - "switch ($oneofname$_case()) {\n", - "oneofname", oneof->name()); - printer->Indent(); - for (int j = 0; j < oneof->field_count(); j++) { - const FieldDescriptor* field = oneof->field(j); - printer->Print( - "case k$field_name$: {\n", - "field_name", UnderscoresToCamelCase(field->name(), true)); - printer->Indent(); + format("switch ($1$_case()) {\n", oneof->name()); + format.Indent(); + for (auto field : FieldRange(oneof)) { + format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); + format.Indent(); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && !ShouldIgnoreRequiredFieldCheck(field, options_) && @@ -4348,35 +4400,31 @@ GenerateIsInitialized(io::Printer* printer) { if (field->options().weak()) { // Just skip. } else { - printer->Print( - "if (has_$name$()) {\n" - " if (!this->$name$().IsInitialized()) return false;\n" - "}\n", - "name", FieldName(field)); + format( + "if (has_$1$()) {\n" + " if (!this->$1$().IsInitialized()) return false;\n" + "}\n", + FieldName(field)); } } - printer->Print( - "break;\n"); - printer->Outdent(); - printer->Print( - "}\n"); + format("break;\n"); + format.Outdent(); + format("}\n"); } - printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" + format( + "case $1$_NOT_SET: {\n" " break;\n" "}\n", - "cap_oneof_name", ToUpper(oneof->name())); - printer->Outdent(); - printer->Print( - "}\n"); + format.Outdent(); + format("}\n"); } - printer->Outdent(); - printer->Print( - " return true;\n" - "}\n"); + format.Outdent(); + format( + " return true;\n" + "}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index ca2ca2c9..170a70cd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -45,37 +45,33 @@ namespace google { namespace protobuf { - namespace io { - class Printer; // printer.h - } +namespace io { +class Printer; // printer.h } +} // namespace protobuf +} // namespace google +namespace google { namespace protobuf { namespace compiler { namespace cpp { -class EnumGenerator; // enum.h -class ExtensionGenerator; // extension.h +class EnumGenerator; // enum.h +class ExtensionGenerator; // extension.h class MessageGenerator { public: // See generator.cc for the meaning of dllexport_decl. - MessageGenerator(const Descriptor* descriptor, int index_in_file_messages, - const Options& options, SCCAnalyzer* scc_analyzer); + MessageGenerator(const Descriptor* descriptor, + const std::map<string, string>& vars, + int index_in_file_messages, const Options& options, + MessageSCCAnalyzer* scc_analyzer); ~MessageGenerator(); // Append the two types of nested generators to the corresponding vector. - void AddGenerators(std::vector<EnumGenerator*>* enum_generators, - std::vector<ExtensionGenerator*>* extension_generators); - - // Header stuff. - - // Return names for forward declarations of this class and all its nested - // types. A given key in {class,enum}_names will map from a class name to the - // descriptor that was responsible for its inclusion in the map. This can be - // used to associate the descriptor with the code generated for it. - void FillMessageForwardDeclarations( - std::map<string, const Descriptor*>* class_names); + void AddGenerators( + std::vector<std::unique_ptr<EnumGenerator>>* enum_generators, + std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators); // Generate definitions for this class and all its nested types. void GenerateClassDefinition(io::Printer* printer); @@ -112,8 +108,8 @@ class MessageGenerator { // generated. size_t GenerateParseOffsets(io::Printer* printer); size_t GenerateParseAuxTable(io::Printer* printer); - // Generates a ParseTable entry. Returns whether the proto uses table-driven - // parsing. + // Generates a ParseTable entry. Returns whether the proto uses + // table-driven parsing. bool GenerateParseTable(io::Printer* printer, size_t offset, size_t aux_offset); @@ -140,8 +136,8 @@ class MessageGenerator { void GenerateArenaDestructorCode(io::Printer* printer); // Helper for GenerateClear and others. Optionally emits a condition that - // assumes the existence of the cached_has_bits variable, and returns true if - // the condition was printed. + // assumes the existence of the cached_has_bits variable, and returns true + // if the condition was printed. bool MaybeGenerateOptionalFieldCondition(io::Printer* printer, const FieldDescriptor* field, int expected_has_bits_index); @@ -166,8 +162,7 @@ class MessageGenerator { // cached_has_bits = _has_bits_[cached_has_bit_index] // for cached_has_bit_index >= 0 void GenerateSerializeOneField(io::Printer* printer, - const FieldDescriptor* field, - bool unbounded, + const FieldDescriptor* field, bool unbounded, int cached_has_bits_index); // Generate a switch statement to serialize 2+ fields from the same oneof. // Or, if fields.size() == 1, just call GenerateSerializeOneField(). @@ -180,19 +175,15 @@ class MessageGenerator { // Generates has_foo() functions and variables for singular field has-bits. void GenerateSingularFieldHasBits(const FieldDescriptor* field, - std::map<string, string> vars, - io::Printer* printer); + Formatter format); // Generates has_foo() functions and variables for oneof field has-bits. void GenerateOneofHasBits(io::Printer* printer); // Generates has_foo_bar() functions for oneof members. void GenerateOneofMemberHasBits(const FieldDescriptor* field, - const std::map<string, string>& vars, - io::Printer* printer); + const Formatter& format); // Generates the clear_foo() method for a field. - void GenerateFieldClear(const FieldDescriptor* field, - const std::map<string, string>& vars, - bool is_inline, - io::Printer* printer); + void GenerateFieldClear(const FieldDescriptor* field, bool is_inline, + Formatter format); void GenerateConstructorBody(io::Printer* printer, std::vector<bool> already_processed, @@ -206,15 +197,16 @@ class MessageGenerator { string classname_; Options options_; FieldGeneratorMap field_generators_; - // optimized_order_ is the order we layout the message's fields in the class. - // This is reused to initialize the fields in-order for cache efficiency. + // optimized_order_ is the order we layout the message's fields in the + // class. This is reused to initialize the fields in-order for cache + // efficiency. // // optimized_order_ excludes oneof fields and weak fields. - std::vector<const FieldDescriptor *> optimized_order_; + std::vector<const FieldDescriptor*> optimized_order_; std::vector<int> has_bit_indices_; int max_has_bit_index_; - std::unique_ptr<std::unique_ptr<EnumGenerator> []> enum_generators_; - std::unique_ptr<std::unique_ptr<ExtensionGenerator> []> extension_generators_; + std::vector<const EnumGenerator*> enum_generators_; + std::vector<const ExtensionGenerator*> extension_generators_; int num_required_fields_; int num_weak_fields_; // table_driven_ indicates the generated message uses table-driven parsing. @@ -222,8 +214,9 @@ class MessageGenerator { std::unique_ptr<MessageLayoutHelper> message_layout_helper_; - SCCAnalyzer* scc_analyzer_; - string scc_name_; + MessageSCCAnalyzer* scc_analyzer_; + + std::map<string, string> variables_; friend class FileGenerator; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); @@ -232,6 +225,6 @@ class MessageGenerator { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index c1e15c52..0bbf35b2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -48,7 +48,7 @@ namespace { // When we are generating code for implicit weak fields, we need to insert some // additional casts. These functions return the casted expression if // implicit_weak_field is true but otherwise return the original expression. -// Ordinarily a static_cast is enough to cast google::protobuf::MessageLite* to a class +// Ordinarily a static_cast is enough to cast proto2::MessageLite* to a class // deriving from it, but we need a reinterpret_cast in cases where the generated // message is forward-declared but its full definition is not visible. string StaticCast(const string& type, const string& expression, @@ -101,9 +101,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor, MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options, - SCCAnalyzer* scc_analyzer) - : FieldGenerator(options), - descriptor_(descriptor), + MessageSCCAnalyzer* scc_analyzer) + : FieldGenerator(descriptor, options), implicit_weak_field_( IsImplicitWeakField(descriptor, options, scc_analyzer)) { SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); @@ -113,364 +112,388 @@ MessageFieldGenerator::~MessageFieldGenerator() {} void MessageFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { + Formatter format(printer, variables_); if (implicit_weak_field_) { - printer->Print(variables_, "::google::protobuf::MessageLite* $name$_;\n"); + format("::$proto_ns$::MessageLite* $name$_;\n"); } else { - printer->Print(variables_, "$type$* $name$_;\n"); + format("$type$* $name$_;\n"); } } void MessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { - if (implicit_weak_field_) { - // These private accessors are used by MergeFrom and - // MergePartialFromCodedStream, and their purpose is to provide access to - // the field without creating a strong dependency on the message type. - printer->Print(variables_, - "private:\n" - "const ::google::protobuf::MessageLite& _internal_$name$() const;\n" - "::google::protobuf::MessageLite* _internal_mutable_$name$();\n" - "public:\n"); - } else { - // This inline accessor directly returns member field and is used in - // Serialize such that AFDO profile correctly captures access information to - // message fields under serialize. - printer->Print(variables_, - "private:\n" - "const $type$& _internal_$name$() const;\n" - "public:\n"); - } - printer->Print(variables_, - "$deprecated_attr$const $type$& $name$() const;\n"); - printer->Annotate("name", descriptor_); - printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n"); - printer->Annotate("release_name", descriptor_); - printer->Print(variables_, - "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$set_allocated_$name$$}$" - "($type$* $name$);\n"); - printer->Annotate("{", "}", descriptor_); + Formatter format(printer, variables_); + format( + "$deprecated_attr$const $type$& ${1$$name$$}$() const;\n" + "$deprecated_attr$$type$* ${1$$release_name$$}$();\n" + "$deprecated_attr$$type$* ${1$mutable_$name$$}$();\n" + "$deprecated_attr$void ${1$set_allocated_$name$$}$" + "($type$* $name$);\n", + descriptor_); if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "$deprecated_attr$void " - "${$unsafe_arena_set_allocated_$name$$}$(\n" - " $type$* $name$);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); + format( + "$deprecated_attr$void " + "${1$unsafe_arena_set_allocated_$name$$}$(\n" + " $type$* $name$);\n" + "$deprecated_attr$$type$* ${1$unsafe_arena_release_$name$$}$();\n", + descriptor_); } } void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( io::Printer* printer) const { - if (implicit_weak_field_) { - printer->Print(variables_, - "const ::google::protobuf::MessageLite& $classname$::_internal_$name$() const {\n" - " if ($name$_ != NULL) {\n" - " return *$name$_;\n" - " } else if (&$type_default_instance$ != NULL) {\n" - " return *reinterpret_cast<const ::google::protobuf::MessageLite*>(\n" - " &$type_default_instance$);\n" - " } else {\n" - " return " - "*::google::protobuf::internal::ImplicitWeakMessage::default_instance();\n" - " }\n" - "}\n"); - } + Formatter format(printer, variables_); if (SupportsArenas(descriptor_)) { - if (implicit_weak_field_) { - printer->Print(variables_, - "::google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n" - " $set_hasbit$\n" - " if ($name$_ == NULL) {\n" - " if (&$type_default_instance$ == NULL) {\n" - " $name$_ = ::google::protobuf::Arena::CreateMessage<\n" - " ::google::protobuf::internal::ImplicitWeakMessage>(\n" - " GetArenaNoVirtual());\n" - " } else {\n" - " $name$_ = reinterpret_cast<const ::google::protobuf::MessageLite*>(\n" - " &$type_default_instance$)->New(GetArenaNoVirtual());\n" - " }\n" + format( + "void $classname$::unsafe_arena_set_allocated_$name$(\n" + " $type$* $name$) {\n" + // If we're not on an arena, free whatever we were holding before. + // (If we are on arena, we can just forget the earlier pointer.) + " if (GetArenaNoVirtual() == NULL) {\n" + " delete $name$_;\n" " }\n" - " return $name$_;\n" - "}\n"); - } - - printer->Print(variables_, - "void $classname$::unsafe_arena_set_allocated_$name$(\n" - " $type$* $name$) {\n" - // If we're not on an arena, free whatever we were holding before. - // (If we are on arena, we can just forget the earlier pointer.) - " if (GetArenaNoVirtual() == NULL) {\n" - " delete $name$_;\n" - " }\n" - " $name$_ = $name$;\n" - " if ($name$) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n" - " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" - ":$full_name$)\n" - "}\n"); - } else if (implicit_weak_field_) { - printer->Print(variables_, - "::google::protobuf::MessageLite* $classname$::_internal_mutable_$name$() {\n" - " $set_hasbit$\n" - " if ($name$_ == NULL) {\n" - " if (&$type_default_instance$ == NULL) {\n" - " $name$_ = new ::google::protobuf::internal::ImplicitWeakMessage;\n" - " } else {\n" - " $name$_ = reinterpret_cast<const ::google::protobuf::MessageLite*>(\n" - " &$type_default_instance$)->New();\n" - " }\n" + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" " }\n" - " return $name$_;\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated" + ":$full_name$)\n" "}\n"); } } void MessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - if (!implicit_weak_field_) { - printer->Print(variables_, - "inline const $type$& $classname$::_internal_$name$() const {\n" - " return *$field_member$;\n" + Formatter format(printer, variables_); + format( + "inline const $type$& $classname$::$name$() const {\n" + " const $type$* p = $casted_member$;\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n" + " &$type_default_instance$);\n" "}\n"); - } - printer->Print(variables_, - "inline const $type$& $classname$::$name$() const {\n" - " const $type$* p = $casted_member$;\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n" - " &$type_default_instance$);\n" - "}\n"); - - printer->Print(variables_, - "inline $type$* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" - "$type_reference_function$" - " $clear_hasbit$\n" - " $type$* temp = $casted_member$;\n"); - if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - " if (GetArenaNoVirtual() != NULL) {\n" - " temp = ::google::protobuf::internal::DuplicateIfNonNull(temp);\n" - " }\n"); - } - printer->Print(variables_, - " $name$_ = NULL;\n" - " return temp;\n" - "}\n"); - if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" - " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" + format( + "inline $type$* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" "$type_reference_function$" " $clear_hasbit$\n" - " $type$* temp = $casted_member$;\n" + " $type$* temp = $casted_member$;\n"); + if (SupportsArenas(descriptor_)) { + format( + " if (GetArenaNoVirtual() != NULL) {\n" + " temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n" + " }\n"); + } + format( " $name$_ = NULL;\n" " return temp;\n" "}\n"); + + if (SupportsArenas(descriptor_)) { + format( + "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" + " // " + "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" + "$type_reference_function$" + " $clear_hasbit$\n" + " $type$* temp = $casted_member$;\n" + " $name$_ = NULL;\n" + " return temp;\n" + "}\n"); } - printer->Print(variables_, - "inline $type$* $classname$::mutable_$name$() {\n" - " $set_hasbit$\n" - " if ($name$_ == NULL) {\n" - " auto* p = CreateMaybeMessage<$type$>(GetArenaNoVirtual());\n"); + format( + "inline $type$* $classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " if ($name$_ == NULL) {\n" + " auto* p = CreateMaybeMessage<$type$>(GetArenaNoVirtual());\n"); if (implicit_weak_field_) { - printer->Print(variables_, - " $name$_ = reinterpret_cast<::google::protobuf::MessageLite*>(p);\n"); + format(" $name$_ = reinterpret_cast<::$proto_ns$::MessageLite*>(p);\n"); } else { - printer->Print(variables_, - " $name$_ = p;\n"); + format(" $name$_ = p;\n"); } - printer->Print(variables_, - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $casted_member$;\n" - "}\n"); + format( + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $casted_member$;\n" + "}\n"); // We handle the most common case inline, and delegate less common cases to // the slow fallback function. - printer->Print(variables_, - "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" - " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n"); - printer->Print(variables_, - " if (message_arena == NULL) {\n"); + format( + "inline void $classname$::set_allocated_$name$($type$* $name$) {\n" + " ::$proto_ns$::Arena* message_arena = GetArenaNoVirtual();\n"); + format(" if (message_arena == NULL) {\n"); if (IsCrossFileMessage(descriptor_)) { - printer->Print(variables_, - " delete reinterpret_cast< ::google::protobuf::MessageLite*>($name$_);\n"); + format( + " delete reinterpret_cast< ::$proto_ns$::MessageLite*>($name$_);\n"); } else { - printer->Print(variables_, - " delete $name$_;\n"); + format(" delete $name$_;\n"); } - printer->Print(variables_, - " }\n" - " if ($name$) {\n"); + format( + " }\n" + " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type()) && IsCrossFileMessage(descriptor_)) { // We have to read the arena through the virtual method, because the type // isn't defined in this file. - printer->Print(variables_, - " ::google::protobuf::Arena* submessage_arena =\n" - " reinterpret_cast<::google::protobuf::MessageLite*>($name$)->GetArena();\n"); + format( + " ::$proto_ns$::Arena* submessage_arena =\n" + " " + "reinterpret_cast<::$proto_ns$::MessageLite*>($name$)->GetArena();\n"); } else if (!SupportsArenas(descriptor_->message_type())) { - printer->Print(variables_, - " ::google::protobuf::Arena* submessage_arena = NULL;\n"); + format(" ::$proto_ns$::Arena* submessage_arena = NULL;\n"); } else { - printer->Print(variables_, - " ::google::protobuf::Arena* submessage_arena =\n" - " ::google::protobuf::Arena::GetArena($name$);\n"); + format( + " ::$proto_ns$::Arena* submessage_arena =\n" + " ::$proto_ns$::Arena::GetArena($name$);\n"); } - printer->Print(variables_, - " if (message_arena != submessage_arena) {\n" - " $name$ = ::google::protobuf::internal::GetOwnedMessage(\n" - " message_arena, $name$, submessage_arena);\n" - " }\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n"); + format( + " if (message_arena != submessage_arena) {\n" + " $name$ = ::$proto_ns$::internal::GetOwnedMessage(\n" + " message_arena, $name$, submessage_arena);\n" + " }\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n"); if (implicit_weak_field_) { - printer->Print(variables_, - " $name$_ = reinterpret_cast<MessageLite*>($name$);\n"); + format(" $name$_ = reinterpret_cast<MessageLite*>($name$);\n"); + } else { + format(" $name$_ = $name$;\n"); + } + format( + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateInternalAccessorDeclarations(io::Printer* printer) const { + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format( + "static const ::$proto_ns$::MessageLite& $name$(" + "const $classname$* msg);\n" + "static ::$proto_ns$::MessageLite* mutable_$name$(" + "$classname$* msg);\n"); + } else { + format("static const $type$& $name$(const $classname$* msg);\n"); + } +} + +void MessageFieldGenerator:: +GenerateInternalAccessorDefinitions(io::Printer* printer) const { + // In theory, these accessors could be inline in HasBitSetters. However, in + // practice, the linker is then not able to throw them out making implicit + // weak dependencies not work at all. + Formatter format(printer, variables_); + if (implicit_weak_field_) { + // These private accessors are used by MergeFrom and + // MergePartialFromCodedStream, and their purpose is to provide access to + // the field without creating a strong dependency on the message type. + format( + "const ::$proto_ns$::MessageLite& $classname$::HasBitSetters::$name$(\n" + " const $classname$* msg) {\n" + " if (msg->$name$_ != NULL) {\n" + " return *msg->$name$_;\n" + " } else if (&$type_default_instance$ != NULL) {\n" + " return *reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n" + " &$type_default_instance$);\n" + " } else {\n" + " return " + "*::$proto_ns$::internal::ImplicitWeakMessage::default_instance();\n" + " }\n" + "}\n"); + if (SupportsArenas(descriptor_)) { + format( + "::$proto_ns$::MessageLite*\n" + "$classname$::HasBitSetters::mutable_$name$($classname$* msg) {\n"); + if (HasFieldPresence(descriptor_->file())) { + format(" msg->$set_hasbit$\n"); + } + format( + " if (msg->$name$_ == NULL) {\n" + " if (&$type_default_instance$ == NULL) {\n" + " msg->$name$_ = ::$proto_ns$::Arena::CreateMessage<\n" + " ::$proto_ns$::internal::ImplicitWeakMessage>(\n" + " msg->GetArenaNoVirtual());\n" + " } else {\n" + " msg->$name$_ = reinterpret_cast<const " + "::$proto_ns$::MessageLite*>(\n" + " &$type_default_instance$)->New(" + "msg->GetArenaNoVirtual());\n" + " }\n" + " }\n" + " return msg->$name$_;\n" + "}\n"); + } else { + format( + "::$proto_ns$::MessageLite*\n" + "$classname$::HasBitSetters::mutable_$name$($classname$* msg) {\n"); + if (HasFieldPresence(descriptor_->file())) { + format(" msg->$set_hasbit$\n"); + } + format( + " if (msg->$name$_ == NULL) {\n" + " if (&$type_default_instance$ == NULL) {\n" + " msg->$name$_ = " + "new ::$proto_ns$::internal::ImplicitWeakMessage;\n" + " } else {\n" + " msg->$name$_ = " + "reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n" + " &$type_default_instance$)->New();\n" + " }\n" + " }\n" + " return msg->$name$_;\n" + "}\n"); + } } else { - printer->Print(variables_, - " $name$_ = $name$;\n"); + // This inline accessor directly returns member field and is used in + // Serialize such that AFDO profile correctly captures access information to + // message fields under serialize. + format( + "const $type$&\n" + "$classname$::HasBitSetters::$name$(const $classname$* msg) {\n" + " return *msg->$field_member$;\n" + "}\n"); } - printer->Print(variables_, - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n"); } void MessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (!HasFieldPresence(descriptor_->file())) { // If we don't have has-bits, message presence is indicated only by ptr != // NULL. Thus on clear, we need to delete the object. - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) {\n" - " delete $name$_;\n" - "}\n" - "$name$_ = NULL;\n"); + format( + "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) {\n" + " delete $name$_;\n" + "}\n" + "$name$_ = NULL;\n"); } else { - printer->Print(variables_, - "if ($name$_ != NULL) $name$_->Clear();\n"); + format("if ($name$_ != NULL) $name$_->Clear();\n"); } } void MessageFieldGenerator:: GenerateMessageClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (!HasFieldPresence(descriptor_->file())) { // If we don't have has-bits, message presence is indicated only by ptr != // NULL. Thus on clear, we need to delete the object. - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) {\n" - " delete $name$_;\n" - "}\n" - "$name$_ = NULL;\n"); + format( + "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) {\n" + " delete $name$_;\n" + "}\n" + "$name$_ = NULL;\n"); } else { - printer->Print(variables_, - "GOOGLE_DCHECK($name$_ != NULL);\n" - "$name$_->Clear();\n"); + format( + "$DCHK$($name$_ != NULL);\n" + "$name$_->Clear();\n"); } } void MessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (implicit_weak_field_) { - printer->Print(variables_, - "_internal_mutable_$name$()->CheckTypeAndMergeFrom(\n" - " from._internal_$name$());\n"); + format( + "HasBitSetters::mutable_$name$(this)->CheckTypeAndMergeFrom(\n" + " HasBitSetters::$name$(&from));\n"); } else { - printer->Print(variables_, - "mutable_$name$()->$type$::MergeFrom(from.$name$());\n"); + format("mutable_$name$()->$type$::MergeFrom(from.$name$());\n"); } } void MessageFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "swap($name$_, other->$name$_);\n"); + Formatter format(printer, variables_); + format("swap($name$_, other->$name$_);\n"); } void MessageFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { - // TODO(gerbens) Remove this when we don't need to destruct default instances. - // In google3 a default instance will never get deleted so we don't need to - // worry about that but in opensource protobuf default instances are deleted - // in shutdown process and we need to take special care when handling them. - printer->Print(variables_, - "if (this != internal_default_instance()) "); - printer->Print(variables_, "delete $name$_;\n"); + Formatter format(printer, variables_); + if (options_.opensource_runtime) { + // TODO(gerbens) Remove this when we don't need to destruct default + // instances. In google3 a default instance will never get deleted so we + // don't need to worry about that but in opensource protobuf default + // instances are deleted in shutdown process and we need to take special + // care when handling them. + format("if (this != internal_default_instance()) "); + } + format("delete $name$_;\n"); } void MessageFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = NULL;\n"); + Formatter format(printer, variables_); + format("$name$_ = NULL;\n"); } void MessageFieldGenerator:: GenerateCopyConstructorCode(io::Printer* printer) const { - printer->Print(variables_, - "if (from.has_$name$()) {\n" - " $name$_ = new $type$(*from.$name$_);\n" - "} else {\n" - " $name$_ = NULL;\n" - "}\n"); + Formatter format(printer, variables_); + format( + "if (from.has_$name$()) {\n" + " $name$_ = new $type$(*from.$name$_);\n" + "} else {\n" + " $name$_ = NULL;\n" + "}\n"); } void MessageFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { + Formatter format(printer, variables_); if (implicit_weak_field_) { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(\n" - " input, _internal_mutable_$name$()));\n"); + format( + "DO_(::$proto_ns$::internal::WireFormatLite::ReadMessage(\n" + " input, HasBitSetters::mutable_$name$(this)));\n"); } else if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(\n" - " input, mutable_$name$()));\n"); + format( + "DO_(::$proto_ns$::internal::WireFormatLite::ReadMessage(\n" + " input, mutable_$name$()));\n"); } else { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::ReadGroup(\n" - " $number$, input, mutable_$name$()));\n"); + format( + "DO_(::$proto_ns$::internal::WireFormatLite::ReadGroup(\n" + " $number$, input, mutable_$name$()));\n"); } } void MessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - printer->Print(variables_, - "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" - " $number$, this->_internal_$name$(), output);\n"); + Formatter format(printer, variables_); + format( + "::$proto_ns$::internal::WireFormatLite::Write$stream_writer$(\n" + " $number$, HasBitSetters::$name$(this), output);\n"); } void MessageFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - printer->Print(variables_, - "target = ::google::protobuf::internal::WireFormatLite::\n" - " InternalWrite$declared_type$ToArray(\n" - " $number$, this->_internal_$name$(), deterministic, target);\n"); + Formatter format(printer, variables_); + format( + "target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$ToArray(\n" + " $number$, HasBitSetters::$name$(this), deterministic, target);\n"); } void MessageFieldGenerator:: GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, - "total_size += $tag_size$ +\n" - " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" - " *$field_member$);\n"); + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " *$field_member$);\n"); } // =================================================================== MessageOneofFieldGenerator::MessageOneofFieldGenerator( const FieldDescriptor* descriptor, const Options& options, - SCCAnalyzer* scc_analyzer) + MessageSCCAnalyzer* scc_analyzer) : MessageFieldGenerator(descriptor, options, scc_analyzer) { SetCommonOneofFieldVariables(descriptor, &variables_); } @@ -479,126 +502,122 @@ MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions( io::Printer* printer) const { - printer->Print(variables_, - "void $classname$::set_allocated_$name$($type$* $name$) {\n" - " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n" - " clear_$oneof_name$();\n" - " if ($name$) {\n"); + Formatter format(printer, variables_); + format( + "void $classname$::set_allocated_$name$($type$* $name$) {\n" + " ::$proto_ns$::Arena* message_arena = GetArenaNoVirtual();\n" + " clear_$oneof_name$();\n" + " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type()) && descriptor_->file() != descriptor_->message_type()->file()) { // We have to read the arena through the virtual method, because the type // isn't defined in this file. - printer->Print(variables_, - " ::google::protobuf::Arena* submessage_arena =\n" - " reinterpret_cast<::google::protobuf::MessageLite*>($name$)->GetArena();\n"); + format( + " ::$proto_ns$::Arena* submessage_arena =\n" + " " + "reinterpret_cast<::$proto_ns$::MessageLite*>($name$)->GetArena();\n"); } else if (!SupportsArenas(descriptor_->message_type())) { - printer->Print(variables_, - " ::google::protobuf::Arena* submessage_arena = NULL;\n"); + format(" ::$proto_ns$::Arena* submessage_arena = NULL;\n"); } else { - printer->Print(variables_, - " ::google::protobuf::Arena* submessage_arena =\n" - " ::google::protobuf::Arena::GetArena($name$);\n"); + format( + " ::$proto_ns$::Arena* submessage_arena =\n" + " ::$proto_ns$::Arena::GetArena($name$);\n"); } - printer->Print(variables_, - " if (message_arena != submessage_arena) {\n" - " $name$ = ::google::protobuf::internal::GetOwnedMessage(\n" - " message_arena, $name$, submessage_arena);\n" - " }\n" - " set_has_$name$();\n" - " $field_member$ = $name$;\n" - " }\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n"); + format( + " if (message_arena != submessage_arena) {\n" + " $name$ = ::$proto_ns$::internal::GetOwnedMessage(\n" + " message_arena, $name$, submessage_arena);\n" + " }\n" + " set_has_$name$();\n" + " $field_member$ = $name$;\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); } void MessageOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - if (!implicit_weak_field_) { - printer->Print(variables_, - "inline const $type$& $classname$::_internal_$name$() const {\n" - " return *$field_member$;\n" - "}\n"); - } - printer->Print(variables_, - "inline $type$* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " $type$* temp = $field_member$;\n"); - if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - " if (GetArenaNoVirtual() != NULL) {\n" - " temp = ::google::protobuf::internal::DuplicateIfNonNull(temp);\n" - " }\n"); - } - printer->Print(variables_, - " $field_member$ = NULL;\n" - " return temp;\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n"); - - printer->Print(variables_, - "inline const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return has_$name$()\n" - " ? *$field_member$\n" - " : *reinterpret_cast< $type$*>(&$type_default_instance$);\n" - "}\n"); - - if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" - " // @@protoc_insertion_point(field_unsafe_arena_release" - ":$full_name$)\n" + Formatter format(printer, variables_); + format( + "inline $type$* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" - " $type$* temp = $field_member$;\n" + " $type$* temp = $field_member$;\n"); + if (SupportsArenas(descriptor_)) { + format( + " if (GetArenaNoVirtual() != NULL) {\n" + " temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n" + " }\n"); + } + format( " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" " return NULL;\n" " }\n" - "}\n" - "inline void $classname$::unsafe_arena_set_allocated_$name$" - "($type$* $name$) {\n" - // We rely on the oneof clear method to free the earlier contents of this - // oneof. We can directly use the pointer we're given to set the new - // value. - " clear_$oneof_name$();\n" - " if ($name$) {\n" - " set_has_$name$();\n" - " $field_member$ = $name$;\n" - " }\n" - " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" - "$full_name$)\n" "}\n"); + + format( + "inline const $type$& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return has_$name$()\n" + " ? *$field_member$\n" + " : *reinterpret_cast< $type$*>(&$type_default_instance$);\n" + "}\n"); + + if (SupportsArenas(descriptor_)) { + format( + "inline $type$* $classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(field_unsafe_arena_release" + ":$full_name$)\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " $type$* temp = $field_member$;\n" + " $field_member$ = NULL;\n" + " return temp;\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "inline void $classname$::unsafe_arena_set_allocated_$name$" + "($type$* $name$) {\n" + // We rely on the oneof clear method to free the earlier contents of + // this oneof. We can directly use the pointer we're given to set the + // new value. + " clear_$oneof_name$();\n" + " if ($name$) {\n" + " set_has_$name$();\n" + " $field_member$ = $name$;\n" + " }\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" + "}\n"); } - printer->Print(variables_, - "inline $type$* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $field_member$ = CreateMaybeMessage< $type$ >(\n" - " GetArenaNoVirtual());\n" - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $field_member$;\n" - "}\n"); + format( + "inline $type$* $classname$::mutable_$name$() {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$ = CreateMaybeMessage< $type$ >(\n" + " GetArenaNoVirtual());\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $field_member$;\n" + "}\n"); } void MessageOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL) {\n" - " delete $field_member$;\n" - "}\n"); + format( + "if (GetArenaNoVirtual() == NULL) {\n" + " delete $field_member$;\n" + "}\n"); } else { - printer->Print(variables_, - "delete $field_member$;\n"); + format("delete $field_member$;\n"); } } @@ -628,9 +647,8 @@ GenerateConstructorCode(io::Printer* printer) const { RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( const FieldDescriptor* descriptor, const Options& options, - SCCAnalyzer* scc_analyzer) - : FieldGenerator(options), - descriptor_(descriptor), + MessageSCCAnalyzer* scc_analyzer) + : FieldGenerator(descriptor, options), implicit_weak_field_( IsImplicitWeakField(descriptor, options, scc_analyzer)) { SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); @@ -640,108 +658,101 @@ RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} void RepeatedMessageFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, - "::google::protobuf::RepeatedPtrField< $type$ > $name$_;\n"); + Formatter format(printer, variables_); + format("::$proto_ns$::RepeatedPtrField< $type$ > $name$_;\n"); } void RepeatedMessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { - printer->Print(variables_, - "$deprecated_attr$$type$* ${$mutable_$name$$}$(int index);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n" - " ${$mutable_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); - - printer->Print(variables_, - "$deprecated_attr$const $type$& $name$(int index) const;\n"); - printer->Annotate("name", descriptor_); - printer->Print(variables_, "$deprecated_attr$$type$* ${$add_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const;\n"); - printer->Annotate("name", descriptor_); + Formatter format(printer, variables_); + format( + "$deprecated_attr$$type$* ${1$mutable_$name$$}$(int index);\n" + "$deprecated_attr$::$proto_ns$::RepeatedPtrField< $type$ >*\n" + " ${1$mutable_$name$$}$();\n" + "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n" + "$deprecated_attr$$type$* ${1$add_$name$$}$();\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n" + " ${1$$name$$}$() const;\n", + descriptor_); } void RepeatedMessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$* $classname$::mutable_$name$(int index) {\n" - // TODO(dlj): move insertion points - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - "$type_reference_function$" - " return $name$_.Mutable(index);\n" - "}\n" - "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" - " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - "$type_reference_function$" - " return &$name$_;\n" - "}\n"); + Formatter format(printer, variables_); + format( + "inline $type$* $classname$::mutable_$name$(int index) {\n" + // TODO(dlj): move insertion points + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + "$type_reference_function$" + " return $name$_.Mutable(index);\n" + "}\n" + "inline ::$proto_ns$::RepeatedPtrField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + "$type_reference_function$" + " return &$name$_;\n" + "}\n"); if (options_.safe_boundary_check) { - printer->Print(variables_, - "inline const $type$& $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.InternalCheckedGet(index,\n" - " *reinterpret_cast<const $type$*>(&$type_default_instance$));\n" - "}\n"); + format( + "inline const $type$& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.InternalCheckedGet(index,\n" + " *reinterpret_cast<const $type$*>(&$type_default_instance$));\n" + "}\n"); } else { - printer->Print(variables_, - "inline const $type$& $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - "$type_reference_function$" - " return $name$_.Get(index);\n" - "}\n"); + format( + "inline const $type$& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + "$type_reference_function$" + " return $name$_.Get(index);\n" + "}\n"); } - printer->Print(variables_, - "inline $type$* $classname$::add_$name$() {\n" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - " return $name$_.Add();\n" - "}\n"); + format( + "inline $type$* $classname$::add_$name$() {\n" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + " return $name$_.Add();\n" + "}\n"); - printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - "$classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - "$type_reference_function$" - " return $name$_;\n" - "}\n"); + format( + "inline const ::$proto_ns$::RepeatedPtrField< $type$ >&\n" + "$classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + "$type_reference_function$" + " return $name$_;\n" + "}\n"); } void RepeatedMessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (implicit_weak_field_) { - printer->Print( - variables_, + format( "CastToBase(&$name$_)->Clear<" - "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>();\n"); + "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>();\n"); } else { - printer->Print(variables_, "$name$_.Clear();\n"); + format("$name$_.Clear();\n"); } } void RepeatedMessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (implicit_weak_field_) { - printer->Print( - variables_, + format( "CastToBase(&$name$_)->MergeFrom<" - "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>(CastToBase(" + "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>(CastToBase(" "from.$name$_));\n"); } else { - printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); + format("$name$_.MergeFrom(from.$name$_);\n"); } } void RepeatedMessageFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print( - variables_, - "CastToBase(&$name$_)->InternalSwap(CastToBase(&other->$name$_));\n"); + Formatter format(printer, variables_); + format("CastToBase(&$name$_)->InternalSwap(CastToBase(&other->$name$_));\n"); } void RepeatedMessageFieldGenerator:: @@ -751,83 +762,85 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { + Formatter format(printer, variables_); if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { if (implicit_weak_field_) { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::" - "ReadMessage(input, CastToBase(&$name$_)->AddWeak(\n" - " reinterpret_cast<const ::google::protobuf::MessageLite*>(\n" - " &$type_default_instance$))));\n"); + format( + "DO_(::$proto_ns$::internal::WireFormatLite::" + "ReadMessage(input, CastToBase(&$name$_)->AddWeak(\n" + " reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n" + " &$type_default_instance$))));\n"); } else { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::" - "ReadMessage(\n" - " input, add_$name$()));\n"); + format( + "DO_(::$proto_ns$::internal::WireFormatLite::" + "ReadMessage(\n" + " input, add_$name$()));\n"); } } else { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::" - "ReadGroup($number$, input, add_$name$()));\n"); + format( + "DO_(::$proto_ns$::internal::WireFormatLite::" + "ReadGroup($number$, input, add_$name$()));\n"); } } void RepeatedMessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - printer->Print(variables_, - "for (unsigned int i = 0,\n" - " n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n" - " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" - " $number$,\n"); + Formatter format(printer, variables_); + format( + "for (unsigned int i = 0,\n" + " n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n" + " ::$proto_ns$::internal::WireFormatLite::Write$stream_writer$(\n" + " $number$,\n"); if (implicit_weak_field_) { - printer->Print( - variables_, + format( " CastToBase($name$_).Get<" - "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>(" + "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>(" "static_cast<int>(i)),\n"); } else { - printer->Print(variables_, - " this->$name$(static_cast<int>(i)),\n"); + format(" this->$name$(static_cast<int>(i)),\n"); } - printer->Print(variables_, - " output);\n" - "}\n"); + format( + " output);\n" + "}\n"); } void RepeatedMessageFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - printer->Print(variables_, - "for (unsigned int i = 0,\n" - " n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n" - " target = ::google::protobuf::internal::WireFormatLite::\n" - " InternalWrite$declared_type$ToArray(\n" - " $number$, this->$name$(static_cast<int>(i)), deterministic, target);\n" - "}\n"); + Formatter format(printer, variables_); + format( + "for (unsigned int i = 0,\n" + " n = static_cast<unsigned int>(this->$name$_size()); i < n; i++) {\n" + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$ToArray(\n" + " $number$, this->$name$(static_cast<int>(i)), deterministic, " + "target);\n" + "}\n"); } void RepeatedMessageFieldGenerator:: GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, - "{\n" - " unsigned int count = static_cast<unsigned int>(this->$name$_size());\n"); - printer->Indent(); - printer->Print(variables_, - "total_size += $tag_size$UL * count;\n" - "for (unsigned int i = 0; i < count; i++) {\n" - " total_size +=\n" - " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"); + Formatter format(printer, variables_); + format( + "{\n" + " unsigned int count = static_cast<unsigned " + "int>(this->$name$_size());\n"); + format.Indent(); + format( + "total_size += $tag_size$UL * count;\n" + "for (unsigned int i = 0; i < count; i++) {\n" + " total_size +=\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"); if (implicit_weak_field_) { - printer->Print( - variables_, + format( " CastToBase($name$_).Get<" - "::google::protobuf::internal::ImplicitWeakTypeHandler<$type$>>(" + "::$proto_ns$::internal::ImplicitWeakTypeHandler<$type$>>(" "static_cast<int>(i)));\n"); } else { - printer->Print(variables_, - " this->$name$(static_cast<int>(i)));\n"); + format(" this->$name$(static_cast<int>(i)));\n"); } - printer->Print(variables_, "}\n"); - printer->Outdent(); - printer->Print("}\n"); + format("}\n"); + format.Outdent(); + format("}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 6879539c..eed8e4f5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -48,7 +48,8 @@ namespace cpp { class MessageFieldGenerator : public FieldGenerator { public: MessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options, SCCAnalyzer* scc_analyzer); + const Options& options, + MessageSCCAnalyzer* scc_analyzer); ~MessageFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -56,6 +57,8 @@ class MessageFieldGenerator : public FieldGenerator { 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; @@ -69,9 +72,7 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; protected: - const FieldDescriptor* descriptor_; const bool implicit_weak_field_; - std::map<string, string> variables_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); @@ -80,7 +81,8 @@ class MessageFieldGenerator : public FieldGenerator { class MessageOneofFieldGenerator : public MessageFieldGenerator { public: MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options, SCCAnalyzer* scc_analyzer); + const Options& options, + MessageSCCAnalyzer* scc_analyzer); ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -103,7 +105,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { public: RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options, - SCCAnalyzer* scc_analyzer); + MessageSCCAnalyzer* scc_analyzer); ~RepeatedMessageFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -121,9 +123,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; private: - const FieldDescriptor* descriptor_; const bool implicit_weak_field_; - std::map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); }; @@ -131,6 +131,6 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h b/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h index d502a6f0..67eeff0a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h @@ -56,6 +56,6 @@ class MessageLayoutHelper { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index f09885be..6a364deb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -45,39 +45,28 @@ namespace cpp { // Generator options (see generator.cc for a description of each): struct Options { - Options() - : safe_boundary_check(false), - proto_h(false), - transitive_pb_h(true), - annotate_headers(false), - enforce_lite(false), - table_driven_parsing(false), - table_driven_serialization(false), - lite_implicit_weak_fields(false), - bootstrap(false), - num_cc_files(0), - access_info_map(NULL) {} - string dllexport_decl; - bool safe_boundary_check; - bool proto_h; - bool transitive_pb_h; - bool annotate_headers; - bool enforce_lite; - bool table_driven_parsing; - bool table_driven_serialization; - bool lite_implicit_weak_fields; - bool bootstrap; - int num_cc_files; + bool safe_boundary_check = false; + bool proto_h = false; + bool transitive_pb_h = true; + bool annotate_headers = false; + bool enforce_lite = false; + bool table_driven_parsing = false; + bool table_driven_serialization = false; + bool lite_implicit_weak_fields = false; + bool bootstrap = false; + bool opensource_runtime = false; + bool opensource_include_paths = false; + int num_cc_files = 0; string annotation_pragma_name; string annotation_guard_name; - const AccessInfoMap* access_info_map; + const AccessInfoMap* access_info_map = nullptr; }; } // namespace cpp } // namespace compiler } // namespace protobuf +} // namespace google -} // namespace google #endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc index e9303865..2f78bda5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc +++ b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc @@ -106,6 +106,8 @@ class FieldGroup { // STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and // calls ArenaStringPtr::Destroy on each. // +// LAZY_MESSAGE is grouped next, as it interferes with the ability to memset +// non-repeated fields otherwise. // // MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls // delete on each. We initialize these fields with a NULL pointer (see @@ -122,6 +124,9 @@ void PaddingOptimizer::OptimizeLayout( enum Family { REPEATED = 0, STRING = 1, + // Laying out LAZY_MESSAGE before MESSAGE allows a single memset to zero + // MESSAGE and ZERO_INITIALIZABLE fields together. + LAZY_MESSAGE = 2, MESSAGE = 3, ZERO_INITIALIZABLE = 4, OTHER = 5, @@ -142,7 +147,9 @@ void PaddingOptimizer::OptimizeLayout( f = STRING; } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { f = MESSAGE; - + if (IsLazy(field, options)) { + f = LAZY_MESSAGE; + } } else if (CanInitializeByZeroing(field)) { f = ZERO_INITIALIZABLE; } diff --git a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h index 42a3b5cd..2382081b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h +++ b/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h @@ -59,6 +59,6 @@ class PaddingOptimizer : public MessageLayoutHelper { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc index ff6ba0f8..4f8a23ed 100644 --- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc @@ -219,7 +219,7 @@ TEST(CppPluginTest, PluginTest) { "}\n", true)); - google::protobuf::compiler::CommandLineInterface cli; + CommandLineInterface cli; cli.SetInputsAreProtoPathRelative(true); CppGenerator cpp_generator; diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 701f9d2d..2f6a0504 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -83,16 +83,16 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, std::map<string, string>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); - (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type()); - (*variables)["default"] = DefaultValue(descriptor); - (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + (*variables)["type"] = PrimitiveTypeName(options, descriptor->cpp_type()); + (*variables)["default"] = DefaultValue(options, descriptor); + (*variables)["tag"] = + SimpleItoa(internal::WireFormat::MakeTag(descriptor)); int fixed_size = FixedSize(descriptor->type()); if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } - (*variables)["wire_format_field_type"] = - "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name( - static_cast<FieldDescriptorProto_Type>(descriptor->type())); + (*variables)["wire_format_field_type"] = FieldDescriptorProto_Type_Name( + static_cast<FieldDescriptorProto_Type>(descriptor->type())); (*variables)["full_name"] = descriptor->full_name(); } @@ -102,7 +102,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, PrimitiveFieldGenerator::PrimitiveFieldGenerator( const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), descriptor_(descriptor) { + : FieldGenerator(descriptor, options) { SetPrimitiveVariables(descriptor, &variables_, options); } @@ -110,91 +110,103 @@ PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} void PrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, "$type$ $name$_;\n"); + Formatter format(printer, variables_); + format("$type$ $name$_;\n"); } void PrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { - printer->Print(variables_, "$deprecated_attr$$type$ $name$() const;\n"); - printer->Annotate("name", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$set_$name$$}$($type$ value);\n"); - printer->Annotate("{", "}", descriptor_); + Formatter format(printer, variables_); + format( + "$deprecated_attr$$type$ ${1$$name$$}$() const;\n" + "$deprecated_attr$void ${1$set_$name$$}$($type$ value);\n", + descriptor_); } void PrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_;\n" - "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" - " $set_hasbit$\n" - " $name$_ = value;\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_;\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n" + " $set_hasbit$\n" + " $name$_ = value;\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); } void PrimitiveFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = $default$;\n"); + Formatter format(printer, variables_); + format("$name$_ = $default$;\n"); } void PrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, "set_$name$(from.$name$());\n"); + Formatter format(printer, variables_); + format("set_$name$(from.$name$());\n"); } void PrimitiveFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "swap($name$_, other->$name$_);\n"); + Formatter format(printer, variables_); + format("swap($name$_, other->$name$_);\n"); } void PrimitiveFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = $default$;\n"); + Formatter format(printer, variables_); + format("$name$_ = $default$;\n"); } void PrimitiveFieldGenerator:: GenerateCopyConstructorCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_ = from.$name$_;\n"); + Formatter format(printer, variables_); + format("$name$_ = from.$name$_;\n"); } void PrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "$set_hasbit$\n" - "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" - " $type$, $wire_format_field_type$>(\n" - " input, &$name$_)));\n"); + Formatter format(printer, variables_); + format( + "$set_hasbit_io$\n" + "DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n" + " $type$, " + "::$proto_ns$::internal::WireFormatLite::$wire_format_field_type$>(\n" + " input, &$name$_)));\n"); } void PrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - printer->Print(variables_, - "::google::protobuf::internal::WireFormatLite::Write$declared_type$(" + Formatter format(printer, variables_); + format( + "::$proto_ns$::internal::WireFormatLite::Write$declared_type$(" "$number$, this->$name$(), output);\n"); } void PrimitiveFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - printer->Print(variables_, - "target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(" + Formatter format(printer, variables_); + format( + "target = " + "::$proto_ns$::internal::WireFormatLite::Write$declared_type$ToArray(" "$number$, this->$name$(), target);\n"); } void PrimitiveFieldGenerator:: GenerateByteSize(io::Printer* printer) const { + Formatter format(printer, variables_); int fixed_size = FixedSize(descriptor_->type()); if (fixed_size == -1) { - printer->Print(variables_, - "total_size += $tag_size$ +\n" - " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" - " this->$name$());\n"); + format( + "total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " this->$name$());\n"); } else { - printer->Print(variables_, - "total_size += $tag_size$ + $fixed_size$;\n"); + format("total_size += $tag_size$ + $fixed_size$;\n"); } } @@ -211,27 +223,29 @@ PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} void PrimitiveOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " if (has_$name$()) {\n" - " return $field_member$;\n" - " }\n" - " return $default$;\n" - "}\n" - "inline void $classname$::set_$name$($type$ value) {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " }\n" - " $field_member$ = value;\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n"); + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " if (has_$name$()) {\n" + " return $field_member$;\n" + " }\n" + " return $default$;\n" + "}\n" + "inline void $classname$::set_$name$($type$ value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " }\n" + " $field_member$ = value;\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); } void PrimitiveOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$field_member$ = $default$;\n"); + Formatter format(printer, variables_); + format("$field_member$ = $default$;\n"); } void PrimitiveOneofFieldGenerator:: @@ -241,25 +255,27 @@ GenerateSwappingCode(io::Printer* printer) const { void PrimitiveOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - printer->Print(variables_, - "$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); + Formatter format(printer, variables_); + format("$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); } void PrimitiveOneofFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "clear_$oneof_name$();\n" - "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" - " $type$, $wire_format_field_type$>(\n" - " input, &$field_member$)));\n" - "set_has_$name$();\n"); + Formatter format(printer, variables_); + format( + "clear_$oneof_name$();\n" + "DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n" + " $type$, " + "::$proto_ns$::internal::WireFormatLite::$wire_format_field_type$>(\n" + " input, &$field_member$)));\n" + "set_has_$name$();\n"); } // =================================================================== RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), descriptor_(descriptor) { + : FieldGenerator(descriptor, options) { SetPrimitiveVariables(descriptor, &variables_, options); if (descriptor->is_packed()) { @@ -275,77 +291,72 @@ RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} void RepeatedPrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, - "::google::protobuf::RepeatedField< $type$ > $name$_;\n"); + Formatter format(printer, variables_); + format("::$proto_ns$::RepeatedField< $type$ > $name$_;\n"); if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file(), options_)) { - printer->Print(variables_, - "mutable int _$name$_cached_byte_size_;\n"); + format("mutable std::atomic<int> _$name$_cached_byte_size_;\n"); } } void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { - printer->Print(variables_, - "$deprecated_attr$$type$ $name$(int index) const;\n"); - printer->Annotate("name", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$void ${$set_$name$$}$(int index, $type$ value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$add_$name$$}$($type$ value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n" - " $name$() const;\n"); - printer->Annotate("name", descriptor_); - printer->Print(variables_, - "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n" - " ${$mutable_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); + Formatter format(printer, variables_); + format( + "$deprecated_attr$$type$ ${1$$name$$}$(int index) const;\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, $type$ value);\n" + "$deprecated_attr$void ${1$add_$name$$}$($type$ value);\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedField< $type$ >&\n" + " ${1$$name$$}$() const;\n" + "$deprecated_attr$::$proto_ns$::RepeatedField< $type$ >*\n" + " ${1$mutable_$name$$}$();\n", + descriptor_); } void RepeatedPrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { - printer->Print(variables_, - "inline $type$ $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.Get(index);\n" - "}\n" - "inline void $classname$::set_$name$(int index, $type$ value) {\n" - " $name$_.Set(index, value);\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "inline void $classname$::add_$name$($type$ value) {\n" - " $name$_.Add(value);\n" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n" - "inline const ::google::protobuf::RepeatedField< $type$ >&\n" - "$classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" - " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$name$_;\n" - "}\n"); + Formatter format(printer, variables_); + format( + "inline $type$ $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.Get(index);\n" + "}\n" + "inline void $classname$::set_$name$(int index, $type$ value) {\n" + " $name$_.Set(index, value);\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline void $classname$::add_$name$($type$ value) {\n" + " $name$_.Add(value);\n" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + "}\n" + "inline const ::$proto_ns$::RepeatedField< $type$ >&\n" + "$classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $name$_;\n" + "}\n" + "inline ::$proto_ns$::RepeatedField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return &$name$_;\n" + "}\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.InternalSwap(&other->$name$_);\n"); + Formatter format(printer, variables_); + format("$name$_.InternalSwap(&other->$name$_);\n"); } void RepeatedPrimitiveFieldGenerator:: @@ -355,124 +366,135 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateCopyConstructorCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.CopyFrom(from.$name$_);\n"); + Formatter format(printer, variables_); + format("$name$_.CopyFrom(from.$name$_);\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n" - " $type$, $wire_format_field_type$>(\n" - " $tag_size$, $tag$u, input, this->mutable_$name$())));\n"); + Formatter format(printer, variables_); + format( + "DO_((::$proto_ns$::internal::WireFormatLite::$repeated_reader$<\n" + " $type$, " + "::$proto_ns$::internal::WireFormatLite::$wire_format_field_type$>(\n" + " $tag_size$, $tag$u, input, this->mutable_$name$())));\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { - printer->Print(variables_, - "DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n" - " $type$, $wire_format_field_type$>(\n" - " input, this->mutable_$name$())));\n"); + Formatter format(printer, variables_); + format( + "DO_((::$proto_ns$::internal::WireFormatLite::$packed_reader$<\n" + " $type$, " + "::$proto_ns$::internal::WireFormatLite::$wire_format_field_type$>(\n" + " input, this->mutable_$name$())));\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { + Formatter format(printer, variables_); bool array_written = false; if (descriptor_->is_packed()) { // Write the tag and the size. - printer->Print(variables_, - "if (this->$name$_size() > 0) {\n" - " ::google::protobuf::internal::WireFormatLite::WriteTag(" - "$number$, " - "::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, " - "output);\n" - " output->WriteVarint32(static_cast< ::google::protobuf::uint32>(\n" - " _$name$_cached_byte_size_));\n"); + format( + "if (this->$name$_size() > 0) {\n" + " ::$proto_ns$::internal::WireFormatLite::WriteTag(" + "$number$, " + "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, " + "output);\n" + " output->WriteVarint32(_$name$_cached_byte_size_.load(\n" + " std::memory_order_relaxed));\n"); if (FixedSize(descriptor_->type()) > 0) { // TODO(ckennelly): Use RepeatedField<T>::unsafe_data() via // WireFormatLite to access the contents of this->$name$_ to save a branch // here. - printer->Print(variables_, - " ::google::protobuf::internal::WireFormatLite::Write$declared_type$Array(\n" - " this->$name$().data(), this->$name$_size(), output);\n"); + format( + " " + "::$proto_ns$::internal::WireFormatLite::Write$declared_type$Array(\n" + " this->$name$().data(), this->$name$_size(), output);\n"); array_written = true; // Wrote array all at once } - printer->Print(variables_, "}\n"); + format("}\n"); } if (!array_written) { - printer->Print(variables_, - "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"); + format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"); if (descriptor_->is_packed()) { - printer->Print(variables_, - " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n" - " this->$name$(i), output);\n"); + format( + " " + "::$proto_ns$::internal::WireFormatLite::Write$declared_type$NoTag(\n" + " this->$name$(i), output);\n"); } else { - printer->Print(variables_, - " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" - " $number$, this->$name$(i), output);\n"); + format( + " ::$proto_ns$::internal::WireFormatLite::Write$declared_type$(\n" + " $number$, this->$name$(i), output);\n"); } - printer->Print("}\n"); + format("}\n"); } } void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + Formatter format(printer, variables_); if (descriptor_->is_packed()) { // Write the tag and the size. - printer->Print(variables_, - "if (this->$name$_size() > 0) {\n" - " target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n" - " $number$,\n" - " ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" - " target);\n" - " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n" - " static_cast< ::google::protobuf::int32>(\n" - " _$name$_cached_byte_size_), target);\n" - " target = ::google::protobuf::internal::WireFormatLite::\n" - " Write$declared_type$NoTagToArray(this->$name$_, target);\n" - "}\n"); + format( + "if (this->$name$_size() > 0) {\n" + " target = ::$proto_ns$::internal::WireFormatLite::WriteTagToArray(\n" + " $number$,\n" + " " + "::$proto_ns$::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" + " target);\n" + " target = " + "::$proto_ns$::io::CodedOutputStream::WriteVarint32ToArray(\n" + " _$name$_cached_byte_size_.load(std::memory_order_relaxed),\n" + " target);\n" + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " Write$declared_type$NoTagToArray(this->$name$_, target);\n" + "}\n"); } else { - printer->Print(variables_, - "target = ::google::protobuf::internal::WireFormatLite::\n" - " Write$declared_type$ToArray($number$, this->$name$_, target);\n"); + format( + "target = ::$proto_ns$::internal::WireFormatLite::\n" + " Write$declared_type$ToArray($number$, this->$name$_, target);\n"); } } void RepeatedPrimitiveFieldGenerator:: GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, "{\n"); - printer->Indent(); + Formatter format(printer, variables_); + format("{\n"); + format.Indent(); int fixed_size = FixedSize(descriptor_->type()); if (fixed_size == -1) { - printer->Print(variables_, - "size_t data_size = ::google::protobuf::internal::WireFormatLite::\n" - " $declared_type$Size(this->$name$_);\n"); + format( + "size_t data_size = ::$proto_ns$::internal::WireFormatLite::\n" + " $declared_type$Size(this->$name$_);\n"); } else { - printer->Print(variables_, - "unsigned int count = static_cast<unsigned int>(this->$name$_size());\n" - "size_t data_size = $fixed_size$UL * count;\n"); + format( + "unsigned int count = static_cast<unsigned int>(this->$name$_size());\n" + "size_t data_size = $fixed_size$UL * count;\n"); } if (descriptor_->is_packed()) { - printer->Print(variables_, - "if (data_size > 0) {\n" - " total_size += $tag_size$ +\n" - " ::google::protobuf::internal::WireFormatLite::Int32Size(\n" - " static_cast< ::google::protobuf::int32>(data_size));\n" - "}\n" - "int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);\n" - "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - "_$name$_cached_byte_size_ = cached_size;\n" - "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" - "total_size += data_size;\n"); + format( + "if (data_size > 0) {\n" + " total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::Int32Size(\n" + " static_cast<$int32$>(data_size));\n" + "}\n" + "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n" + "_$name$_cached_byte_size_.store(cached_size,\n" + " std::memory_order_relaxed);\n" + "total_size += data_size;\n"); } else { - printer->Print(variables_, - "total_size += $tag_size$ *\n" - " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n" - "total_size += data_size;\n"); + format( + "total_size += $tag_size$ *\n" + " " + "::$proto_ns$::internal::FromIntSize(this->$name$_size());\n" + "total_size += data_size;\n"); } - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index d52228e9..77389aa0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -64,10 +64,6 @@ class PrimitiveFieldGenerator : public FieldGenerator { void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; - protected: - const FieldDescriptor* descriptor_; - std::map<string, string> variables_; - private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); }; @@ -111,15 +107,12 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; private: - const FieldDescriptor* descriptor_; - std::map<string, string> variables_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); }; } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc index 95357d9f..677b7374 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.cc +++ b/src/google/protobuf/compiler/cpp/cpp_service.cc @@ -42,151 +42,153 @@ namespace protobuf { namespace compiler { namespace cpp { +namespace { + +void InitMethodVariables(const MethodDescriptor* method, Formatter* format) { + format->Set("name", method->name()); + format->Set("input_type", QualifiedClassName(method->input_type())); + format->Set("output_type", QualifiedClassName(method->output_type())); +} + +} // namespace + ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor, + const std::map<string, string>& vars, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor), vars_(vars) { vars_["classname"] = descriptor_->name(); - vars_["file_namespace"] = FileLevelNamespace(descriptor_->file()->name()); vars_["full_name"] = descriptor_->full_name(); - if (options.dllexport_decl.empty()) { - vars_["dllexport"] = ""; - } else { - vars_["dllexport"] = options.dllexport_decl + " "; - } } ServiceGenerator::~ServiceGenerator() {} void ServiceGenerator::GenerateDeclarations(io::Printer* printer) { + Formatter format(printer, vars_); // Forward-declare the stub type. - printer->Print(vars_, - "class $classname$_Stub;\n" - "\n"); + format( + "class $classname$_Stub;\n" + "\n"); GenerateInterface(printer); GenerateStubDefinition(printer); } void ServiceGenerator::GenerateInterface(io::Printer* printer) { - printer->Print(vars_, - "class $dllexport$$classname$ : public ::google::protobuf::Service {\n" - " protected:\n" - " // This class should be treated as an abstract interface.\n" - " inline $classname$() {};\n" - " public:\n" - " virtual ~$classname$();\n"); + Formatter format(printer, vars_); + format( + "class $dllexport_decl $$classname$ : public ::$proto_ns$::Service {\n" + " protected:\n" + " // This class should be treated as an abstract interface.\n" + " inline $classname$() {};\n" + " public:\n" + " virtual ~$classname$();\n"); printer->Indent(); - printer->Print(vars_, - "\n" - "typedef $classname$_Stub Stub;\n" - "\n" - "static const ::google::protobuf::ServiceDescriptor* descriptor();\n" - "\n"); + format( + "\n" + "typedef $classname$_Stub Stub;\n" + "\n" + "static const ::$proto_ns$::ServiceDescriptor* descriptor();\n" + "\n"); GenerateMethodSignatures(VIRTUAL, printer); - printer->Print( - "\n" - "// implements Service ----------------------------------------------\n" - "\n" - "const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n" - "void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" - " ::google::protobuf::RpcController* controller,\n" - " const ::google::protobuf::Message* request,\n" - " ::google::protobuf::Message* response,\n" - " ::google::protobuf::Closure* done);\n" - "const ::google::protobuf::Message& GetRequestPrototype(\n" - " const ::google::protobuf::MethodDescriptor* method) const;\n" - "const ::google::protobuf::Message& GetResponsePrototype(\n" - " const ::google::protobuf::MethodDescriptor* method) const;\n"); + format( + "\n" + "// implements Service ----------------------------------------------\n" + "\n" + "const ::$proto_ns$::ServiceDescriptor* GetDescriptor();\n" + "void CallMethod(const ::$proto_ns$::MethodDescriptor* method,\n" + " ::$proto_ns$::RpcController* controller,\n" + " const ::$proto_ns$::Message* request,\n" + " ::$proto_ns$::Message* response,\n" + " ::google::protobuf::Closure* done);\n" + "const ::$proto_ns$::Message& GetRequestPrototype(\n" + " const ::$proto_ns$::MethodDescriptor* method) const;\n" + "const ::$proto_ns$::Message& GetResponsePrototype(\n" + " const ::$proto_ns$::MethodDescriptor* method) const;\n"); printer->Outdent(); - printer->Print(vars_, - "\n" - " private:\n" - " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n" - "};\n" - "\n"); + format( + "\n" + " private:\n" + " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n" + "};\n" + "\n"); } void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) { - printer->Print(vars_, - "class $dllexport$$classname$_Stub : public $classname$ {\n" - " public:\n"); + Formatter format(printer, vars_); + format( + "class $dllexport_decl $$classname$_Stub : public $classname$ {\n" + " public:\n"); printer->Indent(); - printer->Print(vars_, - "$classname$_Stub(::google::protobuf::RpcChannel* channel);\n" - "$classname$_Stub(::google::protobuf::RpcChannel* channel,\n" - " ::google::protobuf::Service::ChannelOwnership ownership);\n" - "~$classname$_Stub();\n" - "\n" - "inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n" - "\n" - "// implements $classname$ ------------------------------------------\n" - "\n"); + format( + "$classname$_Stub(::$proto_ns$::RpcChannel* channel);\n" + "$classname$_Stub(::$proto_ns$::RpcChannel* channel,\n" + " ::$proto_ns$::Service::ChannelOwnership ownership);\n" + "~$classname$_Stub();\n" + "\n" + "inline ::$proto_ns$::RpcChannel* channel() { return channel_; }\n" + "\n" + "// implements $classname$ ------------------------------------------\n" + "\n"); GenerateMethodSignatures(NON_VIRTUAL, printer); printer->Outdent(); - printer->Print(vars_, - " private:\n" - " ::google::protobuf::RpcChannel* channel_;\n" - " bool owns_channel_;\n" - " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n" - "};\n" - "\n"); + format( + " private:\n" + " ::$proto_ns$::RpcChannel* channel_;\n" + " bool owns_channel_;\n" + " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n" + "};\n" + "\n"); } -void ServiceGenerator::GenerateMethodSignatures( - VirtualOrNon virtual_or_non, io::Printer* printer) { +void ServiceGenerator::GenerateMethodSignatures(VirtualOrNon virtual_or_non, + io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); - std::map<string, string> sub_vars; - sub_vars["name"] = method->name(); - sub_vars["input_type"] = ClassName(method->input_type(), true); - sub_vars["output_type"] = ClassName(method->output_type(), true); - sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : ""; - - printer->Print(sub_vars, - "$virtual$void $name$(::google::protobuf::RpcController* controller,\n" - " const $input_type$* request,\n" - " $output_type$* response,\n" - " ::google::protobuf::Closure* done);\n"); + Formatter format(printer, vars_); + InitMethodVariables(method, &format); + format.Set("virtual", virtual_or_non == VIRTUAL ? "virtual " : ""); + format( + "$virtual$void $name$(::$proto_ns$::RpcController* controller,\n" + " const $input_type$* request,\n" + " $output_type$* response,\n" + " ::google::protobuf::Closure* done);\n"); } } // =================================================================== -void ServiceGenerator::GenerateDescriptorInitializer( - io::Printer* printer, int index) { - std::map<string, string> vars; - vars["classname"] = descriptor_->name(); - vars["index"] = SimpleItoa(index); - - printer->Print(vars, - "$classname$_descriptor_ = file->service($index$);\n"); +void ServiceGenerator::GenerateDescriptorInitializer(io::Printer* printer, + int index) { + Formatter format(printer, vars_); + format("$classname$_descriptor_ = file->service($1$);\n", index); } // =================================================================== void ServiceGenerator::GenerateImplementation(io::Printer* printer) { - vars_["index"] = SimpleItoa(index_in_metadata_); - printer->Print( - vars_, + Formatter format(printer, vars_); + format( "$classname$::~$classname$() {}\n" "\n" - "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n" - " $file_namespace$::protobuf_AssignDescriptorsOnce();\n" - " return $file_namespace$::file_level_service_descriptors[$index$];\n" + "const ::$proto_ns$::ServiceDescriptor* $classname$::descriptor() {\n" + " " + "::$proto_ns$::internal::AssignDescriptors(&$assign_desc_table$);\n" + " return $file_level_service_descriptors$[$1$];\n" "}\n" "\n" - "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n" + "const ::$proto_ns$::ServiceDescriptor* $classname$::GetDescriptor() {\n" " return descriptor();\n" "}\n" - "\n"); + "\n", + index_in_metadata_); // Generate methods of the interface. GenerateNotImplementedMethods(printer); @@ -195,18 +197,20 @@ void ServiceGenerator::GenerateImplementation(io::Printer* printer) { GenerateGetPrototype(RESPONSE, printer); // Generate stub implementation. - printer->Print(vars_, - "$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n" - " : channel_(channel), owns_channel_(false) {}\n" - "$classname$_Stub::$classname$_Stub(\n" - " ::google::protobuf::RpcChannel* channel,\n" - " ::google::protobuf::Service::ChannelOwnership ownership)\n" - " : channel_(channel),\n" - " owns_channel_(ownership == ::google::protobuf::Service::STUB_OWNS_CHANNEL) {}\n" - "$classname$_Stub::~$classname$_Stub() {\n" - " if (owns_channel_) delete channel_;\n" - "}\n" - "\n"); + format( + "$classname$_Stub::$classname$_Stub(::$proto_ns$::RpcChannel* channel)\n" + " : channel_(channel), owns_channel_(false) {}\n" + "$classname$_Stub::$classname$_Stub(\n" + " ::$proto_ns$::RpcChannel* channel,\n" + " ::$proto_ns$::Service::ChannelOwnership ownership)\n" + " : channel_(channel),\n" + " owns_channel_(ownership == " + "::$proto_ns$::Service::STUB_OWNS_CHANNEL) " + "{}\n" + "$classname$_Stub::~$classname$_Stub() {\n" + " if (owns_channel_) delete channel_;\n" + "}\n" + "\n"); GenerateStubMethods(printer); } @@ -214,123 +218,110 @@ void ServiceGenerator::GenerateImplementation(io::Printer* printer) { void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); - std::map<string, string> sub_vars; - sub_vars["classname"] = descriptor_->name(); - sub_vars["name"] = method->name(); - sub_vars["index"] = SimpleItoa(i); - sub_vars["input_type"] = ClassName(method->input_type(), true); - sub_vars["output_type"] = ClassName(method->output_type(), true); - - printer->Print(sub_vars, - "void $classname$::$name$(::google::protobuf::RpcController* controller,\n" - " const $input_type$*,\n" - " $output_type$*,\n" - " ::google::protobuf::Closure* done) {\n" - " controller->SetFailed(\"Method $name$() not implemented.\");\n" - " done->Run();\n" - "}\n" - "\n"); + Formatter format(printer, vars_); + InitMethodVariables(method, &format); + format( + "void $classname$::$name$(::$proto_ns$::RpcController* controller,\n" + " const $input_type$*,\n" + " $output_type$*,\n" + " ::google::protobuf::Closure* done) {\n" + " controller->SetFailed(\"Method $name$() not implemented.\");\n" + " done->Run();\n" + "}\n" + "\n"); } } void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { - printer->Print( - vars_, - "void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" - " ::google::protobuf::RpcController* controller,\n" - " const ::google::protobuf::Message* request,\n" - " ::google::protobuf::Message* response,\n" + Formatter format(printer, vars_); + format( + "void $classname$::CallMethod(const ::$proto_ns$::MethodDescriptor* " + "method,\n" + " ::$proto_ns$::RpcController* controller,\n" + " const ::$proto_ns$::Message* request,\n" + " ::$proto_ns$::Message* response,\n" " ::google::protobuf::Closure* done) {\n" - " GOOGLE_DCHECK_EQ(method->service(), " - "$file_namespace$::file_level_service_descriptors[$index$]);\n" - " switch(method->index()) {\n"); + " GOOGLE_DCHECK_EQ(method->service(), $file_level_service_descriptors$[$1$]);\n" + " switch(method->index()) {\n", + index_in_metadata_); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); - std::map<string, string> sub_vars; - sub_vars["name"] = method->name(); - sub_vars["index"] = SimpleItoa(i); - sub_vars["input_type"] = ClassName(method->input_type(), true); - sub_vars["output_type"] = ClassName(method->output_type(), true); + Formatter format(printer, vars_); + InitMethodVariables(method, &format); // Note: down_cast does not work here because it only works on pointers, // not references. - printer->Print(sub_vars, - " case $index$:\n" - " $name$(controller,\n" - " ::google::protobuf::down_cast<const $input_type$*>(request),\n" - " ::google::protobuf::down_cast< $output_type$*>(response),\n" - " done);\n" - " break;\n"); + format( + " case $1$:\n" + " $name$(controller,\n" + " ::google::protobuf::down_cast<const $input_type$*>(request),\n" + " ::google::protobuf::down_cast< $output_type$*>(response),\n" + " done);\n" + " break;\n", + i); } - printer->Print(vars_, - " default:\n" - " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" - " break;\n" - " }\n" - "}\n" - "\n"); + format( + " default:\n" + " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" + " break;\n" + " }\n" + "}\n" + "\n"); } void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, io::Printer* printer) { + Formatter format(printer, vars_); if (which == REQUEST) { - printer->Print(vars_, - "const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n"); + format("const ::$proto_ns$::Message& $classname$::GetRequestPrototype(\n"); } else { - printer->Print(vars_, - "const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n"); + format("const ::$proto_ns$::Message& $classname$::GetResponsePrototype(\n"); } - printer->Print(vars_, - " const ::google::protobuf::MethodDescriptor* method) const {\n" - " GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" - " switch(method->index()) {\n"); + format( + " const ::$proto_ns$::MethodDescriptor* method) const {\n" + " GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" + " switch(method->index()) {\n"); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); const Descriptor* type = - (which == REQUEST) ? method->input_type() : method->output_type(); - - std::map<string, string> sub_vars; - sub_vars["index"] = SimpleItoa(i); - sub_vars["type"] = ClassName(type, true); + (which == REQUEST) ? method->input_type() : method->output_type(); - printer->Print(sub_vars, - " case $index$:\n" - " return $type$::default_instance();\n"); + format( + " case $1$:\n" + " return $2$::default_instance();\n", + i, QualifiedClassName(type)); } - printer->Print( - " default:\n" - " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" - " return *::google::protobuf::MessageFactory::generated_factory()\n" - " ->GetPrototype(method->$input_or_output$_type());\n" - " }\n" - "}\n" - "\n", - "input_or_output", which == REQUEST ? "input" : "output"); + format( + " default:\n" + " GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" + " return *::$proto_ns$::MessageFactory::generated_factory()\n" + " ->GetPrototype(method->$1$_type());\n" + " }\n" + "}\n" + "\n", + which == REQUEST ? "input" : "output"); } void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); - std::map<string, string> sub_vars; - sub_vars["classname"] = descriptor_->name(); - sub_vars["name"] = method->name(); - sub_vars["index"] = SimpleItoa(i); - sub_vars["input_type"] = ClassName(method->input_type(), true); - sub_vars["output_type"] = ClassName(method->output_type(), true); - - printer->Print(sub_vars, - "void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n" - " const $input_type$* request,\n" - " $output_type$* response,\n" - " ::google::protobuf::Closure* done) {\n" - " channel_->CallMethod(descriptor()->method($index$),\n" - " controller, request, response, done);\n" - "}\n"); + Formatter format(printer, vars_); + InitMethodVariables(method, &format); + format( + "void $classname$_Stub::$name$(::$proto_ns$::RpcController* " + "controller,\n" + " const $input_type$* request,\n" + " $output_type$* response,\n" + " ::google::protobuf::Closure* done) {\n" + " channel_->CallMethod(descriptor()->method($1$),\n" + " controller, request, response, done);\n" + "}\n", + i); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_service.h b/src/google/protobuf/compiler/cpp/cpp_service.h index 33c02547..3acbe637 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.h +++ b/src/google/protobuf/compiler/cpp/cpp_service.h @@ -42,11 +42,13 @@ namespace google { namespace protobuf { - namespace io { - class Printer; // printer.h - } +namespace io { +class Printer; // printer.h } +} // namespace protobuf +} // namespace google +namespace google { namespace protobuf { namespace compiler { namespace cpp { @@ -55,6 +57,7 @@ class ServiceGenerator { public: // See generator.cc for the meaning of dllexport_decl. explicit ServiceGenerator(const ServiceDescriptor* descriptor, + const std::map<string, string>& vars, const Options& options); ~ServiceGenerator(); @@ -70,7 +73,8 @@ class ServiceGenerator { // descriptor. void GenerateDescriptorInitializer(io::Printer* printer, int index); - // Generate implementations of everything declared by GenerateDeclarations(). + // Generate implementations of everything declared by + // GenerateDeclarations(). void GenerateImplementation(io::Printer* printer); private: @@ -116,6 +120,6 @@ class ServiceGenerator { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index cf6c4b33..ecfabe64 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -36,9 +36,9 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/printer.h> - #include <google/protobuf/stubs/strutil.h> + namespace google { namespace protobuf { namespace compiler { @@ -50,19 +50,20 @@ void SetStringVariables(const FieldDescriptor* descriptor, std::map<string, string>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); - (*variables)["default"] = DefaultValue(descriptor); + (*variables)["default"] = DefaultValue(options, descriptor); (*variables)["default_length"] = SimpleItoa(descriptor->default_value_string().length()); string default_variable_string = MakeDefaultName(descriptor); (*variables)["default_variable_name"] = default_variable_string; (*variables)["default_variable"] = descriptor->default_value_string().empty() - ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()" + ? "&::" + (*variables)["proto_ns"] + + "::internal::GetEmptyStringAlreadyInited()" : "&" + Namespace(descriptor) + "::" + (*variables)["classname"] + "::" + default_variable_string + ".get()"; (*variables)["pointer_type"] = descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; - (*variables)["null_check"] = "GOOGLE_DCHECK(value != NULL);\n"; + (*variables)["null_check"] = (*variables)["DCHK"] + "(value != NULL);\n"; // NOTE: Escaped here to unblock proto1->proto2 migration. // TODO(liujisi): Extend this to apply for other conflicting methods. (*variables)["release_name"] = @@ -70,7 +71,11 @@ void SetStringVariables(const FieldDescriptor* descriptor, descriptor, "release_"); (*variables)["full_name"] = descriptor->full_name(); - (*variables)["string_piece"] = "::std::string"; + if (options.opensource_runtime) { + (*variables)["string_piece"] = "::std::string"; + } else { + (*variables)["string_piece"] = "::StringPiece"; + } (*variables)["lite"] = HasDescriptorMethods(descriptor->file(), options) ? "" : "Lite"; @@ -82,8 +87,7 @@ void SetStringVariables(const FieldDescriptor* descriptor, StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), - descriptor_(descriptor), + : FieldGenerator(descriptor, options), lite_(!HasDescriptorMethods(descriptor->file(), options)), inlined_(false) { @@ -107,9 +111,9 @@ StringFieldGenerator::~StringFieldGenerator() {} void StringFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { + Formatter format(printer, variables_); if (inlined_) { - printer->Print(variables_, - "::google::protobuf::internal::InlinedStringField $name$_;\n"); + format("::$proto_ns$::internal::InlinedStringField $name$_;\n"); } else { // N.B. that we continue to use |ArenaStringPtr| instead of |string*| for // string fields, even when SupportArenas(descriptor_) == false. Why? The @@ -123,25 +127,27 @@ GeneratePrivateMembers(io::Printer* printer) const { // conditionals. It's simpler to stick with this but use lightweight // accessors that assume arena == NULL. There should be very little // overhead anyway because it's just a tagged pointer in-memory. - printer->Print(variables_, "::google::protobuf::internal::ArenaStringPtr $name$_;\n"); + format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n"); } } void StringFieldGenerator:: GenerateStaticMembers(io::Printer* printer) const { + Formatter format(printer, variables_); if (!descriptor_->default_value_string().empty()) { // We make the default instance public, so it can be initialized by // non-friend code. - printer->Print(variables_, - "public:\n" - "static ::google::protobuf::internal::ExplicitlyConstructed< ::std::string>" - " $default_variable_name$;\n" - "private:\n"); + format( + "public:\n" + "static ::$proto_ns$::internal::ExplicitlyConstructed<$string$>" + " $default_variable_name$;\n" + "private:\n"); } } void StringFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { + Formatter format(printer, variables_); // If we're using StringFieldGenerator for a field with a ctype, it's // because that ctype isn't actually implemented. In particular, this is // true of ctype=CORD and ctype=STRING_PIECE in the open source release. @@ -159,90 +165,82 @@ GenerateAccessorDeclarations(io::Printer* printer) const { // reflection interface since the reflection interface is independent of // the string's underlying representation. - bool unknown_ctype = - descriptor_->options().ctype() != EffectiveStringCType(descriptor_); + bool unknown_ctype = descriptor_->options().ctype() != + EffectiveStringCType(descriptor_, options_); if (unknown_ctype) { - printer->Outdent(); - printer->Print( - " private:\n" - " // Hidden due to unknown ctype option.\n"); - printer->Indent(); + format.Outdent(); + format( + " private:\n" + " // Hidden due to unknown ctype option.\n"); + format.Indent(); } - printer->Print(variables_, - "$deprecated_attr$const ::std::string& $name$() const;\n"); - printer->Annotate("name", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$void ${$set_$name$$}$(const ::std::string& value);\n"); - printer->Annotate("{", "}", descriptor_); - - printer->Print(variables_, - "#if LANG_CXX11\n" - "$deprecated_attr$void ${$set_$name$$}$(::std::string&& value);\n" - "#endif\n"); - printer->Annotate("{", "}", descriptor_); - - printer->Print( - variables_, - "$deprecated_attr$void ${$set_$name$$}$(const char* value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$set_$name$$}$(const $pointer_type$* " - "value, size_t size)" - ";\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$::std::string* ${$mutable_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, "$deprecated_attr$::std::string* $release_name$();\n"); - printer->Annotate("release_name", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$void ${$set_allocated_$name$$}$(::std::string* $name$);\n"); - printer->Annotate("{", "}", descriptor_); - if (SupportsArenas(descriptor_)) { - printer->Print( - variables_, - "PROTOBUF_RUNTIME_DEPRECATED(\"The unsafe_arena_ accessors for\"\n" - "\" string fields are deprecated and will be removed in a\"\n" - "\" future release.\")\n" - "::std::string* ${$unsafe_arena_release_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print( - variables_, - "PROTOBUF_RUNTIME_DEPRECATED(\"The unsafe_arena_ accessors for\"\n" - "\" string fields are deprecated and will be removed in a\"\n" - "\" future release.\")\n" - "void ${$unsafe_arena_set_allocated_$name$$}$(\n" - " ::std::string* $name$);\n"); - printer->Annotate("{", "}", descriptor_); + format( + "$deprecated_attr$const $string$& ${1$$name$$}$() const;\n" + "$deprecated_attr$void ${1$set_$name$$}$(const $string$& value);\n" + "#if LANG_CXX11\n" + "$deprecated_attr$void ${1$set_$name$$}$($string$&& value);\n" + "#endif\n" + "$deprecated_attr$void ${1$set_$name$$}$(const char* value);\n", + descriptor_); + if (!options_.opensource_runtime) { + format( + "$deprecated_attr$void ${1$set_$name$$}$(::StringPiece value);\n" + "#ifdef HAS_GLOBAL_STRING\n" + "$deprecated_attr$void ${1$set_$name$$}$(const ::std::string& value);\n" + "#endif\n", + descriptor_); + } + format( + "$deprecated_attr$void ${1$set_$name$$}$(const $pointer_type$* " + "value, size_t size)" + ";\n" + "$deprecated_attr$$string$* ${1$mutable_$name$$}$();\n" + "$deprecated_attr$$string$* ${1$$release_name$$}$();\n" + "$deprecated_attr$void ${1$set_allocated_$name$$}$($string$* $name$);\n", + descriptor_); + if (options_.opensource_runtime) { + if (SupportsArenas(descriptor_)) { + format( + "$GOOGLE_PROTOBUF$_RUNTIME_DEPRECATED(\"The unsafe_arena_ accessors " + "for\"\n" + "\" string fields are deprecated and will be removed in a\"\n" + "\" future release.\")\n" + "$string$* ${1$unsafe_arena_release_$name$$}$();\n" + "$GOOGLE_PROTOBUF$_RUNTIME_DEPRECATED(\"The unsafe_arena_ accessors " + "for\"\n" + "\" string fields are deprecated and will be removed in a\"\n" + "\" future release.\")\n" + "void ${1$unsafe_arena_set_allocated_$name$$}$(\n" + " $string$* $name$);\n", + descriptor_); + } } if (unknown_ctype) { - printer->Outdent(); - printer->Print(" public:\n"); - printer->Indent(); + format.Outdent(); + format(" public:\n"); + format.Indent(); } } void StringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { + Formatter format(printer, variables_); if (SupportsArenas(descriptor_)) { - printer->Print( - variables_, - "inline const ::std::string& $classname$::$name$() const {\n" + format( + "inline const $string$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.Get();\n" "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" + "inline void $classname$::set_$name$(const $string$& value) {\n" " $set_hasbit$\n" " $name$_.Set$lite$($default_variable$, value, GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "#if LANG_CXX11\n" - "inline void $classname$::set_$name$(::std::string&& value) {\n" + "inline void $classname$::set_$name$($string$&& value) {\n" " $set_hasbit$\n" " $name$_.Set$lite$(\n" " $default_variable$, ::std::move(value), GetArenaNoVirtual());\n" @@ -255,7 +253,26 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $name$_.Set$lite$($default_variable$, $string_piece$(value),\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" + "}\n"); + if (!options_.opensource_runtime) { + format( + "inline void $classname$::set_$name$(::StringPiece value) {\n" + " $set_hasbit$\n" + " $name$_.Set$lite$($default_variable$, value, " + "GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n" + "}\n" + "#ifdef HAS_GLOBAL_STRING\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " $set_hasbit$\n" + " $name$_.Set$lite$($default_variable$, " + "::StringPiece(value.data(),\n" + " value.size()), GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_std_string:$full_name$)\n" + "}\n" + "#endif\n"); + } + format( "inline " "void $classname$::set_$name$(const $pointer_type$* value,\n" " size_t size) {\n" @@ -265,31 +282,32 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" + "inline $string$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" + "inline $string$* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n"); if (HasFieldPresence(descriptor_->file())) { - printer->Print(variables_, - " if (!has_$name$()) {\n" - " return NULL;\n" - " }\n" - " $clear_hasbit$\n" - " return $name$_.ReleaseNonDefault(" - "$default_variable$, GetArenaNoVirtual());\n"); + format( + " if (!has_$name$()) {\n" + " return NULL;\n" + " }\n" + " $clear_hasbit$\n" + " return $name$_.ReleaseNonDefault(" + "$default_variable$, GetArenaNoVirtual());\n"); } else { - printer->Print(variables_, - " $clear_hasbit$\n" - " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n"); + format( + " $clear_hasbit$\n" + " return $name$_.Release($default_variable$, " + "GetArenaNoVirtual());\n"); } - printer->Print(variables_, + format( "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "inline void $classname$::set_allocated_$name$($string$* $name$) {\n" " if ($name$ != NULL) {\n" " $set_hasbit$\n" " } else {\n" @@ -298,43 +316,45 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $name$_.SetAllocated($default_variable$, $name$,\n" " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n" - "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n" - " // " - "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" - " $clear_hasbit$\n" - " return $name$_.UnsafeArenaRelease($default_variable$,\n" - " GetArenaNoVirtual());\n" - "}\n" - "inline void $classname$::unsafe_arena_set_allocated_$name$(\n" - " ::std::string* $name$) {\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" - " if ($name$ != NULL) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n" - " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" - " $name$, GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" - "$full_name$)\n" "}\n"); + if (options_.opensource_runtime) { + format( + "inline $string$* $classname$::unsafe_arena_release_$name$() {\n" + " // " + "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" + " $DCHK$(GetArenaNoVirtual() != NULL);\n" + " $clear_hasbit$\n" + " return $name$_.UnsafeArenaRelease($default_variable$,\n" + " GetArenaNoVirtual());\n" + "}\n" + "inline void $classname$::unsafe_arena_set_allocated_$name$(\n" + " $string$* $name$) {\n" + " $DCHK$(GetArenaNoVirtual() != NULL);\n" + " if ($name$ != NULL) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" + " $name$, GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" + "}\n"); + } } else { // No-arena case. - printer->Print( - variables_, - "inline const ::std::string& $classname$::$name$() const {\n" + format( + "inline const $string$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " return $name$_.GetNoArena();\n" "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" + "inline void $classname$::set_$name$(const $string$& value) {\n" " $set_hasbit$\n" " $name$_.SetNoArena($default_variable$, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "#if LANG_CXX11\n" - "inline void $classname$::set_$name$(::std::string&& value) {\n" + "inline void $classname$::set_$name$($string$&& value) {\n" " $set_hasbit$\n" " $name$_.SetNoArena(\n" " $default_variable$, ::std::move(value));\n" @@ -346,7 +366,24 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $set_hasbit$\n" " $name$_.SetNoArena($default_variable$, $string_piece$(value));\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" + "}\n"); + if (!options_.opensource_runtime) { + format( + "inline void $classname$::set_$name$(::StringPiece value) {\n" + " $set_hasbit$\n" + " $name$_.SetNoArena($default_variable$, value);\n" + " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n" + "}\n" + "#ifdef HAS_GLOBAL_STRING\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " $set_hasbit$\n" + " $name$_.SetNoArena($default_variable$,\n" + " ::StringPiece(value.data(), value.size()));\n" + " // @@protoc_insertion_point(field_set_std_string:$full_name$)\n" + "}\n" + "#endif\n"); + } + format( "inline " "void $classname$::set_$name$(const $pointer_type$* value, " "size_t size) {\n" @@ -355,30 +392,30 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $string_piece$(reinterpret_cast<const char*>(value), size));\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" + "inline $string$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_.MutableNoArena($default_variable$);\n" "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" + "inline $string$* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n"); if (HasFieldPresence(descriptor_->file())) { - printer->Print(variables_, - " if (!has_$name$()) {\n" - " return NULL;\n" - " }\n" - " $clear_hasbit$\n" - " return $name$_.ReleaseNonDefaultNoArena($default_variable$);\n"); + format( + " if (!has_$name$()) {\n" + " return NULL;\n" + " }\n" + " $clear_hasbit$\n" + " return $name$_.ReleaseNonDefaultNoArena($default_variable$);\n"); } else { - printer->Print(variables_, - " $clear_hasbit$\n" - " return $name$_.ReleaseNoArena($default_variable$);\n"); + format( + " $clear_hasbit$\n" + " return $name$_.ReleaseNoArena($default_variable$);\n"); } - printer->Print(variables_, + format( "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + "inline void $classname$::set_allocated_$name$($string$* $name$) {\n" " if ($name$ != NULL) {\n" " $set_hasbit$\n" " } else {\n" @@ -392,41 +429,42 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { void StringFieldGenerator:: GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { + Formatter format(printer, variables_); if (!descriptor_->default_value_string().empty()) { // Initialized in GenerateDefaultInstanceAllocator. - printer->Print(variables_, - "::google::protobuf::internal::ExplicitlyConstructed<::std::string> " - "$classname$::$default_variable_name$;\n"); + format( + "::$proto_ns$::internal::ExplicitlyConstructed<$string$> " + "$classname$::$default_variable_name$;\n"); } } void StringFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); // Two-dimension specialization here: supporting arenas or not, and default // value is the empty string or not. Complexity here ensures the minimal // number of branches / amount of extraneous code at runtime (given that the // below methods are inlined one-liners)! if (SupportsArenas(descriptor_)) { if (descriptor_->default_value_string().empty()) { - printer->Print(variables_, - "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n"); + format( + "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n"); } else { - printer->Print(variables_, - "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n"); + format( + "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n"); } } else { if (descriptor_->default_value_string().empty()) { - printer->Print(variables_, - "$name$_.ClearToEmptyNoArena($default_variable$);\n"); + format("$name$_.ClearToEmptyNoArena($default_variable$);\n"); } else { - printer->Print(variables_, - "$name$_.ClearToDefaultNoArena($default_variable$);\n"); + format("$name$_.ClearToDefaultNoArena($default_variable$);\n"); } } } void StringFieldGenerator:: GenerateMessageClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); // Two-dimension specialization here: supporting arenas, field presence, or // not, and default value is the empty string or not. Complexity here ensures // the minimal number of branches / amount of extraneous code at runtime @@ -447,67 +485,60 @@ GenerateMessageClearingCode(io::Printer* printer) const { // // For non-inlined strings, we distinguish from non-default by comparing // instances, rather than contents. - printer->Print(variables_, - "GOOGLE_DCHECK(!$name$_.IsDefault($default_variable$));\n"); + format("$DCHK$(!$name$_.IsDefault($default_variable$));\n"); } if (SupportsArenas(descriptor_)) { if (descriptor_->default_value_string().empty()) { if (must_be_present) { - printer->Print(variables_, - "$name$_.ClearNonDefaultToEmpty();\n"); + format("$name$_.ClearNonDefaultToEmpty();\n"); } else { - printer->Print(variables_, - "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n"); + format( + "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n"); } } else { // Clear to a non-empty default is more involved, as we try to use the // Arena if one is present and may need to reallocate the string. - printer->Print(variables_, - "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n"); + format( + "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n"); } } else if (must_be_present) { // When Arenas are disabled and field presence has been checked, we can // safely treat the ArenaStringPtr as a string*. if (descriptor_->default_value_string().empty()) { - printer->Print(variables_, "$name$_.ClearNonDefaultToEmptyNoArena();\n"); + format("$name$_.ClearNonDefaultToEmptyNoArena();\n"); } else { - printer->Print( - variables_, - "$name$_.UnsafeMutablePointer()->assign(*$default_variable$);\n"); + format("$name$_.UnsafeMutablePointer()->assign(*$default_variable$);\n"); } } else { if (descriptor_->default_value_string().empty()) { - printer->Print(variables_, - "$name$_.ClearToEmptyNoArena($default_variable$);\n"); + format("$name$_.ClearToEmptyNoArena($default_variable$);\n"); } else { - printer->Print(variables_, - "$name$_.ClearToDefaultNoArena($default_variable$);\n"); + format("$name$_.ClearToDefaultNoArena($default_variable$);\n"); } } } void StringFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) { // TODO(gpike): improve this - printer->Print(variables_, "set_$name$(from.$name$());\n"); + format("set_$name$(from.$name$());\n"); } else { - printer->Print(variables_, - "$set_hasbit$\n" - "$name$_.AssignWithDefault($default_variable$, from.$name$_);\n"); + format( + "$set_hasbit$\n" + "$name$_.AssignWithDefault($default_variable$, from.$name$_);\n"); } } void StringFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (inlined_) { - printer->Print( - variables_, - "$name$_.Swap(&other->$name$_);\n"); + format("$name$_.Swap(&other->$name$_);\n"); } else { - printer->Print( - variables_, + format( "$name$_.Swap(&other->$name$_, $default_variable$,\n" " GetArenaNoVirtual());\n"); } @@ -515,6 +546,7 @@ GenerateSwappingCode(io::Printer* printer) const { void StringFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { + Formatter format(printer, variables_); // TODO(ckennelly): Construct non-empty strings as part of the initializer // list. if (inlined_ && descriptor_->default_value_string().empty()) { @@ -522,125 +554,149 @@ GenerateConstructorCode(io::Printer* printer) const { return; } - printer->Print(variables_, - "$name$_.UnsafeSetDefault($default_variable$);\n"); + format("$name$_.UnsafeSetDefault($default_variable$);\n"); } void StringFieldGenerator:: GenerateCopyConstructorCode(io::Printer* printer) const { + Formatter format(printer, variables_); GenerateConstructorCode(printer); if (HasFieldPresence(descriptor_->file())) { - printer->Print(variables_, - "if (from.has_$name$()) {\n"); + format("if (from.has_$name$()) {\n"); } else { - printer->Print(variables_, - "if (from.$name$().size() > 0) {\n"); + format("if (from.$name$().size() > 0) {\n"); } - printer->Indent(); + format.Indent(); if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) { // TODO(gpike): improve this - printer->Print(variables_, - "$name$_.Set$lite$($default_variable$, from.$name$(),\n" - " GetArenaNoVirtual());\n"); + format( + "$name$_.Set$lite$($default_variable$, from.$name$(),\n" + " GetArenaNoVirtual());\n"); } else { - printer->Print(variables_, - "$name$_.AssignWithDefault($default_variable$, from.$name$_);\n"); + format("$name$_.AssignWithDefault($default_variable$, from.$name$_);\n"); } - printer->Outdent(); - printer->Print("}\n"); + format.Outdent(); + format("}\n"); } void StringFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (inlined_) { // The destructor is automatically invoked. return; } - printer->Print(variables_, "$name$_.DestroyNoArena($default_variable$);\n"); + format("$name$_.DestroyNoArena($default_variable$);\n"); } bool StringFieldGenerator::GenerateArenaDestructorCode( io::Printer* printer) const { + Formatter format(printer, variables_); if (!inlined_) { return false; } - printer->Print(variables_, - "_this->$name$_.DestroyNoArena($default_variable$);\n"); + format("_this->$name$_.DestroyNoArena($default_variable$);\n"); return true; } void StringFieldGenerator:: GenerateDefaultInstanceAllocator(io::Printer* printer) const { + Formatter format(printer, variables_); if (!descriptor_->default_value_string().empty()) { - printer->Print( - variables_, + format( "$ns$::$classname$::$default_variable_name$.DefaultConstruct();\n" "*$ns$::$classname$::$default_variable_name$.get_mutable() = " - "::std::string($default$, $default_length$);\n" - "::google::protobuf::internal::OnShutdownDestroyString(\n" - " $ns$::$classname$::$default_variable_name$.get_mutable());\n" - ); + "$string$($default$, $default_length$);\n" + "::$proto_ns$::internal::OnShutdownDestroyString(\n" + " $ns$::$classname$::$default_variable_name$.get_mutable());\n"); } } void StringFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, this->mutable_$name$()));\n"); + Formatter format(printer, variables_); + // The google3 version of proto2 has ArenaStrings and parses into them + // directly, but for the open-source release, we always parse into ::std::string + // instances. Note that for lite, we do similarly to the open source release + // and use ::std::string, not ArenaString. + if (!options_.opensource_runtime && !inlined_ && + SupportsArenas(descriptor_) && !lite_) { + // If arena != NULL, the current string is either an ArenaString (no + // destructor necessary) or a materialized ::std::string (and is on the Arena's + // destructor list). No call to ArenaStringPtr::Destroy is needed. + format( + "if (arena != NULL) {\n" + " ::$proto_ns$::internal::TaggedPtr<$string$> str =\n" + " ::$proto_ns$::internal::ReadArenaString(input, arena);\n" + " DO_(!str.IsNull());\n" + " $set_hasbit_io$\n" + " $name$_.UnsafeSetTaggedPointer(str);\n" + "} else {\n" + " DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n" + " input, this->mutable_$name$()));\n" + "}\n"); + } else { + format( + "DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n" + " input, this->mutable_$name$()));\n"); + } if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, options_, true, variables_, + descriptor_, options_, true, "this->$name$().data(), static_cast<int>(this->$name$().length()),\n", - printer); + format); } } bool StringFieldGenerator:: MergeFromCodedStreamNeedsArena() const { - return false; + return !lite_ && !inlined_ && !options_.opensource_runtime; } void StringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { + Formatter format(printer, variables_); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, options_, false, variables_, + descriptor_, options_, false, "this->$name$().data(), static_cast<int>(this->$name$().length()),\n", - printer); + format); } - printer->Print(variables_, - "::google::protobuf::internal::WireFormatLite::Write$declared_type$MaybeAliased(\n" - " $number$, this->$name$(), output);\n"); + format( + "::$proto_ns$::internal::WireFormatLite::Write$declared_type$" + "MaybeAliased(\n" + " $number$, this->$name$(), output);\n"); } void StringFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + Formatter format(printer, variables_); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, options_, false, variables_, + descriptor_, options_, false, "this->$name$().data(), static_cast<int>(this->$name$().length()),\n", - printer); + format); } - printer->Print(variables_, - "target =\n" - " ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(\n" - " $number$, this->$name$(), target);\n"); + format( + "target =\n" + " ::$proto_ns$::internal::WireFormatLite::Write$declared_type$ToArray(\n" + " $number$, this->$name$(), target);\n"); } void StringFieldGenerator:: GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, - "total_size += $tag_size$ +\n" - " ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" - " this->$name$());\n"); + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " this->$name$());\n"); } uint32 StringFieldGenerator::CalculateFieldTag() const { @@ -661,17 +717,17 @@ StringOneofFieldGenerator::~StringOneofFieldGenerator() {} void StringOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { + Formatter format(printer, variables_); if (SupportsArenas(descriptor_)) { - printer->Print( - variables_, - "inline const ::std::string& $classname$::$name$() const {\n" + format( + "inline const $string$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $field_member$.Get();\n" " }\n" " return *$default_variable$;\n" "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" + "inline void $classname$::set_$name$(const $string$& value) {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -682,7 +738,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "#if LANG_CXX11\n" - "inline void $classname$::set_$name$(::std::string&& value) {\n" + "inline void $classname$::set_$name$($string$&& value) {\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" @@ -704,7 +760,34 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $field_member$.Set$lite$($default_variable$,\n" " $string_piece$(value), GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" + "}\n"); + if (!options_.opensource_runtime) { + format( + "inline void $classname$::set_$name$(::StringPiece value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $field_member$.Set$lite$($default_variable$, value,\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n" + "}\n" + "#ifdef HAS_GLOBAL_STRING\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $field_member$.Set$lite$($default_variable$,\n" + " ::StringPiece(value.data(), value.size()), " + "GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_std_string:$full_name$)\n" + "}\n" + "#endif\n"); + } + format( "inline " "void $classname$::set_$name$(const $pointer_type$* value,\n" " size_t size) {\n" @@ -719,7 +802,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" + "inline $string$* $classname$::mutable_$name$() {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -729,7 +812,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" + "inline $string$* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" @@ -739,57 +822,57 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return NULL;\n" " }\n" "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" - " if (!has_$name$()) {\n" - " $field_member$.UnsafeSetDefault($default_variable$);\n" + "inline void $classname$::set_allocated_$name$($string$* $name$) {\n" + " if (has_$oneof_name$()) {\n" + " clear_$oneof_name$();\n" " }\n" - " clear_$oneof_name$();\n" " if ($name$ != NULL) {\n" " set_has_$name$();\n" - " $field_member$.SetAllocated($default_variable$, $name$,\n" - " GetArenaNoVirtual());\n" + " $field_member$.UnsafeSetDefault($name$);\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n" - "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n" - " // " - "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " return $field_member$.UnsafeArenaRelease(\n" - " $default_variable$, GetArenaNoVirtual());\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n" - "inline void $classname$::unsafe_arena_set_allocated_$name$(" - "::std::string* $name$) {\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" - " if (!has_$name$()) {\n" - " $field_member$.UnsafeSetDefault($default_variable$);\n" - " }\n" - " clear_$oneof_name$();\n" - " if ($name$) {\n" - " set_has_$name$();\n" - " $field_member$.UnsafeArenaSetAllocated($default_variable$, " - "$name$, GetArenaNoVirtual());\n" - " }\n" - " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" - "$full_name$)\n" "}\n"); + if (options_.opensource_runtime) { + format( + "inline $string$* $classname$::unsafe_arena_release_$name$() {\n" + " // " + "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" + " $DCHK$(GetArenaNoVirtual() != NULL);\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " return $field_member$.UnsafeArenaRelease(\n" + " $default_variable$, GetArenaNoVirtual());\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "inline void $classname$::unsafe_arena_set_allocated_$name$(" + "$string$* $name$) {\n" + " $DCHK$(GetArenaNoVirtual() != NULL);\n" + " if (!has_$name$()) {\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" + " }\n" + " clear_$oneof_name$();\n" + " if ($name$) {\n" + " set_has_$name$();\n" + " $field_member$.UnsafeArenaSetAllocated($default_variable$, " + "$name$, GetArenaNoVirtual());\n" + " }\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" + "}\n"); + } } else { // No-arena case. - printer->Print( - variables_, - "inline const ::std::string& $classname$::$name$() const {\n" + format( + "inline const $string$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" " if (has_$name$()) {\n" " return $field_member$.GetNoArena();\n" " }\n" " return *$default_variable$;\n" "}\n" - "inline void $classname$::set_$name$(const ::std::string& value) {\n" + "inline void $classname$::set_$name$(const $string$& value) {\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" @@ -800,7 +883,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "#if LANG_CXX11\n" - "inline void $classname$::set_$name$(::std::string&& value) {\n" + "inline void $classname$::set_$name$($string$&& value) {\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" @@ -821,7 +904,32 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $field_member$.SetNoArena($default_variable$,\n" " $string_piece$(value));\n" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" + "}\n"); + if (!options_.opensource_runtime) { + format( + "inline void $classname$::set_$name$(::StringPiece value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $field_member$.SetNoArena($default_variable$, value);\n" + " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n" + "}\n" + "#ifdef HAS_GLOBAL_STRING\n" + "inline void $classname$::set_$name$(const ::std::string& value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $field_member$.SetNoArena($default_variable$,\n" + " ::StringPiece(value.data(), value.size()));\n" + " // @@protoc_insertion_point(field_set_std_string:$full_name$)\n" + "}\n" + "#endif\n"); + } + format( "inline " "void $classname$::set_$name$(const $pointer_type$* value, size_t " "size) {\n" @@ -834,7 +942,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " reinterpret_cast<const char*>(value), size));\n" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" - "inline ::std::string* $classname$::mutable_$name$() {\n" + "inline $string$* $classname$::mutable_$name$() {\n" " if (!has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" @@ -843,7 +951,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $field_member$.MutableNoArena($default_variable$);\n" "}\n" - "inline ::std::string* $classname$::$release_name$() {\n" + "inline $string$* $classname$::$release_name$() {\n" " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" @@ -852,14 +960,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " return NULL;\n" " }\n" "}\n" - "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" - " if (!has_$name$()) {\n" - " $field_member$.UnsafeSetDefault($default_variable$);\n" + "inline void $classname$::set_allocated_$name$($string$* $name$) {\n" + " if (has_$oneof_name$()) {\n" + " clear_$oneof_name$();\n" " }\n" - " clear_$oneof_name$();\n" " if ($name$ != NULL) {\n" " set_has_$name$();\n" - " $field_member$.SetAllocatedNoArena($default_variable$, $name$);\n" + " $field_member$.UnsafeSetDefault($name$);\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); @@ -868,13 +975,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { void StringOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + Formatter format(printer, variables_); if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "$field_member$.Destroy($default_variable$,\n" - " GetArenaNoVirtual());\n"); + format( + "$field_member$.Destroy($default_variable$,\n" + " GetArenaNoVirtual());\n"); } else { - printer->Print(variables_, - "$field_member$.DestroyNoArena($default_variable$);\n"); + format("$field_member$.DestroyNoArena($default_variable$);\n"); } } @@ -890,31 +997,55 @@ GenerateSwappingCode(io::Printer* printer) const { void StringOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - printer->Print( - variables_, + Formatter format(printer, variables_); + format( "$ns$::_$classname$_default_instance_.$name$_.UnsafeSetDefault(\n" " $default_variable$);\n"); } void StringOneofFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { - printer->Print(variables_, - "if (has_$name$()) {\n" - " $field_member$.DestroyNoArena($default_variable$);\n" - "}\n"); + Formatter format(printer, variables_); + format( + "if (has_$name$()) {\n" + " $field_member$.DestroyNoArena($default_variable$);\n" + "}\n"); } void StringOneofFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, this->mutable_$name$()));\n"); + Formatter format(printer, variables_); + // See above: ArenaString is not included in the open-source release. + if (!options_.opensource_runtime && SupportsArenas(descriptor_) && !lite_) { + // If has_$name$(), then the current string is either an ArenaString (no + // destructor necessary) or a materialized ::std::string (and is on the Arena's + // destructor list). No call to ArenaStringPtr::Destroy is needed. + format( + "if (arena != NULL) {\n" + " clear_$oneof_name$();\n" + " if (!has_$name$()) {\n" + " $field_member$.UnsafeSetDefault($default_variable$);\n" + " set_has_$name$();\n" + " }\n" + " ::$proto_ns$::internal::TaggedPtr<$string$> new_value =\n" + " ::$proto_ns$::internal::ReadArenaString(input, arena);\n" + " DO_(!new_value.IsNull());\n" + " $field_member$.UnsafeSetTaggedPointer(new_value);\n" + "} else {\n" + " DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n" + " input, this->mutable_$name$()));\n" + "}\n"); + } else { + format( + "DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n" + " input, this->mutable_$name$()));\n"); + } if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, options_, true, variables_, + descriptor_, options_, true, "this->$name$().data(), static_cast<int>(this->$name$().length()),\n", - printer); + format); } } @@ -923,7 +1054,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { RepeatedStringFieldGenerator::RepeatedStringFieldGenerator( const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(options), descriptor_(descriptor) { + : FieldGenerator(descriptor, options) { SetStringVariables(descriptor, &variables_, options); } @@ -931,182 +1062,210 @@ RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} void RepeatedStringFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { - printer->Print(variables_, - "::google::protobuf::RepeatedPtrField< ::std::string> $name$_;\n"); + Formatter format(printer, variables_); + format("::$proto_ns$::RepeatedPtrField<$string$> $name$_;\n"); } void RepeatedStringFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { + Formatter format(printer, variables_); // See comment above about unknown ctypes. - bool unknown_ctype = - descriptor_->options().ctype() != EffectiveStringCType(descriptor_); + bool unknown_ctype = descriptor_->options().ctype() != + EffectiveStringCType(descriptor_, options_); if (unknown_ctype) { - printer->Outdent(); - printer->Print( - " private:\n" - " // Hidden due to unknown ctype option.\n"); - printer->Indent(); + format.Outdent(); + format( + " private:\n" + " // Hidden due to unknown ctype option.\n"); + format.Indent(); } - printer->Print(variables_, - "$deprecated_attr$const ::std::string& $name$(int index) const;\n"); - printer->Annotate("name", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$::std::string* ${$mutable_$name$$}$(int index);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$set_$name$$}$(int index, const " - "::std::string& value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print( - variables_, + format( + "$deprecated_attr$const $string$& ${1$$name$$}$(int index) const;\n" + "$deprecated_attr$$string$* ${1$mutable_$name$$}$(int index);\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, const " + "$string$& value);\n" + "#if LANG_CXX11\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, $string$&& value);\n" + "#endif\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, const " + "char* value);\n", + descriptor_); + if (!options_.opensource_runtime) { + format( + "$deprecated_attr$void ${1$set_$name$$}$(int index, " + "StringPiece value);\n" + "#ifdef HAS_GLOBAL_STRING\n" + "$deprecated_attr$void ${1$set_$name$$}$(int index, const " + "::std::string& value);\n" + "#endif\n", + descriptor_); + } + format( + "$deprecated_attr$void ${1$set_$name$$}$(" + "int index, const $pointer_type$* value, size_t size);\n" + "$deprecated_attr$$string$* ${1$add_$name$$}$();\n" + "$deprecated_attr$void ${1$add_$name$$}$(const $string$& value);\n" "#if LANG_CXX11\n" - "$deprecated_attr$void ${$set_$name$$}$(int index, ::std::string&& value);\n" - "#endif\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$set_$name$$}$(int index, const " - "char* value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "" - "$deprecated_attr$void ${$set_$name$$}$(" - "int index, const $pointer_type$* value, size_t size);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$::std::string* ${$add_$name$$}$();\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$void ${$add_$name$$}$(const ::std::string& value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "#if LANG_CXX11\n" - "$deprecated_attr$void ${$add_$name$$}$(::std::string&& value);\n" - "#endif\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$void ${$add_$name$$}$(const char* value);\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print(variables_, - "$deprecated_attr$void ${$add_$name$$}$(const $pointer_type$* " - "value, size_t size)" - ";\n"); - printer->Annotate("{", "}", descriptor_); - printer->Print( - variables_, - "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() " - "const;\n"); - printer->Annotate("name", descriptor_); - printer->Print(variables_, - "$deprecated_attr$::google::protobuf::RepeatedPtrField< ::std::string>* " - "${$mutable_$name$$}$()" - ";\n"); - printer->Annotate("{", "}", descriptor_); + "$deprecated_attr$void ${1$add_$name$$}$($string$&& value);\n" + "#endif\n" + "$deprecated_attr$void ${1$add_$name$$}$(const char* value);\n", + descriptor_); + if (!options_.opensource_runtime) { + format( + "$deprecated_attr$void ${1$add_$name$$}$(StringPiece value);\n" + "#ifdef HAS_GLOBAL_STRING\n" + "$deprecated_attr$void ${1$add_$name$$}$(const ::std::string& value);\n" + "#endif\n", + descriptor_); + } + format( + "$deprecated_attr$void ${1$add_$name$$}$(const $pointer_type$* " + "value, size_t size)" + ";\n" + "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField<$string$>& " + "${1$$name$$}$() " + "const;\n" + "$deprecated_attr$::$proto_ns$::RepeatedPtrField<$string$>* " + "${1$mutable_$name$$}$()" + ";\n", + descriptor_); if (unknown_ctype) { - printer->Outdent(); - printer->Print(" public:\n"); - printer->Indent(); + format.Outdent(); + format(" public:\n"); + format.Indent(); } } void RepeatedStringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { + Formatter format(printer, variables_); if (options_.safe_boundary_check) { - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.InternalCheckedGet(\n" - " index, ::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" - "}\n"); + format( + "inline const $string$& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.InternalCheckedGet(\n" + " index, ::$proto_ns$::internal::GetEmptyStringAlreadyInited());\n" + "}\n"); } else { - printer->Print(variables_, - "inline const ::std::string& $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.Get(index);\n" + format( + "inline const $string$& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.Get(index);\n" + "}\n"); + } + format( + "inline $string$* $classname$::mutable_$name$(int index) {\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.Mutable(index);\n" + "}\n" + "inline void $classname$::set_$name$(int index, const $string$& value) " + "{\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + " $name$_.Mutable(index)->assign(value);\n" + "}\n" + "#if LANG_CXX11\n" + "inline void $classname$::set_$name$(int index, $string$&& value) {\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + " $name$_.Mutable(index)->assign(std::move(value));\n" + "}\n" + "#endif\n" + "inline void $classname$::set_$name$(int index, const char* value) {\n" + " $null_check$" + " $name$_.Mutable(index)->assign(value);\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n"); + if (!options_.opensource_runtime) { + format( + "inline void " + "$classname$::set_$name$(int index, StringPiece value) {\n" + " $name$_.Mutable(index)->assign(value.data(), value.size());\n" + " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n" + "}\n" + "#ifdef HAS_GLOBAL_STRING\n" + "inline void " + "$classname$::set_$name$(int index, const std::string& value) {\n" + " $name$_.Mutable(index)->assign(value.data(), value.size());\n" + " // @@protoc_insertion_point(field_set_std_string:$full_name$)\n" + "}\n" + "#endif\n"); } - printer->Print(variables_, - "inline ::std::string* $classname$::mutable_$name$(int index) {\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_.Mutable(index);\n" - "}\n" - "inline void $classname$::set_$name$(int index, const ::std::string& value) {\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - " $name$_.Mutable(index)->assign(value);\n" - "}\n" - "#if LANG_CXX11\n" - "inline void $classname$::set_$name$(int index, ::std::string&& value) {\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - " $name$_.Mutable(index)->assign(std::move(value));\n" - "}\n" - "#endif\n" - "inline void $classname$::set_$name$(int index, const char* value) {\n" - " $null_check$" - " $name$_.Mutable(index)->assign(value);\n" - " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" - "inline void " - "$classname$::set_$name$" - "(int index, const $pointer_type$* value, size_t size) {\n" - " $name$_.Mutable(index)->assign(\n" - " reinterpret_cast<const char*>(value), size);\n" - " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" - "}\n" - "inline ::std::string* $classname$::add_$name$() {\n" - " // @@protoc_insertion_point(field_add_mutable:$full_name$)\n" - " return $name$_.Add();\n" - "}\n" - "inline void $classname$::add_$name$(const ::std::string& value) {\n" - " $name$_.Add()->assign(value);\n" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n" - "#if LANG_CXX11\n" - "inline void $classname$::add_$name$(::std::string&& value) {\n" - " $name$_.Add(std::move(value));\n" - " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n" - "#endif\n" - "inline void $classname$::add_$name$(const char* value) {\n" - " $null_check$" - " $name$_.Add()->assign(value);\n" - " // @@protoc_insertion_point(field_add_char:$full_name$)\n" - "}\n" - "inline void " - "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" - " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" - " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n" - "}\n" - "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" - "$classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n" - "$classname$::mutable_$name$() {\n" - " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$name$_;\n" - "}\n"); + format( + "inline void " + "$classname$::set_$name$" + "(int index, const $pointer_type$* value, size_t size) {\n" + " $name$_.Mutable(index)->assign(\n" + " reinterpret_cast<const char*>(value), size);\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "inline $string$* $classname$::add_$name$() {\n" + " // @@protoc_insertion_point(field_add_mutable:$full_name$)\n" + " return $name$_.Add();\n" + "}\n" + "inline void $classname$::add_$name$(const $string$& value) {\n" + " $name$_.Add()->assign(value);\n" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + "}\n" + "#if LANG_CXX11\n" + "inline void $classname$::add_$name$($string$&& value) {\n" + " $name$_.Add(std::move(value));\n" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + "}\n" + "#endif\n" + "inline void $classname$::add_$name$(const char* value) {\n" + " $null_check$" + " $name$_.Add()->assign(value);\n" + " // @@protoc_insertion_point(field_add_char:$full_name$)\n" + "}\n"); + if (!options_.opensource_runtime) { + format( + "inline void $classname$::add_$name$(StringPiece value) {\n" + " $name$_.Add()->assign(value.data(), value.size());\n" + " // @@protoc_insertion_point(field_add_string_piece:$full_name$)\n" + "}\n" + "#ifdef HAS_GLOBAL_STRING\n" + "inline void $classname$::add_$name$(const ::std::string& value) {\n" + " $name$_.Add()->assign(value.data(), value.size());\n" + " // @@protoc_insertion_point(field_add_std_string:$full_name$)\n" + "}\n" + "#endif\n"); + } + format( + "inline void " + "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" + " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" + " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n" + "}\n" + "inline const ::$proto_ns$::RepeatedPtrField<$string$>&\n" + "$classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $name$_;\n" + "}\n" + "inline ::$proto_ns$::RepeatedPtrField<$string$>*\n" + "$classname$::mutable_$name$() {\n" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return &$name$_;\n" + "}\n"); } void RepeatedStringFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + Formatter format(printer, variables_); + format("$name$_.Clear();\n"); } void RepeatedStringFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); + Formatter format(printer, variables_); + format("$name$_.MergeFrom(from.$name$_);\n"); } void RepeatedStringFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, - "$name$_.InternalSwap(CastToBase(&other->$name$_));\n"); + Formatter format(printer, variables_); + format("$name$_.InternalSwap(CastToBase(&other->$name$_));\n"); } void RepeatedStringFieldGenerator:: @@ -1116,68 +1275,72 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateCopyConstructorCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.CopyFrom(from.$name$_);"); + Formatter format(printer, variables_); + format("$name$_.CopyFrom(from.$name$_);"); } void RepeatedStringFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, this->add_$name$()));\n"); + Formatter format(printer, variables_); + format( + "DO_(::$proto_ns$::internal::WireFormatLite::Read$declared_type$(\n" + " input, this->add_$name$()));\n"); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, options_, true, variables_, + descriptor_, options_, true, "this->$name$(this->$name$_size() - 1).data(),\n" "static_cast<int>(this->$name$(this->$name$_size() - 1).length()),\n", - printer); + format); } } void RepeatedStringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - printer->Print(variables_, - "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"); - printer->Indent(); + Formatter format(printer, variables_); + format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"); + format.Indent(); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, options_, false, variables_, + descriptor_, options_, false, "this->$name$(i).data(), static_cast<int>(this->$name$(i).length()),\n", - printer); + format); } - printer->Outdent(); - printer->Print(variables_, - " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" - " $number$, this->$name$(i), output);\n" - "}\n"); + format.Outdent(); + format( + " ::$proto_ns$::internal::WireFormatLite::Write$declared_type$(\n" + " $number$, this->$name$(i), output);\n" + "}\n"); } void RepeatedStringFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - printer->Print(variables_, - "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"); - printer->Indent(); + Formatter format(printer, variables_); + format("for (int i = 0, n = this->$name$_size(); i < n; i++) {\n"); + format.Indent(); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, options_, false, variables_, + descriptor_, options_, false, "this->$name$(i).data(), static_cast<int>(this->$name$(i).length()),\n", - printer); + format); } - printer->Outdent(); - printer->Print(variables_, - " target = ::google::protobuf::internal::WireFormatLite::\n" - " Write$declared_type$ToArray($number$, this->$name$(i), target);\n" - "}\n"); + format.Outdent(); + format( + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " Write$declared_type$ToArray($number$, this->$name$(i), target);\n" + "}\n"); } void RepeatedStringFieldGenerator:: GenerateByteSize(io::Printer* printer) const { - printer->Print(variables_, - "total_size += $tag_size$ *\n" - " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n" - "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n" - " total_size += ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" - " this->$name$(i));\n" - "}\n"); + Formatter format(printer, variables_); + format( + "total_size += $tag_size$ *\n" + " ::$proto_ns$::internal::FromIntSize(this->$name$_size());\n" + "for (int i = 0, n = this->$name$_size(); i < n; i++) {\n" + " total_size += " + "::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " this->$name$(i));\n" + "}\n"); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 6cbf722f..3a1de551 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -75,8 +75,6 @@ class StringFieldGenerator : public FieldGenerator { bool MergeFromCodedStreamNeedsArena() const; protected: - const FieldDescriptor* descriptor_; - std::map<string, string> variables_; const bool lite_; bool inlined_; @@ -127,15 +125,12 @@ class RepeatedStringFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; private: - const FieldDescriptor* descriptor_; - std::map<string, string> variables_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); }; } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 22b759a9..2cf030eb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -33,7 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. // // To test the code generator, we actually use it to generate code for -// google/protobuf/unittest.proto, then test that. This means that we +// net/proto2/internal/unittest.proto, then test that. This means that we // are actually testing the parser and other parts of the system at the same // time, and that problems in the generator may show up as compile-time errors // rather than unittest failures, which may be surprising. However, testing @@ -60,7 +60,7 @@ #define HELPERS_TEST_NAME HelpersTest #define DESCRIPTOR_INIT_TEST_NAME DescriptorInitializationTest -#define UNITTEST_PROTO_PATH "google/protobuf/unittest.proto" +#define UNITTEST_PROTO_PATH "net/proto2/internal/unittest.proto" #define UNITTEST ::protobuf_unittest #define UNITTEST_IMPORT ::protobuf_unittest_import diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.h b/src/google/protobuf/compiler/cpp/cpp_unittest.h index 69c8f44c..d2dcf0a5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.h +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.h @@ -28,14 +28,14 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// This header declares the namespace google::protobuf::protobuf_unittest in order to expose +// This header declares the namespace proto2::protobuf_unittest in order to expose // any problems with the generated class names. We use this header to ensure // unittest.cc will declare the namespace prior to other includes, while obeying // normal include ordering. // // When generating a class name of "foo.Bar" we must ensure we prefix the class -// name with "::", in case the namespace google::protobuf::foo exists. We intentionally -// trigger that case here by declaring google::protobuf::protobuf_unittest. +// name with "::", in case the namespace proto2::foo exists. We intentionally +// trigger that case here by declaring proto2::protobuf_unittest. // // See ClassName in helpers.h for more details. @@ -46,6 +46,6 @@ namespace google { namespace protobuf { namespace protobuf_unittest {} } // namespace protobuf - } // namespace google + #endif // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.inc b/src/google/protobuf/compiler/cpp/cpp_unittest.inc index ff6354f8..bb37b4ac 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.inc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.inc @@ -33,7 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. // // To test the code generator, we actually use it to generate code for -// google/protobuf/unittest.proto, then test that. This means that we +// net/proto2/internal/unittest.proto, then test that. This means that we // are actually testing the parser and other parts of the system at the same // time, and that problems in the generator may show up as compile-time errors // rather than unittest failures, which may be surprising. However, testing @@ -50,6 +50,7 @@ #include <vector> #include <google/protobuf/unittest_no_arena.pb.h> + #if !defined(GOOGLE_PROTOBUF_CMAKE_BUILD) && !defined(_MSC_VER) // We exclude this large proto from cmake build because it's too large for // visual studio to compile (report internal errors). @@ -57,7 +58,9 @@ #endif #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h> +#include <google/protobuf/compiler/scc.h> #include <google/protobuf/compiler/importer.h> +#include <google/protobuf/test_util2.h> #include <google/protobuf/unittest_no_generic_services.pb.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> @@ -72,6 +75,7 @@ #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> +#include <google/protobuf/stubs/casts.h> #include <google/protobuf/stubs/stl_util.h> namespace google { @@ -101,7 +105,7 @@ class MockErrorCollector : public MultiFileErrorCollector { #ifndef PROTOBUF_TEST_NO_DESCRIPTORS // Test that generated code has proper descriptors: -// Parse a descriptor directly (using google::protobuf::compiler::Importer) and +// Parse a descriptor directly (using proto2::compiler::Importer) and // compare it to the one that was produced by generated code. TEST(GENERATED_DESCRIPTOR_TEST_NAME, IdenticalDescriptors) { const FileDescriptor* generated_descriptor = @@ -110,12 +114,12 @@ TEST(GENERATED_DESCRIPTOR_TEST_NAME, IdenticalDescriptors) { // Set up the Importer. MockErrorCollector error_collector; DiskSourceTree source_tree; - source_tree.MapPath("", TestSourceDir()); + source_tree.MapPath("", TestUtil::TestSourceDir()); Importer importer(&source_tree, &error_collector); // Import (parse) unittest.proto. const FileDescriptor* parsed_descriptor = - importer.Import(UNITTEST_PROTO_PATH); + importer.Import(TestUtil::MaybeTranslatePath(UNITTEST_PROTO_PATH)); EXPECT_EQ("", error_collector.text_); ASSERT_TRUE(parsed_descriptor != NULL); @@ -165,21 +169,6 @@ TEST(GENERATED_MESSAGE_TEST_NAME, Defaults) { &message.optional_import_message()); } -#ifndef PROTOBUF_USE_DLLS -TEST(GENERATED_MESSAGE_TEST_NAME, Int32StringConversion) { - EXPECT_EQ("971", Int32ToString(971)); - EXPECT_EQ("(~0x7fffffff)", Int32ToString(kint32min)); - EXPECT_EQ("2147483647", Int32ToString(kint32max)); -} - -TEST(GENERATED_MESSAGE_TEST_NAME, Int64StringConversion) { - EXPECT_EQ("GOOGLE_LONGLONG(971)", Int64ToString(971)); - EXPECT_EQ("GOOGLE_LONGLONG(-2147483648)", Int64ToString(kint32min)); - EXPECT_EQ("GOOGLE_LONGLONG(~0x7fffffffffffffff)", Int64ToString(kint64min)); - EXPECT_EQ("GOOGLE_LONGLONG(9223372036854775807)", Int64ToString(kint64max)); -} -#endif // !PROTOBUF_USE_DLLS - TEST(GENERATED_MESSAGE_TEST_NAME, FloatingPointDefaults) { const UNITTEST::TestExtremeDefaultValues& extreme_default = UNITTEST::TestExtremeDefaultValues::default_instance(); @@ -667,8 +656,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, CopyAssignmentOperator) { TestUtil::ExpectAllFieldsSet(message2); } -#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \ - !defined(GOOGLE_PROTOBUF_NO_RTTI) +#if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || GOOGLE_PROTOBUF_RTTI TEST(GENERATED_MESSAGE_TEST_NAME, UpcastCopyFrom) { // Test the CopyFrom method that takes in the generic const Message& // parameter. @@ -676,7 +664,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, UpcastCopyFrom) { TestUtil::SetAllFields(&message1); - const Message* source = implicit_cast<const Message*>(&message1); + const Message* source = ::google::protobuf::implicit_cast<const Message*>(&message1); message2.CopyFrom(*source); TestUtil::ExpectAllFieldsSet(message2); @@ -709,7 +697,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, DynamicMessageCopyFrom) { TEST(GENERATED_MESSAGE_TEST_NAME, NonEmptyMergeFrom) { // Test merging with a non-empty message. Code is a modified form - // of that found in google/protobuf/reflection_ops_unittest.cc. + // of that found in net/proto2/internal/reflection_ops_unittest.cc. UNITTEST::TestAllTypes message1, message2; TestUtil::SetAllFields(&message1); @@ -741,7 +729,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToArray) { TestUtil::SetAllFields(&message1); int size = message1.ByteSizeLong(); data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data)); uint8* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -755,7 +743,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToArray) { TestUtil::SetPackedFields(&packed_message1); int packed_size = packed_message1.ByteSizeLong(); packed_data.resize(packed_size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&packed_data)); + uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&packed_data)); uint8* end = packed_message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(packed_size, end - start); EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); @@ -772,7 +760,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToStream) { data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -791,7 +779,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToStream) { data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -1872,7 +1860,7 @@ TEST_F(OneofTest, CopyAssignmentOperator) { EXPECT_EQ(message2.foo_message().qux_int(), 123); // Make sure that self-assignment does something sane. - message2 = message2; + message2 = *&message2; // Avoid -Wself-assign. EXPECT_EQ(message2.foo_message().qux_int(), 123); } @@ -1883,7 +1871,7 @@ TEST_F(OneofTest, UpcastCopyFrom) { message1.mutable_foogroup()->set_a(123); EXPECT_TRUE(message1.has_foogroup()); - const Message* source = implicit_cast<const Message*>(&message1); + const Message* source = ::google::protobuf::implicit_cast<const Message*>(&message1); message2.CopyFrom(*source); EXPECT_TRUE(message2.has_foogroup()); @@ -1902,7 +1890,7 @@ TEST_F(OneofTest, SerializationToArray) { message1.set_foo_int(123); int size = message1.ByteSizeLong(); data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data)); uint8* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1916,7 +1904,7 @@ TEST_F(OneofTest, SerializationToArray) { message1.set_foo_string("foo"); int size = message1.ByteSizeLong(); data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data)); uint8* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1931,7 +1919,7 @@ TEST_F(OneofTest, SerializationToArray) { message1.set_foo_bytes("qux"); int size = message1.ByteSizeLong(); data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data)); uint8* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1945,7 +1933,7 @@ TEST_F(OneofTest, SerializationToArray) { message1.set_foo_enum(UNITTEST::TestOneof2::FOO); int size = message1.ByteSizeLong(); data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data)); uint8* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1959,7 +1947,7 @@ TEST_F(OneofTest, SerializationToArray) { message1.mutable_foo_message()->set_qux_int(234); int size = message1.ByteSizeLong(); data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data)); uint8* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1973,7 +1961,7 @@ TEST_F(OneofTest, SerializationToArray) { message1.mutable_foogroup()->set_a(345); int size = message1.ByteSizeLong(); data.resize(size); - uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* start = reinterpret_cast<uint8*>(::google::protobuf::string_as_array(&data)); uint8* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1998,7 +1986,7 @@ TEST_F(OneofTest, SerializationToStream) { { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -2019,7 +2007,7 @@ TEST_F(OneofTest, SerializationToStream) { { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -2041,7 +2029,7 @@ TEST_F(OneofTest, SerializationToStream) { { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -2062,7 +2050,7 @@ TEST_F(OneofTest, SerializationToStream) { { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -2083,7 +2071,7 @@ TEST_F(OneofTest, SerializationToStream) { { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -2104,7 +2092,7 @@ TEST_F(OneofTest, SerializationToStream) { { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -2161,7 +2149,7 @@ TEST_F(OneofTest, MergeFrom) { TEST(HELPERS_TEST_NAME, TestSCC) { UNITTEST::TestMutualRecursionA a; - SCCAnalyzer scc_analyzer((Options())); + MessageSCCAnalyzer scc_analyzer((Options())); const SCC* scc = scc_analyzer.GetSCC(a.GetDescriptor()); std::vector<string> names; for (int i = 0; i < scc->descriptors.size(); i++) { @@ -2185,7 +2173,7 @@ TEST(HELPERS_TEST_NAME, TestSCC) { TEST(HELPERS_TEST_NAME, TestSCCAnalysis) { { UNITTEST::TestRecursiveMessage msg; - SCCAnalyzer scc_analyzer((Options())); + MessageSCCAnalyzer scc_analyzer((Options())); const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); EXPECT_EQ(result.is_recursive, true); @@ -2195,7 +2183,7 @@ TEST(HELPERS_TEST_NAME, TestSCCAnalysis) { } { UNITTEST::TestAllExtensions msg; - SCCAnalyzer scc_analyzer((Options())); + MessageSCCAnalyzer scc_analyzer((Options())); const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); EXPECT_EQ(result.is_recursive, false); @@ -2205,7 +2193,7 @@ TEST(HELPERS_TEST_NAME, TestSCCAnalysis) { } { UNITTEST::TestRequired msg; - SCCAnalyzer scc_analyzer((Options())); + MessageSCCAnalyzer scc_analyzer((Options())); const SCC* scc = scc_analyzer.GetSCC(msg.GetDescriptor()); MessageAnalysis result = scc_analyzer.GetSCCAnalysis(scc); EXPECT_EQ(result.is_recursive, false); @@ -2269,8 +2257,8 @@ TEST(DESCRIPTOR_INIT_TEST_NAME, Initialized) { #endif EXPECT_EQ(should_have_descriptors, - DescriptorPool::generated_pool()->InternalIsFileLoaded( - UNITTEST_PROTO_PATH)); + DescriptorPool::generated_pool()->InternalIsFileLoaded( + TestUtil::MaybeTranslatePath(UNITTEST_PROTO_PATH))); } } // namespace cpp_unittest diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc index 2ad4edd2..77636fe9 100644 --- a/src/google/protobuf/compiler/cpp/metadata_test.cc +++ b/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -42,11 +42,12 @@ #include <gtest/gtest.h> namespace google { -namespace atu = ::google::protobuf::compiler::annotation_test_util; - namespace protobuf { namespace compiler { namespace cpp { + +namespace atu = annotation_test_util; + namespace { class CppMetadataTest : public ::testing::Test { @@ -59,7 +60,7 @@ class CppMetadataTest : public ::testing::Test { string* pb_h, GeneratedCodeInfo* pb_h_info, string* proto_h, GeneratedCodeInfo* proto_h_info, string* pb_cc) { - google::protobuf::compiler::CommandLineInterface cli; + CommandLineInterface cli; CppGenerator cpp_generator; cli.RegisterGenerator("--cpp_out", &cpp_generator, ""); string cpp_out = |