diff options
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
20 files changed, 1210 insertions, 464 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index fce58c02..f99159f5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -125,12 +125,9 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { importer.Import("google/protobuf/descriptor.proto"); const FileDescriptor* plugin_proto_file = importer.Import("google/protobuf/compiler/plugin.proto"); - const FileDescriptor* profile_proto_file = - importer.Import("google/protobuf/compiler/profile.proto"); EXPECT_EQ("", error_collector.text_); ASSERT_TRUE(proto_file != NULL); ASSERT_TRUE(plugin_proto_file != NULL); - ASSERT_TRUE(profile_proto_file != NULL); CppGenerator generator; MockGeneratorContext context; @@ -141,8 +138,6 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { parameter = "dllexport_decl=LIBPROTOC_EXPORT"; ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter, &context, &error)); - ASSERT_TRUE(generator.Generate(profile_proto_file, parameter, - &context, &error)); context.ExpectFileMatches("google/protobuf/descriptor.pb.h", "google/protobuf/descriptor.pb.h"); @@ -152,10 +147,6 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { "google/protobuf/compiler/plugin.pb.h"); context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc", "google/protobuf/compiler/plugin.pb.cc"); - context.ExpectFileMatches("google/protobuf/compiler/profile.pb.h", - "google/protobuf/compiler/profile.pb.h"); - context.ExpectFileMatches("google/protobuf/compiler/profile.pb.cc", - "google/protobuf/compiler/profile.pb.cc"); } } // namespace diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 6a8a83d1..3b4b97e6 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -81,10 +81,16 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { std::map<string, string> vars; vars["classname"] = classname_; vars["short_name"] = descriptor_->name(); - vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : ""); - - printer->Print(vars, "enum $enumbase$ {\n"); - printer->Annotate("enumbase", descriptor_); + 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(); const EnumValueDescriptor* min_value = descriptor_->value(0); @@ -102,7 +108,8 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { " PROTOBUF_DEPRECATED" : ""; if (i > 0) printer->Print(",\n"); - printer->Print(vars, "$prefix$$name$$deprecation$ = $number$"); + printer->Print(vars, "${$$prefix$$name$$}$$deprecation$ = $number$"); + printer->Annotate("{", "}", descriptor_->value(i)); if (descriptor_->value(i)->number() < min_value->number()) { min_value = descriptor_->value(i); @@ -134,14 +141,20 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { } printer->Print(vars, - "$dllexport$bool $classname$_IsValid(int value);\n" - "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n" - "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n"); + "$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_); if (generate_array_size_) { printer->Print(vars, - "const int $prefix$$short_name$_ARRAYSIZE = " - "$prefix$$short_name$_MAX + 1;\n\n"); + "const int ${$$prefix$$short_name$_ARRAYSIZE$}$ = " + "$prefix$$short_name$_MAX + 1;\n\n"); + printer->Annotate("{", "}", descriptor_); } if (HasDescriptorMethods(descriptor_->file(), options_)) { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 960730ca..08a635fa 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -74,9 +74,11 @@ GeneratePrivateMembers(io::Printer* printer) const { 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$$type$ $name$() const;\n" - "$deprecated_attr$void set_$name$($type$ value);\n"); + "$deprecated_attr$void ${$set_$name$$}$($type$ value);\n"); + printer->Annotate("{", "}", descriptor_); } void EnumFieldGenerator:: @@ -113,7 +115,7 @@ GenerateMergingCode(io::Printer* printer) const { void EnumFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); + printer->Print(variables_, "swap($name$_, other->$name$_);\n"); } void EnumFieldGenerator:: @@ -259,12 +261,23 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$deprecated_attr$$type$ $name$(int index) const;\n" - "$deprecated_attr$void set_$name$(int index, $type$ value);\n" - "$deprecated_attr$void add_$name$($type$ value);\n"); + "$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$const ::google::protobuf::RepeatedField<int>& $name$() const;\n" - "$deprecated_attr$::google::protobuf::RepeatedField<int>* mutable_$name$();\n"); + "$deprecated_attr$::google::protobuf::RepeatedField<int>* " + "${$mutable_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); } void RepeatedEnumFieldGenerator:: @@ -294,8 +307,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, printer->Print(variables, " $name$_.Add(value);\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n"); - printer->Print(variables, + "}\n" "$inline$const ::google::protobuf::RepeatedField<int>&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index e4fce461..6b1673b2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -35,9 +35,10 @@ #include <google/protobuf/compiler/cpp/cpp_extension.h> #include <map> #include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 4480a9d2..dce9617c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -95,6 +95,13 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, // By default, empty string, so that generic code used for both oneofs and // singular fields can be written. (*variables)["oneof_prefix"] = ""; + + // 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. + (*variables)["{"] = ""; + (*variables)["}"] = ""; } void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, @@ -194,7 +201,6 @@ const FieldGenerator& FieldGeneratorMap::get( return *field_generators_[field->index()]; } - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 00dc25d4..d9dd3850 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -180,10 +180,6 @@ class FieldGenerator { virtual void GenerateDefaultInstanceAllocator(io::Printer* /*printer*/) const {} - // Generate code that should be run when ShutdownProtobufLibrary() is called, - // to delete all dynamically-allocated objects. - virtual void GenerateShutdownCode(io::Printer* /*printer*/) const {} - // Generate lines to decode this field, which will be placed inside the // message's MergeFromCodedStream() method. virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0; @@ -233,7 +229,6 @@ class FieldGeneratorMap { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); }; - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 1f7a66c5..c56e26f7 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -126,12 +126,20 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) new EnumGenerator(file->enum_type(i), options)); enum_generators_.push_back(enum_generators_owner_[i].get()); } + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->index_in_metadata_ = i; + } 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()); } + 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( @@ -526,11 +534,10 @@ class FileGenerator::ForwardDeclarations { void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // 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 either runs at - // static initialization time (by default) or when default_instance() is - // called for the first time (in LITE_RUNTIME mode with - // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER flag enabled). This procedure also - // constructs default instances and registers extensions. + // generated files (DescriptorPool::generated_pool()). It ordinarily runs at + // static initialization time, but is not used at all in LITE_RUNTIME mode + // except when extensions are used. This procedure also constructs default + // instances and registers extensions. // // Its sibling, AssignDescriptors(), actually pulls the compiled // FileDescriptor from the DescriptorPool and uses it to populate all of @@ -546,7 +553,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // table-driven parsing. printer->Print("PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTableField\n" - " const TableStruct::entries[] = {\n"); + " const TableStruct::entries[] " + "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); std::vector<size_t> entries; @@ -567,7 +575,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "};\n" "\n" "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::AuxillaryParseTableField\n" - " const TableStruct::aux[] = {\n"); + " const TableStruct::aux[] " + "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); std::vector<size_t> aux_entries; @@ -586,7 +595,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { printer->Print( "};\n" "PROTOBUF_CONSTEXPR_VAR ::google::protobuf::internal::ParseTable const\n" - " TableStruct::schema[] = {\n"); + " TableStruct::schema[] " + "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); size_t offset = 0; @@ -606,9 +616,47 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "};\n" "\n"); + if (!message_generators_.empty() && options_.table_driven_serialization) { + printer->Print( + "const ::google::protobuf::internal::FieldMetadata TableStruct::field_metadata[] " + "= {\n"); + printer->Indent(); + std::vector<int> field_metadata_offsets; + int idx = 0; + for (int i = 0; i < message_generators_.size(); i++) { + field_metadata_offsets.push_back(idx); + idx += message_generators_[i]->GenerateFieldMetadata(printer); + } + field_metadata_offsets.push_back(idx); + printer->Outdent(); + printer->Print( + "};\n" + "const ::google::protobuf::internal::SerializationTable " + "TableStruct::serialization_table[] = {\n"); + printer->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. + std::vector<const Descriptor*> calculated_order = + FlattenMessagesInFile(file_); + 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])); + } + printer->Outdent(); + printer->Print( + "};\n" + "\n"); + } if (HasDescriptorMethods(file_, options_)) { if (!message_generators_.empty()) { - printer->Print("const ::google::protobuf::uint32 TableStruct::offsets[] = {\n"); + printer->Print("const ::google::protobuf::uint32 TableStruct::offsets[] " + "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); std::vector<std::pair<size_t, size_t> > pairs; for (int i = 0; i < message_generators_.size(); i++) { @@ -617,8 +665,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { printer->Outdent(); printer->Print( "};\n" - "\n" - "static const ::google::protobuf::internal::MigrationSchema schemas[] = {\n"); + "static const ::google::protobuf::internal::MigrationSchema schemas[] " + "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); { int offset = 0; @@ -649,7 +697,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // we still need these symbols to exist printer->Print( // MSVC doesn't like empty arrays, so we add a dummy. - "const ::google::protobuf::uint32 TableStruct::offsets[] = { ~0u };\n" + "const ::google::protobuf::uint32 TableStruct::offsets[1] = {};\n" "static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n" "static const ::google::protobuf::Message* const* " "file_default_instances = NULL;\n"); @@ -739,33 +787,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "} // namespace\n"); } - // ----------------------------------------------------------------- - - // ShutdownFile(): Deletes descriptors, default instances, etc. on shutdown. - printer->Print( - "\n" - "void TableStruct::Shutdown() {\n"); - printer->Indent(); - - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateShutdownCode(printer); - } - - if (HasDescriptorMethods(file_, options_)) { - for (int i = 0; i < message_generators_.size(); i++) { - if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) continue; - printer->Print( - "delete file_level_metadata[$index$].reflection;\n", - "index", SimpleItoa(i)); - } - } - - printer->Outdent(); - printer->Print( - "}\n\n"); - - // ----------------------------------------------------------------- - // Now generate the InitDefaultsImpl() function. printer->Print( "void TableStruct::InitDefaultsImpl() {\n" @@ -826,7 +847,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { string file_data; file_proto.SerializeToString(&file_data); - printer->Print("static const char descriptor[] = {\n"); + printer->Print("static const char descriptor[] " + "GOOGLE_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {\n"); printer->Indent(); if (file_data.size() > 66535) { @@ -877,9 +899,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { file_namespace); } - printer->Print( - "::google::protobuf::internal::OnShutdown(&TableStruct::Shutdown);\n"); - printer->Outdent(); printer->Print( "}\n" @@ -889,19 +908,15 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { " ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);\n" "}\n"); - if (!StaticInitializersForced(file_, options_)) { - printer->Print("#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"); - } - printer->Print( - // With static initializers. - "// Force AddDescriptors() to be called at static initialization time.\n" - "struct StaticDescriptorInitializer {\n" - " StaticDescriptorInitializer() {\n" - " AddDescriptors();\n" - " }\n" - "} static_descriptor_initializer;\n"); - if (!StaticInitializersForced(file_, options_)) { - printer->Print("#endif // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n"); + if (StaticInitializersForced(file_, options_)) { + printer->Print( + "// Force AddDescriptors() to be called at dynamic initialization " + "time.\n" + "struct StaticDescriptorInitializer {\n" + " StaticDescriptorInitializer() {\n" + " AddDescriptors();\n" + " }\n" + "} static_descriptor_initializer;\n"); } } @@ -1025,11 +1040,11 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { "#include <google/protobuf/map.h>" " // IWYU pragma: export\n"); if (HasDescriptorMethods(file_, options_)) { - printer->Print( - "#include <google/protobuf/map_field_inl.h>\n"); + printer->Print("#include <google/protobuf/map_entry.h>\n"); + printer->Print("#include <google/protobuf/map_field_inl.h>\n"); } else { - printer->Print( - "#include <google/protobuf/map_field_lite.h>\n"); + printer->Print("#include <google/protobuf/map_entry_lite.h>\n"); + printer->Print("#include <google/protobuf/map_field_lite.h>\n"); } } @@ -1096,7 +1111,7 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { void FileGenerator::GenerateGlobalStateFunctionDeclarations( io::Printer* printer) { - // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile + // Forward-declare the AddDescriptors, AssignDescriptors // functions, so that we can declare them to be friends of each class. printer->Print( "\n" @@ -1107,12 +1122,14 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( " static const ::google::protobuf::internal::AuxillaryParseTableField aux[];\n" " static const ::google::protobuf::internal::ParseTable schema[];\n" " static const ::google::protobuf::uint32 offsets[];\n" + " static const ::google::protobuf::internal::FieldMetadata field_metadata[];\n" + " static const ::google::protobuf::internal::SerializationTable " + "serialization_table[];\n" // The following function(s) need to be able to access private members of // the messages defined in the file. So we make them static members. // This is the internal implementation of InitDefaults. It should only // be called by InitDefaults which makes sure it will be called only once. " static void InitDefaultsImpl();\n" - " static void Shutdown();\n" "};\n" "void $dllexport_decl$AddDescriptors();\n" "void $dllexport_decl$InitDefaults();\n" @@ -1202,6 +1219,13 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { // dependent. printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); + // 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"); // Generate class inline methods. for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { @@ -1211,6 +1235,10 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { message_generators_[i]->GenerateInlineMethods(printer, /* is_inline = */ true); } + printer->Print( + "#ifdef __GNUC__\n" + " #pragma GCC diagnostic pop\n" + "#endif // __GNUC__\n"); printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); for (int i = 0; i < message_generators_.size(); i++) { @@ -1227,13 +1255,8 @@ void FileGenerator::GenerateProto2NamespaceEnumSpecializations( io::Printer* printer) { // Emit GetEnumDescriptor specializations into google::protobuf namespace: if (HasEnumDefinitions(file_)) { - // The SWIG conditional is to avoid a null-pointer dereference - // (bug 1984964) in swig-1.3.21 resulting from the following syntax: - // namespace X { void Y<Z::W>(); } - // which appears in GetEnumDescriptor() specializations. printer->Print( "\n" - "#ifndef SWIG\n" "namespace google {\nnamespace protobuf {\n" "\n"); for (int i = 0; i < enum_generators_.size(); i++) { @@ -1241,8 +1264,7 @@ void FileGenerator::GenerateProto2NamespaceEnumSpecializations( } printer->Print( "\n" - "} // namespace protobuf\n} // namespace google\n" - "#endif // SWIG\n"); + "} // namespace protobuf\n} // namespace google\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index cee31224..68abd0ef 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -100,6 +100,8 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_options.enforce_lite = true; } else if (options[i].first == "table_driven_parsing") { file_options.table_driven_parsing = true; + } else if (options[i].first == "table_driven_serialization") { + file_options.table_driven_serialization = true; } else { *error = "Unknown generator option: " + options[i].first; return false; diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 9cddba5c..00959796 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -37,14 +37,16 @@ #include <vector> #include <google/protobuf/stubs/hash.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> + + namespace google { namespace protobuf { namespace compiler { @@ -167,6 +169,11 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { } } +string DefaultInstanceName(const Descriptor* descriptor) { + string prefix = descriptor->file()->package().empty() ? "" : "::"; + return prefix + DotsToColons(descriptor->file()->package()) + "::_" + + ClassName(descriptor, false) + "_default_instance_"; +} string DependentBaseClassTemplateName(const Descriptor* descriptor) { return ClassName(descriptor, false) + "_InternalBase"; @@ -654,6 +661,26 @@ void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, "VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer); } +namespace { + +void Flatten(const Descriptor* descriptor, + std::vector<const Descriptor*>* flatten) { + for (int i = 0; i < descriptor->nested_type_count(); i++) + Flatten(descriptor->nested_type(i), flatten); + flatten->push_back(descriptor); +} + +} // namespace + +std::vector<const Descriptor*> FlattenMessagesInFile( + const FileDescriptor* file) { + std::vector<const Descriptor*> result; + for (int i = 0; i < file->message_type_count(); i++) { + Flatten(file->message_type(i), &result); + } + return result; +} + bool HasWeakFields(const Descriptor* descriptor) { return false; } diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index a744a865..6ae68591 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -67,6 +67,9 @@ extern const char kThinSeparator[]; string ClassName(const Descriptor* descriptor, bool qualified); string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); +// Fully qualified name of the default_instance of this message. +string DefaultInstanceName(const Descriptor* descriptor); + // Name of the CRTP class template (for use with proto_h). // This is a class name, like "ProtoName_InternalBase". string DependentBaseClassTemplateName(const Descriptor* descriptor); @@ -159,8 +162,18 @@ string SafeFunctionName(const Descriptor* descriptor, const FieldDescriptor* field, const string& prefix); -// Returns true if unknown fields are preseved after parsing. -inline bool PreserveUnknownFields(const Descriptor* message) { +// 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; } @@ -168,10 +181,8 @@ inline bool PreserveUnknownFields(const Descriptor* message) { ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( const FileDescriptor* file, const Options& options); -// If PreserveUnknownFields() is true, determines whether unknown -// fields will be stored in an UnknownFieldSet or a string. -// If PreserveUnknownFields() is false, this method will not be -// used. +// Determines whether unknown fields will be stored in an UnknownFieldSet or +// a string. inline bool UseUnknownFieldSet(const FileDescriptor* file, const Options& options) { return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; @@ -277,6 +288,10 @@ inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( : file->options().optimize_for(); } +// This orders the messages in a .pb.cc as it's outputted by file.cc +std::vector<const Descriptor*> FlattenMessagesInFile( + const FileDescriptor* file); + bool HasWeakFields(const Descriptor* desc); bool HasWeakFields(const FileDescriptor* desc); diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index d76db169..da33d29b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -150,6 +150,7 @@ GeneratePrivateMembers(io::Printer* printer) const { " $map_classname$;\n"); } printer->Print(variables_, + "private:\n" "::google::protobuf::internal::MapField$lite$<\n" " $map_classname$,\n" " $key_cpp$, $val_cpp$,\n" @@ -161,11 +162,15 @@ GeneratePrivateMembers(io::Printer* printer) const { void MapFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { - printer->Print(variables_, + printer->Print( + variables_, "$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" - " $name$() const;\n" - "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" - " mutable_$name$();\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_); } void MapFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 1ab87638..e82eebbe 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -52,6 +52,8 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/generated_message_table_driven.h> +#include <google/protobuf/generated_message_util.h> +#include <google/protobuf/map_entry_lite.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> @@ -280,7 +282,7 @@ void OptimizePadding(std::vector<const FieldDescriptor*>* fields, enum Family { REPEATED = 0, STRING = 1, - MESSAGE = 2, + MESSAGE = 3, ZERO_INITIALIZABLE = 4, OTHER = 5, kMaxFamily @@ -452,22 +454,13 @@ bool HasPrivateHasMethod(const FieldDescriptor* field) { } -bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) { +bool TableDrivenParsingEnabled( + const Descriptor* descriptor, const Options& options) { if (!options.table_driven_parsing) { return false; } // Consider table-driven parsing. We only do this if: - // - There are no extensions - if (descriptor->extension_range_count() != 0) { - return false; - } - - // - We are not using UnknownFieldSet (part of the non-lite library). - if (UseUnknownFieldSet(descriptor->file(), options)) { - return false; - } - // - We have has_bits for fields. This avoids a check on every field we set // when are present (the common case). if (!HasFieldPresence(descriptor->file())) { @@ -482,16 +475,6 @@ bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) { max_field_number = field->number(); } - // - There are no map fields. - if (field->is_map()) { - return false; - } - - // - There are no oneof fields. - if (field->containing_oneof()) { - return false; - } - // - There are no weak fields. if (field->options().weak()) { return false; @@ -503,8 +486,10 @@ bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) { return false; } - // - Field numbers are relatively dense within the actual number of fields - if (max_field_number * table_sparseness >= descriptor->field_count()) { + // - Field numbers are relatively dense within the actual number of fields. + // We check for strictly greater than in the case where there are no fields + // (only extensions) so max_field_number == descriptor->field_count() == 0. + if (max_field_number * table_sparseness > descriptor->field_count()) { return false; } @@ -516,6 +501,31 @@ bool TableDrivenEnabled(const Descriptor* descriptor, const Options& options) { return true; } +void SetUnknkownFieldsVariable(const Descriptor* descriptor, + const Options& options, + std::map<string, string>* variables) { + 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()"; + } 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)["mutable_unknown_fields"] = + "_internal_metadata_.mutable_unknown_fields()"; +} + } // anonymous namespace // =================================================================== @@ -592,7 +602,7 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, use_dependent_base_ = true; } - table_driven_ = TableDrivenEnabled(descriptor_, options_); + table_driven_ = TableDrivenParsingEnabled(descriptor_, options_); } MessageGenerator::~MessageGenerator() {} @@ -703,24 +713,29 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } if (field->is_repeated()) { - printer->Print(vars, "$deprecated_attr$int $name$_size() const;\n"); + printer->Print(vars, "$deprecated_attr$int ${$$name$_size$}$() const;\n"); + printer->Annotate("{", "}", field); } else if (HasHasMethod(field)) { - printer->Print(vars, "$deprecated_attr$bool has_$name$() const;\n"); + printer->Print(vars, "$deprecated_attr$bool ${$has_$name$$}$() const;\n"); + printer->Annotate("{", "}", field); } else if (HasPrivateHasMethod(field)) { printer->Print(vars, - "private:\n" - "bool has_$name$() const;\n" - "public:\n"); + "private:\n" + "bool ${$has_$name$$}$() const;\n" + "public:\n"); + printer->Annotate("{", "}", field); } if (!dependent_field) { // If this field is dependent, then its clear_() method is in the // depenent base class. (See also GenerateDependentAccessorDeclarations.) - printer->Print(vars, "$deprecated_attr$void clear_$name$();\n"); + 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); // Generate type-specific accessor declarations. field_generators_.get(field).GenerateAccessorDeclarations(printer); @@ -1074,32 +1089,39 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(" public:\n"); printer->Indent(); - printer->Print(vars, - "$classname$();\n" - "virtual ~$classname$();\n" - "\n" - "$classname$(const $classname$& from);\n" - "\n" - "inline $classname$& operator=(const $classname$& from) {\n" - " CopyFrom(from);\n" - " return *this;\n" - "}\n" - "\n"); + printer->Print( + vars, + "$classname$();\n" + "virtual ~$classname$();\n" + "\n" + "$classname$(const $classname$& from);\n" + "\n" + "inline $classname$& operator=(const $classname$& from) {\n" + " CopyFrom(from);\n" + " return *this;\n" + "}\n"); + + if (options_.table_driven_serialization) { + printer->Print( + "private:\n" + "const void* InternalGetTable() const;\n" + "public:\n" + "\n"); + } // Generate move constructor and move assignment operator for types other than // Any. - #ifdef PROTO_EXPERIMENTAL_ENABLE_MOVE if (!IsAnyMessage(descriptor_)) { printer->Print(vars, "#if LANG_CXX11\n" - "$classname$($classname$&& from)\n" + "$classname$($classname$&& from) noexcept\n" " : $classname$() {\n" " *this = ::std::move(from);\n" "}\n" "\n" - "inline $classname$& operator=($classname$&& from) {\n" + "inline $classname$& operator=($classname$&& from) noexcept {\n" " if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {\n" - " InternalSwap(&from);\n" + " if (this != &from) InternalSwap(&from);\n" " } else {\n" " CopyFrom(from);\n" " }\n" @@ -1107,22 +1129,17 @@ GenerateClassDefinition(io::Printer* printer) { "}\n" "#endif\n"); } - #endif - if (PreserveUnknownFields(descriptor_)) { - string type = UseUnknownFieldSet(descriptor_->file(), options_) - ? "::google::protobuf::UnknownFieldSet" - : "::std::string"; - printer->Print( - "inline const $type$& unknown_fields() const {\n" - " return _internal_metadata_.unknown_fields();\n" - "}\n" - "\n" - "inline $type$* mutable_unknown_fields() {\n" - " return _internal_metadata_.mutable_unknown_fields();\n" - "}\n" - "\n", - "type", type ); + SetUnknkownFieldsVariable(descriptor_, options_, &vars); + if (PublicUnknownFieldsAccessors(descriptor_)) { + printer->Print(vars, + "inline const $unknown_fields_type$& unknown_fields() const {\n" + " return $unknown_fields$;\n" + "}\n" + "inline $unknown_fields_type$* mutable_unknown_fields() {\n" + " return $mutable_unknown_fields$;\n" + "}\n" + "\n"); } // N.B.: We exclude GetArena() when arena support is disabled, falling back on @@ -1190,7 +1207,6 @@ GenerateClassDefinition(io::Printer* printer) { " $message_index$;\n" "\n"); - if (SupportsArenas(descriptor_)) { printer->Print(vars, "void UnsafeArenaSwap($classname$* other);\n"); @@ -1214,6 +1230,9 @@ GenerateClassDefinition(io::Printer* printer) { 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" @@ -1250,9 +1269,14 @@ GenerateClassDefinition(io::Printer* printer) { "\n" "size_t ByteSizeLong() const PROTOBUF_FINAL;\n" "bool MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n" - "void SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;\n"); + " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n"); + if (!options_.table_driven_serialization || + descriptor_->options().message_set_wire_format()) { + printer->Print( + "void SerializeWithCachedSizes(\n" + " ::google::protobuf::io::CodedOutputStream* output) const " + "PROTOBUF_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_)) { @@ -1278,6 +1302,9 @@ GenerateClassDefinition(io::Printer* printer) { "final", use_final); 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" @@ -1443,7 +1470,7 @@ GenerateClassDefinition(io::Printer* printer) { if (SupportsArenas(descriptor_)) { printer->Print( - "friend class ::google::protobuf::Arena;\n" + "template <typename T> friend class ::google::protobuf::Arena::InternalHelper;\n" "typedef void InternalArenaConstructable_;\n" "typedef void DestructorSkippable_;\n"); } @@ -1639,9 +1666,44 @@ bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset, " $classname$, _has_bits_),\n"); } + if (descriptor_->oneof_decl_count() > 0) { + printer->Print(vars, + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" + " $classname$, _oneof_case_),\n"); + } else { + printer->Print("-1, // no _oneof_case_\n"); + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print(vars, + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " + "_extensions_),\n"); + } else { + printer->Print("-1, // no _extensions_\n"); + } + + // TODO(ckennelly): Consolidate this with the calculation for + // AuxillaryParseTableField. + std::vector<string> package_parts; + + const Descriptor* outer = descriptor_; + while (outer->containing_type() != NULL) { + outer = outer->containing_type(); + } + + package_parts = Split( + outer->full_name(), ".", true); + // outer->full_name() contains the class itself. Remove it as it is + // used in the name of the default instance variable. + GOOGLE_DCHECK_NE(package_parts.size(), 0); + package_parts.back().clear(); + + vars["ns"] = Join(package_parts, "::"); + printer->Print(vars, "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" - " $classname$, _internal_metadata_),\n"); + " $classname$, _internal_metadata_),\n" + "&::$ns$_$classname$_default_instance_,\n"); if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(vars, "true,\n"); @@ -1670,6 +1732,239 @@ void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, "{ $offset$, $has_bits_offsets$, sizeof($classname$)},\n"); } +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 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 FieldDescriptor* field, const Options& options) { + bool is_a_map = IsMapEntryMessage(field->containing_type()); + int type = field->type(); + if (field->containing_oneof()) { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kOneOf); + } + if (field->is_packed()) { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kPacked); + } else if (field->is_repeated()) { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kRepeated); + } else if (!HasFieldPresence(field->file()) && + field->containing_oneof() == NULL && !is_a_map) { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kNoPresence); + } else { + return internal::FieldMetadata::CalculateType( + type, internal::FieldMetadata::kPresence); + } +} +#endif + +int FindMessageIndexInFile(const Descriptor* descriptor) { + std::vector<const Descriptor*> flatten = + FlattenMessagesInFile(descriptor->file()); + return std::find(flatten.begin(), flatten.end(), descriptor) - + flatten.begin(); +} + +} // namespace + +int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { + if (!options_.table_driven_serialization) { + return 0; + } + + std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_); + if (IsMapEntryMessage(descriptor_)) { + for (int i = 0; i < 2; i++) { + const FieldDescriptor* field = sorted[i]; + uint32 tag = internal::WireFormatLite::MakeTag( + field->number(), WireFormat::WireTypeForFieldType(field->type())); + + std::map<string, string> vars; + vars["classname"] = classname_; + vars["parent_classname"] = + ClassName(descriptor_->containing_type(), false); + vars["field_name"] = FieldName(field); + vars["tag"] = SimpleItoa(tag); + vars["hasbit"] = SimpleItoa(i); + vars["type"] = SimpleItoa(CalcFieldNum(field, options_)); + vars["ptr"] = "NULL"; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + GOOGLE_CHECK(!IsMapEntryMessage(field->message_type())); + { + vars["ptr"] = + QualifiedFileLevelSymbol( + field->message_type()->file()->package(), + FileLevelNamespace(field->message_type()->file()->name())) + + "::TableStruct::serialization_table + " + + SimpleItoa(FindMessageIndexInFile(field->message_type())); + } + } + vars["extra"] = HasDescriptorMethods(descriptor_->file(), options_) + ? "::SuperType" + : ""; + printer->Print(vars, + "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "::google::protobuf::internal::MapEntryHelper<$parent_classname$::$" + "classname$$extra$>, $field_name$_), $tag$," + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "::google::protobuf::internal::MapEntryHelper<$parent_classname$::$" + "classname$$extra$>, _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", classname_); + 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)); + } + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeSorter()); + for (int i = 0, extension_idx = 0; /* no range */; i++) { + for (; extension_idx < sorted_extensions.size() && + (i == sorted.size() || + sorted_extensions[extension_idx]->start < sorted[i]->number()); + 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, " + "reinterpret_cast<const " + "void*>(::google::protobuf::internal::ExtensionSerializer)},\n", + "classname", classname_, "start", SimpleItoa(range->start), "end", + SimpleItoa(range->end)); + } + if (i == sorted.size()) break; + const FieldDescriptor* field = sorted[i]; + + uint32 tag = internal::WireFormatLite::MakeTag( + field->number(), WireFormat::WireTypeForFieldType(field->type())); + if (field->is_packed()) { + tag = internal::WireFormatLite::MakeTag( + field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + } + + string classfieldname = FieldName(field); + if (field->containing_oneof()) { + classfieldname = field->containing_oneof()->name(); + } + std::map<string, string> vars; + vars["classname"] = classname_; + vars["field_name"] = classfieldname; + vars["tag"] = SimpleItoa(tag); + vars["ptr"] = "NULL"; + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (IsMapEntryMessage(field->message_type())) { + vars["idx"] = SimpleItoa(FindMessageIndexInFile(field->message_type())); + vars["fieldclassname"] = ClassName(field->message_type(), false); + 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<$classname$::$" + "fieldclassname$>::MapFieldType, " + "TableStruct::serialization_table>))},\n"); + continue; + } else { + vars["ptr"] = + QualifiedFileLevelSymbol( + field->message_type()->file()->package(), + FileLevelNamespace(field->message_type()->file()->name())) + + "::TableStruct::serialization_table + " + + SimpleItoa(FindMessageIndexInFile(field->message_type())); + } + } + vars["type"] = SimpleItoa(CalcFieldNum(field, options_)); + + + 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"); + } 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"); + } 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"); + } else { + printer->Print(vars, + "{GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($" + "classname$, $field_name$_), $tag$, ~0u, $type$, " + "$ptr$},\n"); + } + } + 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$, " + "_internal_metadata_), 0, ~0u, " + "::google::protobuf::internal::FieldMetadata::kSpecial, reinterpret_cast<const " + "void*>($serializer$)},\n", + "classname", classname_, "serializer", serializer); + return num_field_metadata; +} + void MessageGenerator:: GenerateDefaultInstanceAllocator(io::Printer* printer) { // Construct the default instances of all fields, as they will be used @@ -1732,25 +2027,6 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) { } void MessageGenerator:: -GenerateShutdownCode(io::Printer* printer) { - if (IsMapEntryMessage(descriptor_)) return; - - printer->Print("_$classname$_default_instance_.Shutdown();\n", "classname", - classname_); - - if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print("delete file_level_metadata[$index$].reflection;\n", "index", - SimpleItoa(index_in_file_messages_)); - } - - // Handle default instances of fields. - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateShutdownCode(printer); - } -} - -void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { if (IsMapEntryMessage(descriptor_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { @@ -1854,6 +2130,15 @@ GenerateClassMethods(io::Printer* printer) { GenerateSwap(printer); printer->Print("\n"); + if (options_.table_driven_serialization) { + printer->Print( + "const void* $classname$::InternalGetTable() const {\n" + " return $file_namespace$::TableStruct::serialization_table + $index$;\n" + "}\n" + "\n", + "classname", classname_, "index", SimpleItoa(index_in_file_messages_), + "file_namespace", FileLevelNamespace(descriptor_->file()->name())); + } if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" @@ -1926,13 +2211,25 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { processing_type |= static_cast<unsigned>( field->is_repeated() ? internal::kRepeatedMask : 0); + processing_type |= static_cast<unsigned>( + field->containing_oneof() ? internal::kOneofMask : 0); + + if (field->is_map()) { + processing_type = internal::TYPE_MAP; + } + const unsigned char tag_size = WireFormat::TagSize(field->number(), field->type()); std::map<string, string> vars; vars["classname"] = classname_; - vars["name"] = FieldName(field); - vars["has"] = SimpleItoa(has_bit_indices_[field->index()]); + if (field->containing_oneof() != NULL) { + vars["name"] = field->containing_oneof()->name(); + vars["presence"] = SimpleItoa(field->containing_oneof()->index()); + } else { + vars["name"] = FieldName(field); + vars["presence"] = SimpleItoa(has_bit_indices_[field->index()]); + } vars["nwtype"] = SimpleItoa(normal_wiretype); vars["pwtype"] = SimpleItoa(packed_wiretype); vars["ptype"] = SimpleItoa(processing_type); @@ -1942,7 +2239,7 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { "{\n" " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" " $classname$, $name$_),\n" - " static_cast< ::google::protobuf::uint32>($has$),\n" + " static_cast< ::google::protobuf::uint32>($presence$),\n" " $nwtype$, $pwtype$, $ptype$, $tag_size$\n" "},\n"); } @@ -1977,7 +2274,7 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { printer->Print( vars, "{::google::protobuf::internal::AuxillaryParseTableField::enum_aux{" - "$type$_IsValid, \"$type$\" }},\n"); + "$type$_IsValid}},\n"); last_field_number++; break; case FieldDescriptor::CPPTYPE_MESSAGE: { @@ -1995,7 +2292,17 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { GOOGLE_DCHECK_NE(package_parts.size(), 0); package_parts.back().clear(); - vars["classname"] = ClassName(field->message_type(), false); + if (field->is_map()) { + vars["classname"] = ClassName(field->containing_type(), false) + + "::" + ClassName(field->message_type(), false); + printer->Print(vars, + "{::google::protobuf::internal::AuxillaryParseTableField::map_" + "aux{&::google::protobuf::internal::ParseMap<$classname$>}},\n"); + last_field_number++; + break; + } else { + vars["classname"] = ClassName(field->message_type(), false); + } vars["ns"] = Join(package_parts, "::"); vars["type"] = FieldMessageTypeName(field); vars["file_namespace"] = FileLevelNamespace(outer->file()->name()); @@ -2005,7 +2312,7 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { " &::$ns$_$classname$_default_instance_,\n"); bool dont_emit_table = - !TableDrivenEnabled(field->message_type(), options_); + !TableDrivenParsingEnabled(field->message_type(), options_); if (dont_emit_table) { printer->Print(" NULL,\n"); @@ -2034,16 +2341,10 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { break; } vars["full_name"] = field->full_name(); - vars["strict"] = - field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 - ? "true" : "false"; - vars["type"] = field->full_name(); printer->Print(vars, "{::google::protobuf::internal::AuxillaryParseTableField::string_aux{\n" " $default$,\n" - " \"$full_name$\",\n" - " $strict$,\n" - " \"$type$\"\n" + " \"$full_name$\"\n" "}},\n"); last_field_number++; break; @@ -2103,8 +2404,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( const FieldDescriptor* field = descriptor_->field(i); if (field->containing_oneof() || field->options().weak()) { printer->Print( - "GOOGLE_PROTOBUF_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(" - "(&_$classname$_default_instance_), $name$_),\n", + "offsetof($classname$DefaultTypeInternal, $name$_),\n", "classname", classname_, "name", FieldName(field)); } else { printer->Print( @@ -2178,6 +2478,7 @@ GenerateSharedDestructorCode(io::Printer* printer) { // Do nothing when the message is allocated in an arena. printer->Print( "::google::protobuf::Arena* arena = GetArenaNoVirtual();\n" + "GOOGLE_DCHECK(arena == NULL);\n" "if (arena != NULL) {\n" " return;\n" "}\n" @@ -2385,8 +2686,7 @@ GenerateStructors(io::Printer* printer) { initializer_with_arena += ", _weak_field_map_(arena)"; } - string initializer_null; - initializer_null = ", _internal_metadata_(NULL)"; + string initializer_null = superclass + "(), _internal_metadata_(NULL)"; if (IsAnyMessage(descriptor_)) { initializer_null += ", _any_metadata_(&type_url_, &value_)"; } @@ -2396,26 +2696,22 @@ GenerateStructors(io::Printer* printer) { printer->Print( "$classname$::$classname$()\n" - " : $superclass$()$initializer$ {\n" + " : $initializer$ {\n" " if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {\n" " $file_namespace$::InitDefaults();\n" " }\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", - "classname", classname_, "superclass", superclass, "full_name", - descriptor_->full_name(), "initializer", initializer_null, - "file_namespace", FileLevelNamespace(descriptor_->file()->name())); + "classname", classname_, "full_name", descriptor_->full_name(), + "initializer", initializer_null, "file_namespace", + FileLevelNamespace(descriptor_->file()->name())); if (SupportsArenas(descriptor_)) { printer->Print( "$classname$::$classname$(::google::protobuf::Arena* arena)\n" " : $initializer$ {\n" - // When arenas are used it's safe to assume we have finished - // static init time (protos with arenas are unsafe during static init) - "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n" " $file_namespace$::InitDefaults();\n" - "#endif // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n" " SharedCtor();\n" " RegisterArenaDtor(arena);\n" " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" @@ -2602,7 +2898,6 @@ GenerateStructors(io::Printer* printer) { "}\n", "classname", classname_); } - } // Return the number of bits set in n, a non-negative integer. @@ -2615,6 +2910,22 @@ static int popcnt(uint32 n) { return result; } +bool MessageGenerator::MaybeGenerateOptionalFieldCondition( + io::Printer* printer, const FieldDescriptor* field, + int expected_has_bits_index) { + 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); + return true; + } + return false; +} + void MessageGenerator:: GenerateClear(io::Printer* printer) { printer->Print( @@ -2623,6 +2934,15 @@ GenerateClear(io::Printer* printer) { "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); + printer->Print( + // 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" + "// Prevent compiler warnings about cached_has_bits being unused\n" + "(void) cached_has_bits;\n\n"); + + int cached_has_bit_index = -1; + // Step 1: Extensions if (descriptor_->extension_range_count() > 0) { printer->Print("_extensions_.Clear();\n"); @@ -2731,9 +3051,14 @@ GenerateClear(io::Printer* printer) { GOOGLE_DCHECK_LE(2, count); GOOGLE_DCHECK_GE(8, count); + 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)); + } printer->Print( - "if (_has_bits_[$index$ / 32] & $mask$u) {\n", - "index", SimpleItoa(last_chunk * 8), + "if (cached_has_bits & $mask$u) {\n", "mask", SimpleItoa(last_chunk_mask)); printer->Indent(); } @@ -2780,7 +3105,12 @@ GenerateClear(io::Printer* printer) { if (should_check_bit && // If no field presence, then always clear strings/messages as well. HasFieldPresence(descriptor_->file())) { - printer->Print("if (has_$name$()) {\n", "name", fieldname); + if (!MaybeGenerateOptionalFieldCondition(printer, field, + cached_has_bit_index)) { + printer->Print( + "if (has_$name$()) {\n", + "name", fieldname); + } printer->Indent(); have_enclosing_if = true; } @@ -2816,9 +3146,7 @@ GenerateClear(io::Printer* printer) { printer->Print("_has_bits_.Clear();\n"); } - if (PreserveUnknownFields(descriptor_)) { - printer->Print("_internal_metadata_.Clear();\n"); - } + printer->Print("_internal_metadata_.Clear();\n"); printer->Outdent(); printer->Print("}\n"); @@ -2922,6 +3250,7 @@ GenerateSwap(io::Printer* printer) { printer->Print("void $classname$::InternalSwap($classname$* other) {\n", "classname", classname_); printer->Indent(); + printer->Print("using std::swap;\n"); if (HasGeneratedMethods(descriptor_->file(), options_)) { for (int i = 0; i < optimized_order_.size(); i++) { @@ -2933,24 +3262,22 @@ GenerateSwap(io::Printer* printer) { for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( - "std::swap($oneof_name$_, other->$oneof_name$_);\n" - "std::swap(_oneof_case_[$i$], other->_oneof_case_[$i$]);\n", + "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)); } if (HasFieldPresence(descriptor_->file())) { for (int i = 0; i < HasBitsSize() / 4; ++i) { - printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", + printer->Print("swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n", "i", SimpleItoa(i)); } } - if (PreserveUnknownFields(descriptor_)) { - printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - } + printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); + printer->Print("swap(_cached_size_, other->_cached_size_);\n"); if (descriptor_->extension_range_count() > 0) { printer->Print("_extensions_.Swap(&other->_extensions_);\n"); } @@ -3253,21 +3580,16 @@ GenerateCopyFrom(io::Printer* printer) { void MessageGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) { + std::map<string, string> vars; + SetUnknkownFieldsVariable(descriptor_, options_, &vars); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. - printer->Print( + vars["classname"] = classname_; + printer->Print(vars, "bool $classname$::MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input) {\n", - "classname", classname_); - - printer->Print( - " return _extensions_.ParseMessageSet(input, " - "internal_default_instance(),\n" - " mutable_unknown_fields());\n", - // Vars. - "classname", classname_); - - printer->Print( + " ::google::protobuf::io::CodedInputStream* input) {\n" + " return _extensions_.ParseMessageSet(input,\n" + " internal_default_instance(), $mutable_unknown_fields$);\n" "}\n"); return; } @@ -3283,14 +3605,18 @@ GenerateMergeFromCodedStream(io::Printer* printer) { if (table_driven_) { printer->Indent(); + const string lite = UseUnknownFieldSet(descriptor_->file(), options_) ? + "" : "Lite"; + printer->Print( - "return ::google::protobuf::internal::MergePartialFromCodedStream(\n" + "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_->file()->name())); + "file_namespace", FileLevelNamespace(descriptor_->file()->name()), + "lite", lite); printer->Outdent(); @@ -3302,8 +3628,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n" " ::google::protobuf::uint32 tag;\n"); - if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file(), options_)) { + if (!UseUnknownFieldSet(descriptor_->file(), options_)) { // Use LazyStringOutputString to avoid initializing unknown fields string // unless it is actually needed. For the same reason, disable eager refresh // on the CodedOutputStream. @@ -3356,13 +3681,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } printer->Print("::std::pair< ::google::protobuf::uint32, bool> p = " - "input->ReadTagWithCutoff$lasttag$($max$u);\n" + "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)), - "lasttag", !capture_last_tag ? "NoLastTag" : ""); + maxtag))); if (descriptor_->field_count() > 0) { // We don't even want to print the switch() if we have no fields because @@ -3397,9 +3721,11 @@ GenerateMergeFromCodedStream(io::Printer* printer) { 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>($commontag$u)) {\n", - "commontag", SimpleItoa(WireFormat::MakeTag(field))); + 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))); printer->Indent(); if (field->is_packed()) { @@ -3413,22 +3739,30 @@ GenerateMergeFromCodedStream(io::Printer* printer) { if (field->is_packed()) { internal::WireFormatLite::WireType wiretype = WireFormat::WireTypeForFieldType(field->type()); - printer->Print("} else if (static_cast< ::google::protobuf::uint8>(tag) ==\n" - " static_cast< ::google::protobuf::uint8>($uncommontag$u)) {\n", - "uncommontag", SimpleItoa( - internal::WireFormatLite::MakeTag( - field->number(), wiretype))); + 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(); field_generator.GenerateMergeFromCodedStream(printer); printer->Outdent(); } else if (field->is_packable() && !field->is_packed()) { internal::WireFormatLite::WireType wiretype = internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED; - printer->Print("} else if (static_cast< ::google::protobuf::uint8>(tag) ==\n" - " static_cast< ::google::protobuf::uint8>($uncommontag$u)) {\n", - "uncommontag", SimpleItoa( - internal::WireFormatLite::MakeTag( - field->number(), wiretype))); + 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(); field_generator.GenerateMergeFromCodedStreamWithPacking(printer); printer->Outdent(); @@ -3454,12 +3788,20 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print("handle_unusual:\n"); printer->Indent(); // If tag is 0 or an end-group tag then this must be the end of the message. - printer->Print( - "if (tag == 0 ||\n" - " ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n" - " ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n" - " goto success;\n" - "}\n"); + 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"); + } else { + printer->Print( + "if (tag == 0) {\n" + " goto success;\n" + "}\n"); + } // Handle extension ranges. if (descriptor_->extension_range_count() > 0) { @@ -3487,23 +3829,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } } printer->Print(") {\n"); - if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - " DO_(_extensions_.ParseField(tag, input, " - "internal_default_instance(),\n" - " mutable_unknown_fields()));\n"); - } else { - printer->Print( - " DO_(_extensions_.ParseField(tag, input, " - "internal_default_instance(),\n" - " &unknown_fields_stream));\n"); - } + if (UseUnknownFieldSet(descriptor_->file(), options_)) { + printer->Print(vars, + " DO_(_extensions_.ParseField(tag, input,\n" + " internal_default_instance(),\n" + " $mutable_unknown_fields$));\n"); } else { printer->Print( - // With static initializers. - " DO_(_extensions_.ParseField(tag, input, " - "internal_default_instance());\n"); + " DO_(_extensions_.ParseField(tag, input,\n" + " internal_default_instance(),\n" + " &unknown_fields_stream));\n"); } printer->Print( " continue;\n" @@ -3511,19 +3846,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } // We really don't recognize this tag. Skip it. - if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( + if (UseUnknownFieldSet(descriptor_->file(), options_)) { + printer->Print(vars, "DO_(::google::protobuf::internal::WireFormat::SkipField(\n" - " input, tag, mutable_unknown_fields()));\n"); - } else { - printer->Print( - "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n" - " input, tag, &unknown_fields_stream));\n"); - } + " input, tag, $mutable_unknown_fields$));\n"); } else { printer->Print( - "DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n"); + "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n" + " input, tag, &unknown_fields_stream));\n"); } if (descriptor_->field_count() > 0) { @@ -3660,13 +3990,16 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) { " _extensions_.SerializeMessageSetWithCachedSizes(output);\n", "classname", classname_); GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); - printer->Print( + std::map<string, string> vars; + SetUnknkownFieldsVariable(descriptor_, options_, &vars); + printer->Print(vars, " ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n" - " unknown_fields(), output);\n"); + " $unknown_fields$, output);\n"); printer->Print( "}\n"); return; } + if (options_.table_driven_serialization) return; printer->Print( "void $classname$::SerializeWithCachedSizes(\n" @@ -3701,10 +4034,12 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) { " deterministic, target);\n", "classname", classname_); GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); - printer->Print( + std::map<string, string> vars; + SetUnknkownFieldsVariable(descriptor_, options_, &vars); + printer->Print(vars, " target = ::google::protobuf::internal::WireFormat::\n" " SerializeUnknownMessageSetItemsToArray(\n" - " unknown_fields(), target);\n"); + " $unknown_fields$, target);\n"); printer->Print( " return target;\n" "}\n"); @@ -3868,29 +4203,29 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { } } - if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print("if (_internal_metadata_.have_unknown_fields()) {\n"); - printer->Indent(); - if (to_array) { - printer->Print( - "target = " - "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n" - " unknown_fields(), target);\n"); - } else { - printer->Print( - "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" - " unknown_fields(), output);\n"); - } - printer->Outdent(); - - printer->Print( - "}\n"); + std::map<string, string> vars; + SetUnknkownFieldsVariable(descriptor_, options_, &vars); + if (UseUnknownFieldSet(descriptor_->file(), options_)) { + printer->Print(vars, + "if ($have_unknown_fields$) {\n"); + printer->Indent(); + if (to_array) { + printer->Print(vars, + "target = " + "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n" + " $unknown_fields$, target);\n"); } else { - printer->Print( - "output->WriteRaw(unknown_fields().data(),\n" - " static_cast<int>(unknown_fields().size()));\n"); + printer->Print(vars, + "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" + " $unknown_fields$, output);\n"); } + printer->Outdent(); + + printer->Print("}\n"); + } else { + printer->Print(vars, + "output->WriteRaw($unknown_fields$.data(),\n" + " static_cast<int>($unknown_fields$.size()));\n"); } } @@ -3934,18 +4269,19 @@ void MessageGenerator:: GenerateByteSize(io::Printer* printer) { if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. - printer->Print( - "size_t $classname$::ByteSizeLong() const {\n" - "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" - " size_t total_size = _extensions_.MessageSetByteSize();\n", - "classname", classname_, "full_name", descriptor_->full_name()); GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); - printer->Print( - "if (_internal_metadata_.have_unknown_fields()) {\n" - " total_size += ::google::protobuf::internal::WireFormat::\n" - " ComputeUnknownMessageSetItemsSize(unknown_fields());\n" - "}\n"); - printer->Print( + std::map<string, string> vars; + SetUnknkownFieldsVariable(descriptor_, options_, &vars); + vars["classname"] = classname_; + vars["full_name"] = descriptor_->full_name(); + printer->Print(vars, + "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" + " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" + " }\n" " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" " _cached_size_ = cached_size;\n" @@ -3999,19 +4335,19 @@ GenerateByteSize(io::Printer* printer) { "\n"); } - if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - "if (_internal_metadata_.have_unknown_fields()) {\n" - " total_size +=\n" - " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" - " unknown_fields());\n" - "}\n"); - } else { - printer->Print( - "total_size += unknown_fields().size();\n" - "\n"); - } + std::map<string, string> vars; + SetUnknkownFieldsVariable(descriptor_, options_, &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"); + } else { + printer->Print(vars, + "total_size += $unknown_fields$.size();\n" + "\n"); } // Handle required fields (if any). We expect all of them to be @@ -4360,7 +4696,6 @@ GenerateIsInitialized(io::Printer* printer) { "}\n"); } - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 23aaeeb0..352069eb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -104,10 +104,6 @@ class MessageGenerator { // allocated before any can be initialized. void GenerateDefaultInstanceInitializer(io::Printer* printer); - // Generates code that should be run when ShutdownProtobufLibrary() is called, - // to delete all dynamically-allocated objects. - void GenerateShutdownCode(io::Printer* printer); - // Generate all non-inline methods for this class. void GenerateClassMethods(io::Printer* printer); @@ -132,6 +128,9 @@ class MessageGenerator { // of entries generated and the index of the first has_bit entry. std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer); void GenerateSchema(io::Printer* printer, int offset, int has_offset); + // For each field generates a table entry describing the field for the + // table driven serializer. + int GenerateFieldMetadata(io::Printer* printer); // Generate constructors and destructor. void GenerateStructors(io::Printer* printer); @@ -147,6 +146,13 @@ class MessageGenerator { // Generate the arena-specific destructor code. 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. + bool MaybeGenerateOptionalFieldCondition(io::Printer* printer, + const FieldDescriptor* field, + int expected_has_bits_index); + // Generate standard Message methods. void GenerateClear(io::Printer* printer); void GenerateOneofClear(io::Printer* printer); @@ -179,7 +185,6 @@ class MessageGenerator { io::Printer* printer, const Descriptor::ExtensionRange* range, bool unbounded); - // Generates has_foo() functions and variables for singular field has-bits. void GenerateSingularFieldHasBits(const FieldDescriptor* field, std::map<string, string> vars, diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index ed1719cc..5b260caa 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -50,6 +50,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = FieldMessageTypeName(descriptor); + (*variables)["type_default_instance"] = + DefaultInstanceName(descriptor->message_type()); if (descriptor->options().weak() || !descriptor->containing_oneof()) { (*variables)["non_null_ptr_to_name"] = StrCat("this->", (*variables)["name"], "_"); @@ -98,6 +100,7 @@ void MessageFieldGenerator:: GenerateGetterDeclaration(io::Printer* printer) const { printer->Print(variables_, "$deprecated_attr$const $type$& $name$() const;\n"); + printer->Annotate("name", descriptor_); } void MessageFieldGenerator:: @@ -107,9 +110,14 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const { } // Arena manipulation code is out-of-line in the derived message class. printer->Print(variables_, - "$deprecated_attr$$type$* mutable_$name$();\n" - "$deprecated_attr$$type$* $release_name$();\n" - "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n"); + "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n"); + printer->Annotate("release_name", descriptor_); + printer->Print(variables_, + "$deprecated_attr$void ${$set_allocated_$name$$}$" + "($type$* $name$);\n"); + printer->Annotate("{", "}", descriptor_); } void MessageFieldGenerator:: @@ -130,15 +138,25 @@ GenerateAccessorDeclarations(io::Printer* printer) const { GenerateGetterDeclaration(printer); if (!dependent_field_) { printer->Print(variables_, - "$deprecated_attr$$type$* mutable_$name$();\n" - "$deprecated_attr$$type$* $release_name$();\n" - "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n"); + "$deprecated_attr$$type$* ${$mutable_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + printer->Print(variables_, "$deprecated_attr$$type$* $release_name$();\n"); + printer->Annotate("release_name", descriptor_); + printer->Print(variables_, + "$deprecated_attr$void ${$set_allocated_$name$$}$" + "($type$* $name$);\n"); + printer->Annotate("{", "}", descriptor_); } if (SupportsArenas(descriptor_)) { + printer->Print( + variables_, + "$deprecated_attr$$type$* ${$unsafe_arena_release_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); printer->Print(variables_, - "$deprecated_attr$$type$* unsafe_arena_release_$name$();\n" - "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n" - " $type$* $name$);\n"); + "$deprecated_attr$void " + "${$unsafe_arena_set_allocated_$name$$}$(\n" + " $type$* $name$);\n"); + printer->Annotate("{", "}", descriptor_); } } @@ -346,30 +364,18 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { void MessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - if (dependent_field_) { - // for dependent fields we cannot access its internal_default_instance, - // because the type is incomplete. - // TODO(gerbens) deprecate dependent base class. - std::map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline " : ""; - printer->Print(variables, - "$inline$const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_ != NULL ? *$name$_\n" - " : *internal_default_instance()->$name$_;\n" - "}\n"); - return; - } - std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$const $type$& $classname$::$name$() const {\n" + " const $type$* p = $name$_;\n" " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_ != NULL ? *$name$_\n" - " : *$type$::internal_default_instance();\n" + " return p != NULL ? *p : *reinterpret_cast<const $type$*>(\n" + " &$type_default_instance$);\n" "}\n"); + if (dependent_field_) return; + if (SupportsArenas(descriptor_)) { printer->Print(variables, "$inline$" @@ -511,18 +517,12 @@ GenerateMergingCode(io::Printer* printer) const { void MessageFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); + printer->Print(variables_, "swap($name$_, other->$name$_);\n"); } void MessageFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { - // 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()) {\n" - " delete $name$_;\n" - "}\n"); + printer->Print(variables_, "delete $name$_;\n"); } void MessageFieldGenerator:: @@ -899,16 +899,20 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$deprecated_attr$$type$* mutable_$name$(int index);\n" - "$deprecated_attr$$type$* add_$name$();\n"); + "$deprecated_attr$$type$* ${$mutable_$name$$}$(int index);\n"); + printer->Annotate("{", "}", descriptor_); + printer->Print(variables_, "$deprecated_attr$$type$* ${$add_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); if (dependent_getter_) { printer->Print(variables_, "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" " $name$() const;\n"); + printer->Annotate("name", descriptor_); } printer->Print(variables_, - "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n" - " mutable_$name$();\n"); + "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n" + " ${$mutable_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); } void RepeatedMessageFieldGenerator:: @@ -916,6 +920,7 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const { if (dependent_getter_) { printer->Print(variables_, "$deprecated_attr$const $type$& $name$(int index) const;\n"); + printer->Annotate("name", descriptor_); } if (dependent_field_) { InternalGenerateTypeDependentAccessorDeclarations(printer); @@ -927,6 +932,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { if (!dependent_getter_) { printer->Print(variables_, "$deprecated_attr$const $type$& $name$(int index) const;\n"); + printer->Annotate("name", descriptor_); } if (!dependent_field_) { InternalGenerateTypeDependentAccessorDeclarations(printer); @@ -935,6 +941,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" " $name$() const;\n"); + printer->Annotate("name", descriptor_); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc new file mode 100644 index 00000000..f72a7d60 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_move_unittest.cc @@ -0,0 +1,169 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/test_util.h> +#include <google/protobuf/unittest.pb.h> +#include <gtest/gtest.h> + +#if LANG_CXX11 +#include <google/protobuf/stubs/type_traits.h> +#endif + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +// Can't use an anonymous namespace here due to brokenness of Tru64 compiler. +namespace cpp_unittest { + +// Moves are enabled only when compiling with a C++11 compiler or newer. +#if LANG_CXX11 + +TEST(MovableMessageTest, MoveConstructor) { + protobuf_unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + const auto* nested = &message1.optional_nested_message(); + + protobuf_unittest::TestAllTypes message2(std::move(message1)); + TestUtil::ExpectAllFieldsSet(message2); + + // Check if the optional_nested_message was actually moved (and not just + // copied). + EXPECT_EQ(nested, &message2.optional_nested_message()); + EXPECT_NE(nested, &message1.optional_nested_message()); +} + +TEST(MovableMessageTest, MoveAssignmentOperator) { + protobuf_unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + const auto* nested = &message1.optional_nested_message(); + + protobuf_unittest::TestAllTypes message2; + message2 = std::move(message1); + TestUtil::ExpectAllFieldsSet(message2); + + // Check if the optional_nested_message was actually moved (and not just + // copied). + EXPECT_EQ(nested, &message2.optional_nested_message()); + EXPECT_NE(nested, &message1.optional_nested_message()); +} + +TEST(MovableMessageTest, SelfMoveAssignment) { + // The `self` reference is necessary to defeat -Wself-move. + protobuf_unittest::TestAllTypes message, &self = message; + TestUtil::SetAllFields(&message); + message = std::move(self); + TestUtil::ExpectAllFieldsSet(message); +} + +TEST(MovableMessageTest, MoveSameArena) { + Arena arena; + + auto* message1_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena); + TestUtil::SetAllFields(message1_on_arena); + const auto* nested = &message1_on_arena->optional_nested_message(); + + auto* message2_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena); + + // Moving messages on the same arena should lead to swapped pointers. + *message2_on_arena = std::move(*message1_on_arena); + EXPECT_EQ(nested, &message2_on_arena->optional_nested_message()); +} + +TEST(MovableMessageTest, MoveDifferentArenas) { + Arena arena1, arena2; + + auto* message1_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena1); + TestUtil::SetAllFields(message1_on_arena); + const auto* nested = &message1_on_arena->optional_nested_message(); + + auto* message2_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena2); + + // Moving messages on two different arenas should lead to a copy. + *message2_on_arena = std::move(*message1_on_arena); + EXPECT_NE(nested, &message2_on_arena->optional_nested_message()); + TestUtil::ExpectAllFieldsSet(*message1_on_arena); + TestUtil::ExpectAllFieldsSet(*message2_on_arena); +} + +TEST(MovableMessageTest, MoveFromArena) { + Arena arena; + + auto* message1_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena); + TestUtil::SetAllFields(message1_on_arena); + const auto* nested = &message1_on_arena->optional_nested_message(); + + protobuf_unittest::TestAllTypes message2; + + // Moving from a message on the arena should lead to a copy. + message2 = std::move(*message1_on_arena); + EXPECT_NE(nested, &message2.optional_nested_message()); + TestUtil::ExpectAllFieldsSet(*message1_on_arena); + TestUtil::ExpectAllFieldsSet(message2); +} + +TEST(MovableMessageTest, MoveToArena) { + Arena arena; + + protobuf_unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + const auto* nested = &message1.optional_nested_message(); + + auto* message2_on_arena = + Arena::CreateMessage<protobuf_unittest::TestAllTypes>(&arena); + + // Moving to a message on the arena should lead to a copy. + *message2_on_arena = std::move(message1); + EXPECT_NE(nested, &message2_on_arena->optional_nested_message()); + TestUtil::ExpectAllFieldsSet(message1); + TestUtil::ExpectAllFieldsSet(*message2_on_arena); +} + +TEST(MovableMessageTest, Noexcept) { + EXPECT_TRUE( + std::is_nothrow_move_constructible<protobuf_unittest::TestAllTypes>()); + EXPECT_TRUE(std::is_nothrow_move_assignable<protobuf_unittest::TestAllTypes>()); +} + +#endif // LANG_CXX11 + +} // namespace cpp_unittest + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index bdaa12a5..04338083 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -49,7 +49,8 @@ struct Options { transitive_pb_h(true), annotate_headers(false), enforce_lite(false), - table_driven_parsing(false) {} + table_driven_parsing(false), + table_driven_serialization(false) {} string dllexport_decl; bool safe_boundary_check; @@ -58,6 +59,7 @@ struct Options { bool annotate_headers; bool enforce_lite; bool table_driven_parsing; + bool table_driven_serialization; string annotation_pragma_name; string annotation_guard_name; }; diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index e45f35b3..b05fcc4e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -115,9 +115,11 @@ GeneratePrivateMembers(io::Printer* printer) const { 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$$type$ $name$() const;\n" - "$deprecated_attr$void set_$name$($type$ value);\n"); + "$deprecated_attr$void ${$set_$name$$}$($type$ value);\n"); + printer->Annotate("{", "}", descriptor_); } void PrimitiveFieldGenerator:: @@ -148,7 +150,7 @@ GenerateMergingCode(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { - printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); + printer->Print(variables_, "swap($name$_, other->$name$_);\n"); } void PrimitiveFieldGenerator:: @@ -290,14 +292,23 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$deprecated_attr$$type$ $name$(int index) const;\n" - "$deprecated_attr$void set_$name$(int index, $type$ value);\n" - "$deprecated_attr$void add_$name$($type$ value);\n"); + "$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$const ::google::protobuf::RepeatedField< $type$ >&\n" - " $name$() const;\n" - "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n" - " mutable_$name$();\n"); + "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n" + " ${$mutable_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); } void RepeatedPrimitiveFieldGenerator:: @@ -316,8 +327,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { "$inline$void $classname$::add_$name$($type$ value) {\n" " $name$_.Add(value);\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" - "}\n"); - printer->Print(variables, + "}\n" "$inline$const ::google::protobuf::RepeatedField< $type$ >&\n" "$classname$::$name$() const {\n" " // @@protoc_insertion_point(field_list:$full_name$)\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 6a710888..fec13b6d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -142,28 +142,47 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "$deprecated_attr$const ::std::string& $name$() const;\n" - "$deprecated_attr$void set_$name$(const ::std::string& value);\n"); + "$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_); - if (!SupportsArenas(descriptor_)) { - printer->Print(variables_, - "#if LANG_CXX11\n" - "$deprecated_attr$void set_$name$(::std::string&& value);\n" - "#endif\n"); - } + 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$void set_$name$(const char* value);\n" - "$deprecated_attr$void set_$name$(const $pointer_type$* value, size_t size)" - ";\n" - "$deprecated_attr$::std::string* mutable_$name$();\n" - "$deprecated_attr$::std::string* $release_name$();\n" - "$deprecated_attr$void set_allocated_$name$(::std::string* $name$);\n"); + "$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_, - "$deprecated_attr$::std::string* unsafe_arena_release_$name$();\n" - "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n" - " ::std::string* $name$);\n"); + printer->Print( + variables_, + "$deprecated_attr$::std::string* ${$unsafe_arena_release_$name$$}$();\n"); + printer->Annotate("{", "}", descriptor_); + printer->Print( + variables_, + "$deprecated_attr$void ${$unsafe_arena_set_allocated_$name$$}$(\n" + " ::std::string* $name$);\n"); + printer->Annotate("{", "}", descriptor_); } @@ -191,6 +210,14 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $name$_.Set($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" + " $set_hasbit$\n" + " $name$_.Set(\n" + " $default_variable$, ::std::move(value), GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n" + "}\n" + "#endif\n" "$inline$void $classname$::set_$name$(const char* value) {\n" " $null_check$" " $set_hasbit$\n" @@ -456,15 +483,10 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) const { printer->Print(variables_, "$classname$::$default_variable_name$.DefaultConstruct();\n" "*$classname$::$default_variable_name$.get_mutable() = " - "::std::string($default$, $default_length$);\n"); - } -} - -void StringFieldGenerator:: -GenerateShutdownCode(io::Printer* printer) const { - if (!descriptor_->default_value_string().empty()) { - printer->Print(variables_, - "$classname$::$default_variable_name$.Shutdown();\n"); + "::std::string($default$, $default_length$);\n" + "::google::protobuf::internal::OnShutdownDestroyString(\n" + " $classname$::$default_variable_name$.get_mutable());\n" + ); } } @@ -554,6 +576,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" + "#if LANG_CXX11\n" + "$inline$void $classname$::set_$name$(::std::string&& value) {\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.Set(\n" + " $default_variable$, ::std::move(value), GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n" + "}\n" + "#endif\n" "$inline$void $classname$::set_$name$(const char* value) {\n" " $null_check$" " if (!has_$name$()) {\n" @@ -837,28 +872,62 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "$deprecated_attr$const ::std::string& $name$(int index) const;\n" - "$deprecated_attr$::std::string* mutable_$name$(int index);\n" - "$deprecated_attr$void set_$name$(int index, const ::std::string& value);\n" - "#if LANG_CXX11\n" - "$deprecated_attr$void set_$name$(int index, ::std::string&& value);\n" - "#endif\n" - "$deprecated_attr$void set_$name$(int index, const char* value);\n" - "" - "$deprecated_attr$void set_$name$(" - "int index, const $pointer_type$* value, size_t size);\n" - "$deprecated_attr$::std::string* add_$name$();\n" - "$deprecated_attr$void add_$name$(const ::std::string& value);\n" - "#if LANG_CXX11\n" - "$deprecated_attr$void add_$name$(::std::string&& value);\n" - "#endif\n" - "$deprecated_attr$void add_$name$(const char* value);\n" - "$deprecated_attr$void add_$name$(const $pointer_type$* value, size_t size)" - ";\n" - "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() " - "const;\n" - "$deprecated_attr$::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" + "$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_, + "#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_); if (unknown_ctype) { printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index af263c1a..531252b0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -65,7 +65,6 @@ class StringFieldGenerator : public FieldGenerator { void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateDestructorCode(io::Printer* printer) const; void GenerateDefaultInstanceAllocator(io::Printer* printer) const; - void GenerateShutdownCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index e56964c7..fdde771b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -576,12 +576,73 @@ TEST(GeneratedMessageTest, SwapWithOther) { EXPECT_EQ(unittest::TestAllTypes::BAR, message2.repeated_nested_enum(1)); } -TEST(GeneratedMessageTest, CopyConstructor) { - unittest::TestAllTypes message1; +TEST(GeneratedMessageTest, ADLSwap) { + unittest::TestAllTypes message1, message2; TestUtil::SetAllFields(&message1); - unittest::TestAllTypes message2(message1); + // Note the address of one of the repeated fields, to verify it was swapped + // rather than copied. + const int32* addr = &message1.repeated_int32().Get(0); + + using std::swap; + swap(message1, message2); + TestUtil::ExpectAllFieldsSet(message2); + TestUtil::ExpectClear(message1); + + EXPECT_EQ(addr, &message2.repeated_int32().Get(0)); +} + +TEST(GeneratedMessageTest, CopyConstructor) { + // All set. + { + unittest::TestAllTypes message1; + TestUtil::SetAllFields(&message1); + + unittest::TestAllTypes message2(message1); + TestUtil::ExpectAllFieldsSet(message2); + } + + // None set. + { + unittest::TestAllTypes message1; + unittest::TestAllTypes message2(message1); + + EXPECT_FALSE(message1.has_optional_string()); + EXPECT_FALSE(message2.has_optional_string()); + EXPECT_EQ(&message1.optional_string(), + &message2.optional_string()); + + EXPECT_FALSE(message1.has_optional_bytes()); + EXPECT_FALSE(message2.has_optional_bytes()); + EXPECT_EQ(&message1.optional_bytes(), + &message2.optional_bytes()); + + EXPECT_FALSE(message1.has_optional_nested_message()); + EXPECT_FALSE(message2.has_optional_nested_message()); + EXPECT_EQ(&message1.optional_nested_message(), + &message2.optional_nested_message()); + + EXPECT_FALSE(message1.has_optional_foreign_message()); + EXPECT_FALSE(message2.has_optional_foreign_message()); + EXPECT_EQ(&message1.optional_foreign_message(), + &message2.optional_foreign_message()); + + EXPECT_FALSE(message1.has_optional_import_message()); + EXPECT_FALSE(message2.has_optional_import_message()); + EXPECT_EQ(&message1.optional_import_message(), + &message2.optional_import_message()); + + EXPECT_FALSE(message1.has_optional_public_import_message()); + EXPECT_FALSE(message2.has_optional_public_import_message()); + EXPECT_EQ(&message1.optional_public_import_message(), + &message2.optional_public_import_message()); + + EXPECT_FALSE(message1.has_optional_lazy_message()); + EXPECT_FALSE(message2.has_optional_lazy_message()); + EXPECT_EQ(&message1.optional_lazy_message(), + &message2.optional_lazy_message()); + } } TEST(GeneratedMessageTest, CopyConstructorWithArenas) { @@ -1340,7 +1401,7 @@ class GeneratedServiceTest : public testing::Test { foo_(descriptor_->FindMethodByName("Foo")), bar_(descriptor_->FindMethodByName("Bar")), stub_(&mock_channel_), - done_(NewPermanentCallback(&DoNothing)) {} + done_(::google::protobuf::NewPermanentCallback(&DoNothing)) {} virtual void SetUp() { ASSERT_TRUE(foo_ != NULL); |