diff options
author | Adam Cozzette <acozzette@google.com> | 2016-11-17 16:48:38 -0800 |
---|---|---|
committer | Adam Cozzette <acozzette@google.com> | 2016-11-17 16:59:59 -0800 |
commit | 5a76e633ea9b5adb215e93fdc11e1c0c08b3fc74 (patch) | |
tree | 0276f81f8848a05d84cd7e287b43d665e30f04e3 /src/google/protobuf/compiler/cpp | |
parent | e28286fa05d8327fd6c5aa70cfb3be558f0932b8 (diff) |
Integrated internal changes from Google
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
27 files changed, 2122 insertions, 1968 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index deef290b..bf4e5831 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -114,7 +114,7 @@ class MockGeneratorContext : public GeneratorContext { } private: - map<string, string*> files_; + std::map<string, string*> files_; }; TEST(BootstrapTest, GeneratedDescriptorMatches) { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 6ced26bc..9493d5f8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -70,7 +70,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, EnumGenerator::~EnumGenerator() {} void EnumGenerator::FillForwardDeclaration( - map<string, const EnumDescriptor*>* enum_names) { + std::map<string, const EnumDescriptor*>* enum_names) { if (!options_.proto_h) { return; } @@ -78,7 +78,7 @@ void EnumGenerator::FillForwardDeclaration( } void EnumGenerator::GenerateDefinition(io::Printer* printer) { - map<string, string> vars; + std::map<string, string> vars; vars["classname"] = classname_; vars["short_name"] = descriptor_->name(); vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : ""); @@ -180,7 +180,7 @@ GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { } void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { - map<string, string> vars; + std::map<string, string> vars; vars["nested_name"] = descriptor_->name(); vars["classname"] = classname_; vars["constexpr"] = options_.proto_h ? "constexpr " : ""; @@ -229,33 +229,36 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { } } -void EnumGenerator::GenerateDescriptorInitializer( - io::Printer* printer, int index) { - map<string, string> vars; - vars["classname"] = classname_; - vars["index"] = SimpleItoa(index); +void EnumGenerator::GenerateDescriptorInitializer(io::Printer* printer) { + std::map<string, string> vars; + vars["index"] = SimpleItoa(descriptor_->index()); + vars["index_in_metadata"] = SimpleItoa(index_in_metadata_); if (descriptor_->containing_type() == NULL) { printer->Print(vars, - "$classname$_descriptor_ = file->enum_type($index$);\n"); + "file_level_enum_descriptors[$index_in_metadata$] = " + "file->enum_type($index$);\n"); } else { vars["parent"] = ClassName(descriptor_->containing_type(), false); printer->Print(vars, - "$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n"); + "file_level_enum_descriptors[$index_in_metadata$] = " + "$parent$_descriptor->enum_type($index$);\n"); } } void EnumGenerator::GenerateMethods(io::Printer* printer) { - map<string, string> vars; + std::map<string, string> vars; vars["classname"] = classname_; + vars["index_in_metadata"] = SimpleItoa(index_in_metadata_); vars["constexpr"] = options_.proto_h ? "constexpr " : ""; if (HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print(vars, - "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" - " protobuf_AssignDescriptorsOnce();\n" - " return $classname$_descriptor_;\n" - "}\n"); + printer->Print( + vars, + "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" + " return file_level_enum_descriptors[$index_in_metadata$];\n" + "}\n"); } printer->Print(vars, @@ -266,13 +269,13 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { // each number once by first constructing a set containing all valid // numbers, then printing a case statement for each element. - set<int> numbers; + std::set<int> numbers; for (int j = 0; j < descriptor_->value_count(); j++) { const EnumValueDescriptor* value = descriptor_->value(j); numbers.insert(value->number()); } - for (set<int>::iterator iter = numbers.begin(); + for (std::set<int>::iterator iter = numbers.begin(); iter != numbers.end(); ++iter) { printer->Print( " case $number$:\n", diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 90edf001..0b568c57 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -66,7 +66,8 @@ class EnumGenerator { // enums. A given key in enum_names will map from an enum class name to the // EnumDescriptor that was responsible for its inclusion in the map. This can // be used to associate the descriptor with the code generated for it. - void FillForwardDeclaration(map<string, const EnumDescriptor*>* enum_names); + void FillForwardDeclaration( + std::map<string, const EnumDescriptor*>* enum_names); // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for @@ -87,7 +88,7 @@ class EnumGenerator { // Generate code that initializes the global variable storing the enum's // descriptor. - void GenerateDescriptorInitializer(io::Printer* printer, int index); + void GenerateDescriptorInitializer(io::Printer* printer); // Generate non-inline methods related to the enum, such as IsValidValue(). // Goes in the .cc file. @@ -100,6 +101,9 @@ class EnumGenerator { // whether to generate the *_ARRAYSIZE constant. const bool generate_array_size_; + int index_in_metadata_; + + friend class FileGenerator; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index c3dfa817..093bf06c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -46,7 +46,7 @@ namespace cpp { namespace { void SetEnumVariables(const FieldDescriptor* descriptor, - map<string, string>* variables, + std::map<string, string>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); const EnumValueDescriptor* default_value = descriptor->default_value_enum(); @@ -82,7 +82,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void EnumFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$$type$ $classname$::$name$() const {\n" @@ -122,6 +122,11 @@ GenerateConstructorCode(io::Printer* printer) const { } void EnumFieldGenerator:: +GenerateCopyConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = from.$name$_;\n"); +} + +void EnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "int value;\n" @@ -186,7 +191,7 @@ EnumOneofFieldGenerator::~EnumOneofFieldGenerator() {} void EnumOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$$type$ $classname$::$name$() const {\n" @@ -223,8 +228,9 @@ GenerateSwappingCode(io::Printer* printer) const { void EnumOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - printer->Print(variables_, - " $classname$_default_oneof_instance_->$name$_ = $default$;\n"); + printer->Print( + variables_, + " $classname$_default_oneof_instance_.$name$_ = $default$;\n"); } // =================================================================== @@ -262,7 +268,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$$type$ $classname$::$name$(int index) const {\n" @@ -311,11 +317,6 @@ GenerateMergingCode(io::Printer* printer) const { } void RepeatedEnumFieldGenerator:: -GenerateUnsafeMergingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.UnsafeMergeFrom(from.$name$_);\n"); -} - -void RepeatedEnumFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index 57ffeec5..3ecd7ba8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -58,6 +58,7 @@ class EnumFieldGenerator : public FieldGenerator { void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; @@ -65,7 +66,7 @@ class EnumFieldGenerator : public FieldGenerator { protected: const FieldDescriptor* descriptor_; - map<string, string> variables_; + std::map<string, string> variables_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); @@ -101,9 +102,9 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; - void GenerateUnsafeMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const {} void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; @@ -112,7 +113,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { private: const FieldDescriptor* descriptor_; - map<string, string> variables_; + std::map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 4554c72c..e4fce461 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -92,7 +92,7 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, ExtensionGenerator::~ExtensionGenerator() {} void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { - map<string, string> vars; + std::map<string, string> vars; vars["extendee" ] = ExtendeeClassName(descriptor_); vars["number" ] = SimpleItoa(descriptor_->number()); vars["type_traits" ] = type_traits_; @@ -128,7 +128,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { ClassName(descriptor_->extension_scope(), false) + "::"; string name = scope + descriptor_->name(); - map<string, string> vars; + std::map<string, string> vars; vars["extendee" ] = ExtendeeClassName(descriptor_); vars["type_traits" ] = type_traits_; vars["name" ] = name; @@ -167,7 +167,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { } void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { - map<string, string> vars; + std::map<string, string> vars; vars["extendee" ] = ExtendeeClassName(descriptor_); vars["number" ] = SimpleItoa(descriptor_->number()); vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index e2033c1a..4480a9d2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -59,7 +59,7 @@ namespace cpp { using internal::WireFormat; void SetCommonFieldVariables(const FieldDescriptor* descriptor, - map<string, string>* variables, + std::map<string, string>* variables, const Options& options) { (*variables)["name"] = FieldName(descriptor); (*variables)["index"] = SimpleItoa(descriptor->index()); @@ -98,7 +98,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, } void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, - map<string, string>* variables) { + std::map<string, string>* variables) { const string prefix = descriptor->containing_oneof()->name() + "_."; (*variables)["oneof_prefix"] = prefix; (*variables)["oneof_name"] = descriptor->containing_oneof()->name(); diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index fdd338a6..00dc25d4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -61,11 +61,11 @@ namespace cpp { // ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size', // 'deprecation']. void SetCommonFieldVariables(const FieldDescriptor* descriptor, - map<string, string>* variables, + std::map<string, string>* variables, const Options& options); void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, - map<string, string>* variables); + std::map<string, string>* variables); class FieldGenerator { public: @@ -124,10 +124,20 @@ class FieldGenerator { io::Printer* /*printer*/) const {} // Generate lines of code (statements, not declarations) which clear the - // field. This is used to define the clear_$name$() method as well as - // the Clear() method for the whole message. + // field. This is used to define the clear_$name$() method virtual void GenerateClearingCode(io::Printer* printer) const = 0; + // Generate lines of code (statements, not declarations) which clear the field + // as part of the Clear() method for the whole message. For message types + // which have field presence bits, MessageGenerator::GenerateClear will have + // already checked the presence bits. + // + // Since most field types can re-use GenerateClearingCode, this method is not + // pure virtual. + virtual void GenerateMessageClearingCode(io::Printer* printer) const { + GenerateClearingCode(printer); + } + // Generate lines of code (statements, not declarations) which merges the // contents of the field from the current message to the target message, // which is stored in the generated code variable "from". @@ -136,12 +146,8 @@ class FieldGenerator { // GenerateMergeFrom method. virtual void GenerateMergingCode(io::Printer* printer) const = 0; - // The same, but the generated code may or may not check the possibility that - // the two objects being merged have the same address. To be safe, callers - // should avoid calling this unless they know the objects are different. - virtual void GenerateUnsafeMergingCode(io::Printer* printer) const { - GenerateMergingCode(printer); - } + // Generates a copy constructor + virtual void GenerateCopyConstructorCode(io::Printer* printer) const = 0; // Generate lines of code (statements, not declarations) which swaps // this field and the corresponding field of another message, which diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 369497ce..63aee4ff 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -60,33 +60,42 @@ namespace cpp { FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) : file_(file), options_(options), - message_generators_( - new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]), - enum_generators_( - new google::protobuf::scoped_ptr<EnumGenerator>[file->enum_type_count()]), - service_generators_( - new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]), - extension_generators_( - new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]) { + message_generators_owner_( + new google::protobuf::scoped_ptr<MessageGenerator>[ file->message_type_count() ]), + enum_generators_owner_( + new google::protobuf::scoped_ptr<EnumGenerator>[ file->enum_type_count() ]), + service_generators_owner_( + new google::protobuf::scoped_ptr<ServiceGenerator>[ file->service_count() ]), + extension_generators_owner_( + new google::protobuf::scoped_ptr<ExtensionGenerator>[ file->extension_count() ]) { for (int i = 0; i < file->message_type_count(); i++) { - message_generators_[i].reset( - new MessageGenerator(file->message_type(i), options)); + message_generators_owner_[i].reset( + new MessageGenerator(file->message_type(i), options)); + message_generators_owner_[i]->Flatten(&message_generators_); + } + + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->AddGenerators(&enum_generators_, + &extension_generators_); } for (int i = 0; i < file->enum_type_count(); i++) { - enum_generators_[i].reset( - new EnumGenerator(file->enum_type(i), options)); + enum_generators_owner_[i].reset( + new EnumGenerator(file->enum_type(i), options)); + enum_generators_.push_back(enum_generators_owner_[i].get()); } for (int i = 0; i < file->service_count(); i++) { - service_generators_[i].reset( - new ServiceGenerator(file->service(i), options)); + service_generators_owner_[i].reset( + new ServiceGenerator(file->service(i), options)); + service_generators_.push_back(service_generators_owner_[i].get()); } for (int i = 0; i < file->extension_count(); i++) { - extension_generators_[i].reset( - new ExtensionGenerator(file->extension(i), options)); + extension_generators_owner_[i].reset( + new ExtensionGenerator(file->extension(i), options)); + extension_generators_.push_back(extension_generators_owner_[i].get()); } package_parts_ = Split(file_->package(), ".", true); @@ -94,29 +103,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) FileGenerator::~FileGenerator() {} -void FileGenerator::GenerateProtoHeader(io::Printer* printer, - const string& info_path) { - if (!options_.proto_h) { - return; - } - - string filename_identifier = FilenameIdentifier(file_->name()); - GenerateTopHeaderGuard(printer, filename_identifier); - - - GenerateLibraryIncludes(printer); - - for (int i = 0; i < file_->public_dependency_count(); i++) { - const FileDescriptor* dep = file_->public_dependency(i); - const char* extension = ".proto.h"; - string dependency = StripProto(dep->name()) + extension; - printer->Print( - "#include \"$dependency$\" // IWYU pragma: export\n", - "dependency", dependency); - } - - GenerateMetadataPragma(printer, info_path); - +void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -166,6 +153,32 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer, "\n" "// @@protoc_insertion_point(global_scope)\n" "\n"); +} + +void FileGenerator::GenerateProtoHeader(io::Printer* printer, + const string& info_path) { + if (!options_.proto_h) { + return; + } + + string filename_identifier = FilenameIdentifier(file_->name()); + GenerateTopHeaderGuard(printer, filename_identifier); + + + GenerateLibraryIncludes(printer); + + for (int i = 0; i < file_->public_dependency_count(); i++) { + const FileDescriptor* dep = file_->public_dependency(i); + const char* extension = ".proto.h"; + string dependency = StripProto(dep->name()) + extension; + printer->Print( + "#include \"$dependency$\" // IWYU pragma: export\n", + "dependency", dependency); + } + + GenerateMetadataPragma(printer, info_path); + + GenerateHeader(printer); GenerateBottomHeaderGuard(printer, filename_identifier); } @@ -185,59 +198,29 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer, GenerateDependencyIncludes(printer); GenerateMetadataPragma(printer, info_path); - printer->Print( - "// @@protoc_insertion_point(includes)\n"); - - - - // Open namespace. - GenerateNamespaceOpeners(printer); - if (!options_.proto_h) { - GenerateGlobalStateFunctionDeclarations(printer); - GenerateMessageForwardDeclarations(printer); - - printer->Print("\n"); - - GenerateEnumDefinitions(printer); - - printer->Print(kThickSeparator); - printer->Print("\n"); - - GenerateMessageDefinitions(printer); - - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); - - GenerateServiceDefinitions(printer); - - GenerateExtensionIdentifiers(printer); - - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); - - GenerateInlineFunctionDefinitions(printer); - } - - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); + GenerateHeader(printer); + } else { + // This is unfortunately necessary for some plugins. I don't see why we + // need two of the same insertion points. + // TODO(gerbens) remove this. + printer->Print( + "// @@protoc_insertion_point(includes)\n"); - // Close up namespace. - GenerateNamespaceClosers(printer); + // Open namespace. + GenerateNamespaceOpeners(printer); + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + // Close up namespace. + GenerateNamespaceClosers(printer); - if (!options_.proto_h) { - // We need to specialize some templates in the ::google::protobuf namespace: - GenerateProto2NamespaceEnumSpecializations(printer); + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); } - printer->Print( - "\n" - "// @@protoc_insertion_point(global_scope)\n" - "\n"); - GenerateBottomHeaderGuard(printer, filename_identifier); } @@ -267,7 +250,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "right", use_system_include ? ">" : "\""); // Unknown fields implementation in lite mode uses StringOutputStream - if (!UseUnknownFieldSet(file_, options_) && file_->message_type_count() > 0) { + if (!UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { printer->Print( "#include <google/protobuf/io/zero_copy_stream_impl_lite.h>\n"); } @@ -297,25 +280,48 @@ void FileGenerator::GenerateSource(io::Printer* printer) { GenerateNamespaceOpeners(printer); + for (int i = 0; i < message_generators_.size(); i++) { + if (IsMapEntryMessage(message_generators_[i]->descriptor_)) continue; + printer->Print( + "class $classname$DefaultTypeInternal : " + "public ::google::protobuf::internal::ExplicitlyConstructed<$classname$> {};\n" + "$classname$DefaultTypeInternal _$classname$_default_instance_;\n", + "classname", message_generators_[i]->classname_); + } + if (HasDescriptorMethods(file_, options_)) { printer->Print( "\n" "namespace {\n" "\n"); - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateDescriptorDeclarations(printer); + + if (!message_generators_.empty()) { + printer->Print("::google::protobuf::Metadata file_level_metadata[$size$];\n", + "size", SimpleItoa(message_generators_.size())); } - for (int i = 0; i < file_->enum_type_count(); i++) { + if (!enum_generators_.empty()) { printer->Print( - "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n", - "name", ClassName(file_->enum_type(i), false)); + "const ::google::protobuf::EnumDescriptor* " + "file_level_enum_descriptors[$size$];\n", + "size", SimpleItoa(enum_generators_.size())); + } + if (HasGenericServices(file_, options_) && file_->service_count() > 0) { + printer->Print( + "const ::google::protobuf::ServiceDescriptor* " + "file_level_service_descriptors[$size$];\n", + "size", SimpleItoa(file_->service_count())); } + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->index_in_metadata_ = i; + message_generators_[i]->GenerateDescriptorDeclarations(printer); + } + for (int i = 0; i < enum_generators_.size(); i++) { + enum_generators_[i]->index_in_metadata_ = i; + } if (HasGenericServices(file_, options_)) { - for (int i = 0; i < file_->service_count(); i++) { - printer->Print( - "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n", - "name", file_->service(i)->name()); + for (int i = 0; i < service_generators_.size(); i++) { + service_generators_[i]->index_in_metadata_ = i; } } @@ -330,26 +336,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) { GenerateBuildDescriptors(printer); // Generate enums. - for (int i = 0; i < file_->enum_type_count(); i++) { + for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->GenerateMethods(printer); } // Generate classes. - for (int i = 0; i < file_->message_type_count(); i++) { - if (i == 0 && HasGeneratedMethods(file_, options_)) { - printer->Print( - "\n" - "namespace {\n" - "\n" - "static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD" - " GOOGLE_ATTRIBUTE_NORETURN;\n" - "static void MergeFromFail(int line) {\n" - " ::google::protobuf::internal::MergeFromFail(__FILE__, line);\n" - "}\n" - "\n" - "} // namespace\n" - "\n"); - } + for (int i = 0; i < message_generators_.size(); i++) { printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); @@ -364,7 +356,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { if (HasGenericServices(file_, options_)) { // Generate services. - for (int i = 0; i < file_->service_count(); i++) { + for (int i = 0; i < service_generators_.size(); i++) { if (i == 0) printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); @@ -373,7 +365,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { } // Define extensions. - for (int i = 0; i < file_->extension_count(); i++) { + for (int i = 0; i < extension_generators_.size(); i++) { extension_generators_[i]->GenerateDefinition(printer); } @@ -391,8 +383,9 @@ void FileGenerator::GenerateSource(io::Printer* printer) { class FileGenerator::ForwardDeclarations { public: ~ForwardDeclarations() { - for (map<string, ForwardDeclarations *>::iterator it = namespaces_.begin(), - end = namespaces_.end(); + for (std::map<string, ForwardDeclarations*>::iterator + it = namespaces_.begin(), + end = namespaces_.end(); it != end; ++it) { delete it->second; } @@ -407,11 +400,11 @@ class FileGenerator::ForwardDeclarations { return ns; } - map<string, const Descriptor*>& classes() { return classes_; } - map<string, const EnumDescriptor*>& enums() { return enums_; } + std::map<string, const Descriptor*>& classes() { return classes_; } + std::map<string, const EnumDescriptor*>& enums() { return enums_; } void Print(io::Printer* printer) const { - for (map<string, const EnumDescriptor *>::const_iterator + for (std::map<string, const EnumDescriptor *>::const_iterator it = enums_.begin(), end = enums_.end(); it != end; ++it) { @@ -420,13 +413,21 @@ class FileGenerator::ForwardDeclarations { printer->Print("bool $enumname$_IsValid(int value);\n", "enumname", it->first); } - for (map<string, const Descriptor *>::const_iterator it = classes_.begin(), - end = classes_.end(); + for (std::map<string, const Descriptor*>::const_iterator + it = classes_.begin(), + end = classes_.end(); it != end; ++it) { printer->Print("class $classname$;\n", "classname", it->first); printer->Annotate("classname", it->second); + + printer->Print( + "class $classname$DefaultTypeInternal;\n" + "extern $classname$DefaultTypeInternal " + "_$classname$_default_instance_;\n", // NOLINT + "classname", + it->first); } - for (map<string, ForwardDeclarations *>::const_iterator + for (std::map<string, ForwardDeclarations *>::const_iterator it = namespaces_.begin(), end = namespaces_.end(); it != end; ++it) { @@ -440,9 +441,9 @@ class FileGenerator::ForwardDeclarations { private: - map<string, ForwardDeclarations*> namespaces_; - map<string, const Descriptor*> classes_; - map<string, const EnumDescriptor*> enums_; + std::map<string, ForwardDeclarations*> namespaces_; + std::map<string, const Descriptor*> classes_; + std::map<string, const EnumDescriptor*> enums_; }; void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { @@ -465,75 +466,135 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // and we only use AddDescriptors() to allocate default instances. if (HasDescriptorMethods(file_, options_)) { - printer->Print( - "\n" - "void $assigndescriptorsname$() GOOGLE_ATTRIBUTE_COLD;\n" - "void $assigndescriptorsname$() {\n", - "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); - printer->Indent(); - - // Make sure the file has found its way into the pool. If a descriptor - // is requested *during* static init then AddDescriptors() may not have - // been called yet, so we call it manually. Note that it's fine if - // AddDescriptors() is called multiple times. - printer->Print( - "$adddescriptorsname$();\n", - "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); + if (!message_generators_.empty()) { + printer->Print( + "\n" + "const ::google::protobuf::uint32* $offsetfunname$() GOOGLE_ATTRIBUTE_COLD;\n" + "const ::google::protobuf::uint32* $offsetfunname$() {\n", + "offsetfunname", GlobalOffsetTableName(file_->name())); + printer->Indent(); - // Get the file's descriptor from the pool. - printer->Print( - "const ::google::protobuf::FileDescriptor* file =\n" - " ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n" - " \"$filename$\");\n" - // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file" - // being unused when compiling an empty .proto file. - "GOOGLE_CHECK(file != NULL);\n", - "filename", file_->name()); + printer->Print("static const ::google::protobuf::uint32 offsets[] = {\n"); + printer->Indent(); + std::vector<std::pair<size_t, size_t> > pairs; + for (int i = 0; i < message_generators_.size(); i++) { + pairs.push_back(message_generators_[i]->GenerateOffsets(printer)); + } + printer->Outdent(); + printer->Outdent(); + printer->Print( + " };\n" + " return offsets;\n" + "}\n" + "\n"); - // Go through all the stuff defined in this file and generated code to - // assign the global descriptor pointers based on the file descriptor. - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateDescriptorInitializer(printer, i); - } - for (int i = 0; i < file_->enum_type_count(); i++) { - enum_generators_[i]->GenerateDescriptorInitializer(printer, i); - } - if (HasGenericServices(file_, options_)) { - for (int i = 0; i < file_->service_count(); i++) { - service_generators_[i]->GenerateDescriptorInitializer(printer, i); + printer->Print( + "static const ::google::protobuf::internal::MigrationSchema schemas[] = {\n"); + printer->Indent(); + { + int offset = 0; + for (int i = 0; i < message_generators_.size(); i++) { + message_generators_[i]->GenerateSchema(printer, offset, + pairs[i].second); + offset += pairs[i].first; + } + } + printer->Outdent(); + printer->Print( + "};\n" + "\n" + "static const ::google::protobuf::internal::DefaultInstanceData " + "file_default_instances[] = {\n"); + printer->Indent(); + for (int i = 0; i < message_generators_.size(); i++) { + const Descriptor* descriptor = message_generators_[i]->descriptor_; + if (IsMapEntryMessage(descriptor)) continue; + + string oneof_default = "NULL"; + if (message_generators_[i]->descriptor_->oneof_decl_count()) { + oneof_default = + "&" + ClassName(descriptor, false) + "_default_oneof_instance_"; + } + printer->Print( + "{reinterpret_cast<const " + "::google::protobuf::Message*>(&_$classname$_default_instance_), " + "$oneof_default$},\n", + "classname", ClassName(descriptor, false), "oneof_default", + oneof_default); } + printer->Outdent(); + printer->Print( + "};\n" + "\n"); + } else { + // we still need these symbols to exist + printer->Print( + "inline ::google::protobuf::uint32* $offsetfunname$() { return NULL; }\n" + "static const ::google::protobuf::internal::MigrationSchema* schemas = NULL;\n" + "static const ::google::protobuf::internal::DefaultInstanceData* " + "file_default_instances = NULL;\n", + "offsetfunname", + GlobalOffsetTableName(file_->name())); } - printer->Outdent(); - printer->Print( - "}\n" - "\n"); - // --------------------------------------------------------------- // protobuf_AssignDescriptorsOnce(): The first time it is called, calls // AssignDescriptors(). All later times, waits for the first call to // complete and then returns. + string message_factory = "NULL"; printer->Print( "namespace {\n" "\n" - "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n" + "void protobuf_AssignDescriptors() {\n" + // Make sure the file has found its way into the pool. If a descriptor + // is requested *during* static init then AddDescriptors() may not have + // been called yet, so we call it manually. Note that it's fine if + // AddDescriptors() is called multiple times. + " $adddescriptorsname$();\n" + " ::google::protobuf::MessageFactory* factory = $factory$;\n" + " AssignDescriptors(\n" + " \"$filename$\", schemas, file_default_instances, " + "$offsetfunname$(), factory,\n" + " $metadata$, $enum_descriptors$, $service_descriptors$);\n" + "}\n" + "\n" "void protobuf_AssignDescriptorsOnce() {\n" - " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n" - " &$assigndescriptorsname$);\n" + " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" + " ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);\n" "}\n" "\n", - "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); - - // protobuf_RegisterTypes(): Calls - // MessageFactory::InternalRegisterGeneratedType() for each message type. + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), + "offsetfunname", GlobalOffsetTableName(file_->name()), "filename", + file_->name(), "metadata", + !message_generators_.empty() ? "file_level_metadata" : "NULL", + "enum_descriptors", + !enum_generators_.empty() ? "file_level_enum_descriptors" : "NULL", + "service_descriptors", + HasGenericServices(file_, options_) && file_->service_count() > 0 + ? "file_level_service_descriptors" + : "NULL", + "factory", message_factory); + + // Only here because of useless string reference that we don't want in + // protobuf_AssignDescriptorsOnce, because that is called from all the + // GetMetadata member methods. printer->Print( "void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;\n" "void protobuf_RegisterTypes(const ::std::string&) {\n" " protobuf_AssignDescriptorsOnce();\n"); printer->Indent(); - for (int i = 0; i < file_->message_type_count(); i++) { + // All normal messages can be done generically + if (!message_generators_.empty()) { + printer->Print( + "::google::protobuf::internal::RegisterAllTypes(file_level_metadata, $size$);\n", + "size", SimpleItoa(message_generators_.size())); + } + + // Map types are treated special + // TODO(gerbens) find a way to treat maps more like normal messages. + for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->GenerateTypeRegistrations(printer); } @@ -553,7 +614,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "shutdownfilename", GlobalShutdownFileName(file_->name())); printer->Indent(); - for (int i = 0; i < file_->message_type_count(); i++) { + for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->GenerateShutdownCode(printer); } @@ -566,8 +627,8 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // Now generate the InitDefaults() function. printer->Print( "void $initdefaultsname$_impl() {\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - "\n", + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n" + "", // Vars. "initdefaultsname", GlobalInitDefaultsName(file_->name())); @@ -586,26 +647,28 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "name", add_desc_name); } + // Force initialization of primitive values we depend on. + printer->Print("::google::protobuf::internal::InitProtobufDefaults();\n"); + // Allocate and initialize default instances. This can't be done lazily // since default instances are returned by simple accessors and are used with // extensions. Speaking of which, we also register extensions at this time. - for (int i = 0; i < file_->message_type_count(); i++) { + for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->GenerateDefaultInstanceAllocator(printer); } - for (int i = 0; i < file_->extension_count(); i++) { + for (int i = 0; i < extension_generators_.size(); i++) { extension_generators_[i]->GenerateRegistration(printer); } - for (int i = 0; i < file_->message_type_count(); i++) { + for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->GenerateDefaultInstanceInitializer(printer); } printer->Outdent(); printer->Print( "}\n" "\n" - "GOOGLE_PROTOBUF_DECLARE_ONCE($initdefaultsname$_once_);\n" "void $initdefaultsname$() {\n" - " ::google::protobuf::GoogleOnceInit(&$initdefaultsname$_once_,\n" - " &$initdefaultsname$_impl);\n" + " static GOOGLE_PROTOBUF_DECLARE_ONCE(once);\n" + " ::google::protobuf::GoogleOnceInit(&once, &$initdefaultsname$_impl);\n" "}\n", "initdefaultsname", GlobalInitDefaultsName(file_->name())); @@ -614,8 +677,6 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // Now generate the AddDescriptors() function. printer->Print( "void $adddescriptorsname$_impl() {\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - "\n" " $initdefaultsname$();\n", // Vars. "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), @@ -632,60 +693,42 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { string file_data; file_proto.SerializeToString(&file_data); + printer->Print("static const char descriptor[] = {\n"); + printer->Indent(); + #ifdef _MSC_VER bool breakdown_large_file = true; #else bool breakdown_large_file = false; #endif - // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535 - // bytes in length". Declare a static array of characters rather than use a - // string literal. - if (breakdown_large_file && file_data.size() > 65535) { - // This has to be explicitly marked as a signed char because the generated - // code puts negative values in the array, and sometimes plain char is - // unsigned. That implicit narrowing conversion is not allowed in C++11. - // <http://stackoverflow.com/questions/4434140/narrowing-conversions-in-c0x-is-it-just-me-or-does-this-sound-like-a-breakin> - // has details on why. - printer->Print( - "static const signed char descriptor[] = {\n"); - printer->Indent(); - - // Only write 25 bytes per line. + if (breakdown_large_file && file_data.size() > 66538) { + // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535 + // bytes in length". Declare a static array of characters rather than use + // a string literal. Only write 25 bytes per line. static const int kBytesPerLine = 25; for (int i = 0; i < file_data.size();) { - for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { - printer->Print( - "$char$, ", - "char", SimpleItoa(file_data[i])); - } - printer->Print( - "\n"); + for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { + printer->Print("'$char$', ", "char", + CEscape(file_data.substr(i, 1))); + } + printer->Print("\n"); } - - printer->Outdent(); - printer->Print( - "};\n"); - - printer->Print( - "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n", - "size", SimpleItoa(file_data.size())); - } else { - printer->Print( - "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); - // Only write 40 bytes per line. static const int kBytesPerLine = 40; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { - printer->Print("\n \"$data$\"", - "data", - EscapeTrigraphs( - CEscape(file_data.substr(i, kBytesPerLine)))); + printer->Print(" \"$data$\"\n", "data", + EscapeTrigraphs(CEscape( + file_data.substr(i, kBytesPerLine)))); + } } + + printer->Outdent(); + printer->Print("};\n"); printer->Print( - ", $size$);\n", + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(\n" + " descriptor, $size$);\n", "size", SimpleItoa(file_data.size())); - } // Call MessageFactory::InternalRegisterGeneratedFile(). printer->Print( @@ -777,14 +820,11 @@ void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) { decls = decls->AddOrGetNamespace(package_parts_[i]); } // Generate enum definitions. - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->FillEnumForwardDeclarations(&decls->enums()); - } - for (int i = 0; i < file_->enum_type_count(); i++) { + for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->FillForwardDeclaration(&decls->enums()); } // Generate forward declarations of classes. - for (int i = 0; i < file_->message_type_count(); i++) { + for (int i = 0; i < message_generators_.size(); i++) { message_generators_[i]->FillMessageForwardDeclarations( &decls->classes()); } @@ -840,12 +880,10 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { printer->Print( "#include <google/protobuf/arena.h>\n" "#include <google/protobuf/arenastring.h>\n" - "#include <google/protobuf/generated_message_util.h>\n"); - if (UseUnknownFieldSet(file_, options_)) { - printer->Print( - "#include <google/protobuf/metadata.h>\n"); - } - if (file_->message_type_count() > 0) { + "#include <google/protobuf/generated_message_util.h>\n" + "#include <google/protobuf/metadata.h>\n"); + + if (!message_generators_.empty()) { if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include <google/protobuf/message.h>\n"); @@ -855,8 +893,10 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { } } printer->Print( - "#include <google/protobuf/repeated_field.h>\n" - "#include <google/protobuf/extension_set.h>\n"); + "#include <google/protobuf/repeated_field.h>" + " // IWYU pragma: export\n" + "#include <google/protobuf/extension_set.h>" + " // IWYU pragma: export\n"); if (HasMapFields(file_)) { printer->Print( "#include <google/protobuf/map.h>\n"); @@ -884,7 +924,7 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { "#include <google/protobuf/service.h>\n"); } - if (UseUnknownFieldSet(file_, options_) && file_->message_type_count() > 0) { + if (UseUnknownFieldSet(file_, options_) && !message_generators_.empty()) { printer->Print( "#include <google/protobuf/unknown_field_set.h>\n"); } @@ -910,7 +950,7 @@ void FileGenerator::GenerateMetadataPragma(io::Printer* printer, } void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { - set<string> public_import_names; + std::set<string> public_import_names; for (int i = 0; i < file_->public_dependency_count(); i++) { public_import_names.insert(file_->public_dependency(i)->name()); } @@ -943,33 +983,11 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "dllexport_decl", options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); - - printer->Print( - // Note that we don't put dllexport_decl on these because they are only - // called by the .pb.cc file in which they are defined. - "void $assigndescriptorsname$();\n" - "void $shutdownfilename$();\n" - "\n", - "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()), - "shutdownfilename", GlobalShutdownFileName(file_->name())); -} - -void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) { - map<string, const Descriptor*> classes; - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->FillMessageForwardDeclarations(&classes); - } - for (map<string, const Descriptor *>::const_iterator it = classes.begin(), - end = classes.end(); - it != end; ++it) { - printer->Print("class $classname$;\n", "classname", it->first); - printer->Annotate("classname", it->second); - } } void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { // Generate class definitions. - for (int i = 0; i < file_->message_type_count(); i++) { + for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { printer->Print("\n"); printer->Print(kThinSeparator); @@ -981,10 +999,7 @@ void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { // Generate enum definitions. - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateEnumDefinitions(printer); - } - for (int i = 0; i < file_->enum_type_count(); i++) { + for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->GenerateDefinition(printer); } } @@ -992,7 +1007,7 @@ void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { if (HasGenericServices(file_, options_)) { // Generate service definitions. - for (int i = 0; i < file_->service_count(); i++) { + for (int i = 0; i < service_generators_.size(); i++) { if (i > 0) { printer->Print("\n"); printer->Print(kThinSeparator); @@ -1008,9 +1023,10 @@ void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { } void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { - // Declare extension identifiers. + // Declare extension identifiers. These are in global scope and so only + // the global scope extensions. for (int i = 0; i < file_->extension_count(); i++) { - extension_generators_[i]->GenerateDeclaration(printer); + extension_generators_owner_[i]->GenerateDeclaration(printer); } } @@ -1051,7 +1067,7 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); // Generate class inline methods. - for (int i = 0; i < file_->message_type_count(); i++) { + for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { printer->Print(kThinSeparator); printer->Print("\n"); @@ -1061,7 +1077,7 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { } printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); - for (int i = 0; i < file_->message_type_count(); i++) { + for (int i = 0; i < message_generators_.size(); i++) { if (i > 0) { printer->Print(kThinSeparator); printer->Print("\n"); @@ -1084,10 +1100,7 @@ void FileGenerator::GenerateProto2NamespaceEnumSpecializations( "#ifndef SWIG\n" "namespace google {\nnamespace protobuf {\n" "\n"); - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); - } - for (int i = 0; i < file_->enum_type_count(); i++) { + for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); } printer->Print( diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index 5dcf692b..25d6eabf 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -68,6 +68,9 @@ class FileGenerator { FileGenerator(const FileDescriptor* file, const Options& options); ~FileGenerator(); + // Shared code between the two header generators below. + void GenerateHeader(io::Printer* printer); + // info_path, if non-empty, should be the path (relative to printer's output) // to the metadata file describing this proto header. void GenerateProtoHeader(io::Printer* printer, @@ -117,18 +120,6 @@ class FileGenerator { // Generates types for classes. void GenerateMessageDefinitions(io::Printer* printer); - // Generates forward-declarations for just this file's classes. This is - // used for .pb.h headers, but not in proto_h mode. - void GenerateMessageForwardDeclarations(io::Printer* printer); - - // Fills in types for forward declarations. This is used internally, and - // also by other FileGenerators to determine imports' declarations. - void FillMessageForwardDeclarations(ForwardDeclarations* decls); - void FillMessageDefinitions(ForwardDeclarations* decls); - - // Generates enum definitions. - void GenerateEnumForwardDeclarations(io::Printer* printer); - void FillEnumForwardDeclarations(ForwardDeclarations* decls); void GenerateEnumDefinitions(io::Printer* printer); // Generates generic service definitions. @@ -145,13 +136,25 @@ class FileGenerator { const FileDescriptor* file_; const Options options_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<ServiceGenerator> > service_generators_; - google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_; + // Contains the post-order walk of all the messages (and child messages) in + // this file. If you need a pre-order walk just reverse iterate. + std::vector<MessageGenerator*> message_generators_; + std::vector<EnumGenerator*> enum_generators_; + std::vector<ServiceGenerator*> service_generators_; + std::vector<ExtensionGenerator*> extension_generators_; + + // These members are just for owning (and thus proper deleting). Some of the + // message_ and enum_generators above are owned by child messages. + google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > + message_generators_owner_; + google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_owner_; + google::protobuf::scoped_array<google::protobuf::scoped_ptr<ServiceGenerator> > + service_generators_owner_; + google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > + extension_generators_owner_; // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}. - vector<string> package_parts_; + std::vector<string> package_parts_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index 31d189c2..648ab28a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -59,7 +59,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, const string& parameter, GeneratorContext* generator_context, string* error) const { - vector<pair<string, string> > options; + std::vector<std::pair<string, string> > options; ParseGeneratorParameter(parameter, &options); // ----------------------------------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 6d844cc2..5a37b9d7 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -371,9 +371,9 @@ string DefaultValue(const FieldDescriptor* field) { return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; case FieldDescriptor::CPPTYPE_DOUBLE: { double value = field->default_value_double(); - if (value == numeric_limits<double>::infinity()) { + if (value == std::numeric_limits<double>::infinity()) { return "::google::protobuf::internal::Infinity()"; - } else if (value == -numeric_limits<double>::infinity()) { + } else if (value == -std::numeric_limits<double>::infinity()) { return "-::google::protobuf::internal::Infinity()"; } else if (value != value) { return "::google::protobuf::internal::NaN()"; @@ -384,9 +384,9 @@ string DefaultValue(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_FLOAT: { float value = field->default_value_float(); - if (value == numeric_limits<float>::infinity()) { + if (value == std::numeric_limits<float>::infinity()) { return "static_cast<float>(::google::protobuf::internal::Infinity())"; - } else if (value == -numeric_limits<float>::infinity()) { + } else if (value == -std::numeric_limits<float>::infinity()) { return "static_cast<float>(-::google::protobuf::internal::Infinity())"; } else if (value != value) { return "static_cast<float>(::google::protobuf::internal::NaN())"; @@ -450,8 +450,8 @@ string GlobalInitDefaultsName(const string& filename) { } // Return the name of the AssignDescriptors() function for a given file. -string GlobalAssignDescriptorsName(const string& filename) { - return "protobuf_AssignDesc_" + FilenameIdentifier(filename); +string GlobalOffsetTableName(const string& filename) { + return "protobuf_Offsets_" + FilenameIdentifier(filename); } // Return the name of the ShutdownFile() function for a given file. @@ -602,7 +602,7 @@ static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, static void GenerateUtf8CheckCode(const FieldDescriptor* field, const Options& options, bool for_parse, - const map<string, string>& variables, + const std::map<string, string>& variables, const char* parameters, const char* strict_function, const char* verify_function, @@ -652,7 +652,7 @@ static void GenerateUtf8CheckCode(const FieldDescriptor* field, void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, const Options& options, bool for_parse, - const map<string, string>& variables, + const std::map<string, string>& variables, const char* parameters, io::Printer* printer) { GenerateUtf8CheckCode(field, options, for_parse, variables, parameters, @@ -662,7 +662,7 @@ void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, const Options& options, bool for_parse, - const map<string, string>& variables, + const std::map<string, string>& variables, const char* parameters, io::Printer* printer) { GenerateUtf8CheckCode(field, options, for_parse, variables, parameters, diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 3a0c0388..c988bda8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -150,8 +150,8 @@ string GlobalAddDescriptorsName(const string& filename); // Return the name of the InitDefaults() function for a given file. string GlobalInitDefaultsName(const string& filename); -// Return the name of the AssignDescriptors() function for a given file. -string GlobalAssignDescriptorsName(const string& filename); +// Return the name of the offset table function for a given file. +string GlobalOffsetTableName(const string& filename); // Return the qualified C++ name for a file level symbol. string QualifiedFileLevelSymbol(const string& package, const string& name); @@ -269,13 +269,13 @@ bool IsWellKnownMessage(const FileDescriptor* descriptor); void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, const Options& options, bool for_parse, - const map<string, string>& variables, + const std::map<string, string>& variables, const char* parameters, io::Printer* printer); void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, const Options& options, bool for_parse, - const map<string, string>& variables, + const std::map<string, string>& variables, const char* parameters, io::Printer* printer); inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 31ac9ca7..c0e172b2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -45,10 +45,10 @@ bool IsProto3Field(const FieldDescriptor* field_descriptor) { } void SetMessageVariables(const FieldDescriptor* descriptor, - map<string, string>* variables, + std::map<string, string>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); - (*variables)["type"] = FieldMessageTypeName(descriptor); + (*variables)["type"] = ClassName(descriptor->message_type(), false); (*variables)["stream_writer"] = (*variables)["declared_type"] + (HasFastArraySerialization(descriptor->message_type()->file(), options) @@ -137,7 +137,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void MapFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline" : ""; printer->Print(variables, "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" @@ -154,7 +154,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MapFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; printer->Print(variables, "$this_message$$name$_.Clear();\n"); } @@ -173,14 +173,20 @@ void MapFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(variables_, - "$name$_.SetAssignDescriptorCallback(\n" - " protobuf_AssignDescriptorsOnce);\n" - "$name$_.SetEntryDescriptor(\n" - " &$type$_descriptor_);\n"); + "$name$_.SetAssignDescriptorCallback(\n" + " protobuf_AssignDescriptorsOnce);\n" + "$name$_.SetEntryDescriptor(\n" + " &$type$_descriptor);\n"); } } void MapFieldGenerator:: +GenerateCopyConstructorCode(io::Printer* printer) const { + GenerateConstructorCode(printer); + GenerateMergingCode(printer); +} + +void MapFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { const FieldDescriptor* key_field = descriptor_->message_type()->FindFieldByName("key"); @@ -252,7 +258,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { } static void GenerateSerializationLoop(io::Printer* printer, - const map<string, string>& variables, + const std::map<string, string>& variables, bool supports_arenas, const string& utf8_check, const string& loop_header, @@ -291,17 +297,17 @@ static void GenerateSerializationLoop(io::Printer* printer, void MapFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["write_entry"] = "::google::protobuf::internal::WireFormatLite::Write" + variables["stream_writer"] + "(\n " + variables["number"] + ", *entry, output)"; - variables["deterministic"] = "output->IsSerializationDeterminstic()"; + variables["deterministic"] = "output->IsSerializationDeterministic()"; GenerateSerializeWithCachedSizes(printer, variables); } void MapFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["write_entry"] = "target = ::google::protobuf::internal::WireFormatLite::\n" " InternalWrite" + variables["declared_type"] + @@ -312,7 +318,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { } void MapFieldGenerator::GenerateSerializeWithCachedSizes( - io::Printer* printer, const map<string, string>& variables) const { + io::Printer* printer, const std::map<string, string>& variables) const { printer->Print(variables, "if (!this->$name$().empty()) {\n"); printer->Indent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index 2930fe59..816687b3 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -55,6 +55,7 @@ class MapFieldGenerator : public FieldGenerator { void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; @@ -63,11 +64,11 @@ class MapFieldGenerator : public FieldGenerator { private: // A helper for GenerateSerializeWithCachedSizes{,ToArray}. void GenerateSerializeWithCachedSizes( - io::Printer* printer, const map<string, string>& variables) const; + io::Printer* printer, const std::map<string, string>& variables) const; const FieldDescriptor* descriptor_; const bool dependent_field_; - map<string, string> variables_; + std::map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index efc56ddc..d878c4de 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -207,7 +207,7 @@ class FieldGroup { } void SetPreferredLocation(float location) { preferred_location_ = location; } - const vector<const FieldDescriptor*>& fields() const { return fields_; } + const std::vector<const FieldDescriptor*>& fields() const { return fields_; } // FieldGroup objects sort by their preferred location. bool operator<(const FieldGroup& other) const { @@ -221,7 +221,7 @@ class FieldGroup { // approximate, but should put this group close to where its member fields // originally went. float preferred_location_; - vector<const FieldDescriptor*> fields_; + std::vector<const FieldDescriptor*> fields_; // We rely on the default copy constructor and operator= so this type can be // used in a vector. }; @@ -251,6 +251,39 @@ bool CanInitializeByZeroing(const FieldDescriptor* field) { } } +bool IsPOD(const FieldDescriptor* field) { + if (field->is_repeated() || field->is_extension()) return false; + switch (field->cpp_type()) { + case internal::WireFormatLite::CPPTYPE_ENUM: + case internal::WireFormatLite::CPPTYPE_INT32: + case internal::WireFormatLite::CPPTYPE_INT64: + case internal::WireFormatLite::CPPTYPE_UINT32: + case internal::WireFormatLite::CPPTYPE_UINT64: + case internal::WireFormatLite::CPPTYPE_FLOAT: + case internal::WireFormatLite::CPPTYPE_DOUBLE: + case internal::WireFormatLite::CPPTYPE_BOOL: + return true; + case internal::WireFormatLite::CPPTYPE_STRING: + return false; + default: + return false; + } +} + +// Helper for the code that emits the SharedCtor() method. +bool CanConstructByZeroing(const FieldDescriptor* field, + const Options& options) { + bool ret = CanInitializeByZeroing(field); + + // Non-repeated, non-lazy message fields are simply raw pointers, so we can + // use memset to initialize these in SharedCtor. We cannot use this in + // Clear, as we need to potentially delete the existing value. + ret = ret || + (!field->is_repeated() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); + return ret; +} + // Reorder 'fields' so that if the fields are output into a c++ class in the new // order, fields of similiar family (see below) are together and within each // family, alignment padding is minimized. @@ -260,9 +293,6 @@ bool CanInitializeByZeroing(const FieldDescriptor* field) { // locality much for function that access each field in order. This is also the // only (weak) signal we have for author intent concerning field layout. // -// TODO(ckennelly): Update these functions to use the optimized layout order -// for their access patterns. -// // TODO(ckennelly): If/when we have profiles available for the compiler, use // those rather than respect declaration order. // @@ -275,30 +305,32 @@ bool CanInitializeByZeroing(const FieldDescriptor* field) { // STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and // calls ArenaStringPtr::Destroy on each. // +// // MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls // delete on each. We initialize these fields with a NULL pointer (see -// MessageFieldGenerator::GenerateConstructorCode). -// TODO(ckennelly): memset these in SharedCtor. +// MessageFieldGenerator::GenerateConstructorCode), which allows them to be +// memset. // // ZERO_INITIALIZABLE is memset in Clear/SharedCtor // // OTHER these fields are initialized one-by-one. -void OptimizePadding(vector<const FieldDescriptor*>* fields) { +void OptimizePadding(std::vector<const FieldDescriptor*>* fields, + const Options& options) { // The sorted numeric order of Family determines the declaration order in the // memory layout. enum Family { REPEATED = 0, STRING = 1, MESSAGE = 2, - ZERO_INITIALIZABLE = 3, - OTHER = 4, + ZERO_INITIALIZABLE = 4, + OTHER = 5, kMaxFamily }; // First divide fields into those that align to 1 byte, 4 bytes or 8 bytes. - vector<FieldGroup> aligned_to_1[kMaxFamily]; - vector<FieldGroup> aligned_to_4[kMaxFamily]; - vector<FieldGroup> aligned_to_8[kMaxFamily]; + std::vector<FieldGroup> aligned_to_1[kMaxFamily]; + std::vector<FieldGroup> aligned_to_4[kMaxFamily]; + std::vector<FieldGroup> aligned_to_8[kMaxFamily]; for (int i = 0; i < fields->size(); ++i) { const FieldDescriptor* field = (*fields)[i]; @@ -309,6 +341,7 @@ void OptimizePadding(vector<const FieldDescriptor*>* fields) { f = STRING; } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { f = MESSAGE; + } else if (CanInitializeByZeroing(field)) { f = ZERO_INITIALIZABLE; } @@ -427,23 +460,9 @@ bool HasHasMethod(const FieldDescriptor* field) { return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE; } -size_t HasBitsSize(const Descriptor* descriptor) { - // TODO(jieluo) - Optimize _has_bits_ for repeated and oneof fields. - size_t sizeof_has_bits = (descriptor->field_count() + 31) / 32 * 4; - if (descriptor->field_count() == 0) { - // Zero-size arrays aren't technically allowed, and MSVC in particular - // doesn't like them. We still need to declare these arrays to make - // other code compile. Since this is an uncommon case, we'll just declare - // them with size 1 and waste some space. Oh well. - sizeof_has_bits = 4; - } - - return sizeof_has_bits; -} - // Collects map entry message type information. void CollectMapInfo(const Descriptor* descriptor, - map<string, string>* variables) { + std::map<string, string>* variables) { GOOGLE_CHECK(IsMapEntryMessage(descriptor)); const FieldDescriptor* key = descriptor->FindFieldByName("key"); const FieldDescriptor* val = descriptor->FindFieldByName("value"); @@ -475,6 +494,7 @@ bool HasPrivateHasMethod(const FieldDescriptor* field) { field->containing_oneof() != NULL); } + } // anonymous namespace // =================================================================== @@ -500,7 +520,33 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, optimized_order_.push_back(descriptor_->field(i)); } } - OptimizePadding(&optimized_order_); + OptimizePadding(&optimized_order_, options_); + + if (HasFieldPresence(descriptor_->file())) { + int has_bit_index = 0; + has_bit_indices_.resize(descriptor_->field_count(), -1); + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + // Skip fields that do not have has bits. + if (field->is_repeated()) { + continue; + } + + has_bit_indices_[field->index()] = has_bit_index; + has_bit_index++; + } + + // Assign fields that do not use has bits to be at the end. This can be + // removed once we shrink the has bits we assign. + // + // TODO(ckennelly): Shrink the has bits for these fields. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (has_bit_indices_[field->index()] < 0) { + has_bit_indices_[field->index()] = has_bit_index++; + } + } + } for (int i = 0; i < descriptor->nested_type_count(); i++) { nested_generators_[i].reset( @@ -534,48 +580,42 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, MessageGenerator::~MessageGenerator() {} -void MessageGenerator:: -FillMessageForwardDeclarations(map<string, const Descriptor*>* class_names) { - (*class_names)[classname_] = descriptor_; - - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // map entry message doesn't need forward declaration. Since map entry - // message cannot be a top level class, we just need to avoid calling - // GenerateForwardDeclaration here. - if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->FillMessageForwardDeclarations(class_names); +size_t MessageGenerator::HasBitsSize() const { + // TODO(jieluo) - Optimize _has_bits_ for repeated and oneof fields. + size_t sizeof_has_bits = (descriptor_->field_count() + 31) / 32 * 4; + if (descriptor_->field_count() == 0) { + // Zero-size arrays aren't technically allowed, and MSVC in particular + // doesn't like them. We still need to declare these arrays to make + // other code compile. Since this is an uncommon case, we'll just declare + // them with size 1 and waste some space. Oh well. + sizeof_has_bits = 4; } -} -void MessageGenerator:: -FillEnumForwardDeclarations(map<string, const EnumDescriptor*>* enum_names) { - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->FillEnumForwardDeclarations(enum_names); - } - for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->FillForwardDeclaration(enum_names); - } + return sizeof_has_bits; } -void MessageGenerator:: -GenerateEnumDefinitions(io::Printer* printer) { +void MessageGenerator::Flatten(std::vector<MessageGenerator*>* list) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateEnumDefinitions(printer); + nested_generators_[i]->Flatten(list); } + list->push_back(this); +} +void MessageGenerator::AddGenerators( + std::vector<EnumGenerator*>* enum_generators, + std::vector<ExtensionGenerator*>* extension_generators) { for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateDefinition(printer); + enum_generators->push_back(enum_generators_[i].get()); + } + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators->push_back(extension_generators_[i].get()); } } -void MessageGenerator:: -GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); - } - for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); - } +void MessageGenerator::FillMessageForwardDeclarations( + std::map<string, const Descriptor*>* class_names) { + if (IsMapEntryMessage(descriptor_)) return; + (*class_names)[classname_] = descriptor_; } void MessageGenerator:: @@ -585,7 +625,7 @@ GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { PrintFieldComment(printer, field); - map<string, string> vars; + std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); if (use_dependent_base_ && IsFieldDependent(field)) { @@ -607,7 +647,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { PrintFieldComment(printer, field); - map<string, string> vars; + std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); vars["constant_name"] = FieldConstantName(field); @@ -679,6 +719,8 @@ GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); + if (field->options().weak()) continue; + PrintFieldComment(printer, field); // These functions are not really dependent: they are part of the @@ -688,7 +730,7 @@ GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { // See the comment in FileGenerator::GenerateInlineFunctionDefinitions // for a more complete explanation. if (use_dependent_base_ && IsFieldDependent(field)) { - map<string, string> vars; + std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); vars["inline"] = "inline "; if (field->containing_oneof()) { @@ -725,13 +767,16 @@ GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { void MessageGenerator:: GenerateSingularFieldHasBits(const FieldDescriptor* field, - map<string, string> vars, + std::map<string, string> vars, io::Printer* printer) { if (HasFieldPresence(descriptor_->file())) { // N.B.: without field presence, we do not use has-bits or generate // has_$name$() methods. - vars["has_array_index"] = SimpleItoa(field->index() / 32); - vars["has_mask"] = StrCat(strings::Hex(1u << (field->index() % 32), + int has_bit_index = has_bit_indices_[field->index()]; + GOOGLE_CHECK_GE(has_bit_index, 0); + + vars["has_array_index"] = SimpleItoa(has_bit_index / 32); + vars["has_mask"] = StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); printer->Print(vars, "$inline$" @@ -771,7 +816,7 @@ GenerateSingularFieldHasBits(const FieldDescriptor* field, void MessageGenerator:: GenerateOneofHasBits(io::Printer* printer, bool is_inline) { for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - map<string, string> vars; + std::map<string, string> vars; vars["oneof_name"] = descriptor_->oneof_decl(i)->name(); vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); vars["cap_oneof_name"] = @@ -793,7 +838,7 @@ GenerateOneofHasBits(io::Printer* printer, bool is_inline) { void MessageGenerator:: GenerateOneofMemberHasBits(const FieldDescriptor* field, - const map<string, string>& vars, + const std::map<string, string>& vars, io::Printer* printer) { // Singular field in a oneof // N.B.: Without field presence, we do not use has-bits or generate @@ -815,7 +860,7 @@ GenerateOneofMemberHasBits(const FieldDescriptor* field, void MessageGenerator:: GenerateFieldClear(const FieldDescriptor* field, - const map<string, string>& vars, + const std::map<string, string>& vars, io::Printer* printer) { // Generate clear_$name$() (See GenerateFieldAccessorDeclarations and // GenerateDependentFieldAccessorDeclarations, $dependent_classname$ is @@ -863,7 +908,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { PrintFieldComment(printer, field); - map<string, string> vars; + std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); vars["inline"] = is_inline ? "inline " : ""; if (use_dependent_base_ && IsFieldDependent(field)) { @@ -925,7 +970,7 @@ GenerateDependentBaseClassDefinition(io::Printer* printer) { return; } - map<string, string> vars; + std::map<string, string> vars; vars["classname"] = DependentBaseClassTemplateName(descriptor_); vars["full_name"] = descriptor_->full_name(); vars["superclass"] = SuperClassName(descriptor_, options_); @@ -951,23 +996,13 @@ GenerateDependentBaseClassDefinition(io::Printer* printer) { void MessageGenerator:: GenerateClassDefinition(io::Printer* printer) { - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // map entry message doesn't need class definition. Since map entry message - // cannot be a top level class, we just need to avoid calling - // GenerateClassDefinition here. - if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateClassDefinition(printer); - printer->Print("\n"); - printer->Print(kThinSeparator); - printer->Print("\n"); - } - + if (IsMapEntryMessage(descriptor_)) return; if (use_dependent_base_) { GenerateDependentBaseClassDefinition(printer); printer->Print("\n"); } - map<string, string> vars; + std::map<string, string> vars; vars["classname"] = classname_; vars["full_name"] = descriptor_->full_name(); vars["field_count"] = SimpleItoa(descriptor_->field_count()); @@ -1007,44 +1042,19 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n" - " return _internal_metadata_.unknown_fields();\n" - "}\n" - "\n" - "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n" - " return _internal_metadata_.mutable_unknown_fields();\n" - "}\n" - "\n"); - } else { - if (SupportsArenas(descriptor_)) { - printer->Print( - "inline const ::std::string& unknown_fields() const {\n" - " return _unknown_fields_.Get(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" - "}\n" - "\n" - "inline ::std::string* mutable_unknown_fields() {\n" - " return _unknown_fields_.Mutable(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" - " GetArenaNoVirtual());\n" - "}\n" - "\n"); - } else { - printer->Print( - "inline const ::std::string& unknown_fields() const {\n" - " return _unknown_fields_.GetNoArena(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" - "}\n" - "\n" - "inline ::std::string* mutable_unknown_fields() {\n" - " return _unknown_fields_.MutableNoArena(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" - "}\n" - "\n"); - } - } + 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 ); } // N.B.: We exclude GetArena() when arena support is disabled, falling back on @@ -1054,8 +1064,10 @@ GenerateClassDefinition(io::Printer* printer) { // virtual method version of GetArenaNoVirtual(), required for generic dispatch given a // MessageLite* (e.g., in RepeatedField::AddAllocated()). printer->Print( - "inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }\n" - "inline void* GetMaybeArenaPointer() const {\n" + "inline ::google::protobuf::Arena* GetArena() const PROTOBUF_FINAL {\n" + " return GetArenaNoVirtual();\n" + "}\n" + "inline void* GetMaybeArenaPointer() const PROTOBUF_FINAL {\n" " return MaybeArenaPtr();\n" "}\n"); } @@ -1101,7 +1113,10 @@ GenerateClassDefinition(io::Printer* printer) { // TODO(gerbens) make this private, while still granting other protos access. printer->Print( vars, - "static const $classname$* internal_default_instance();\n" + "static inline const $classname$* internal_default_instance() {\n" + " return reinterpret_cast<const $classname$*>(\n" + " &_$classname$_default_instance_);\n" + "}\n" "\n"); @@ -1124,97 +1139,76 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } + vars["new_final"] = " PROTOBUF_FINAL"; + printer->Print(vars, "void Swap($classname$* other);\n" "\n" "// implements Message ----------------------------------------------\n" "\n" - "inline $classname$* New() const { return New(NULL); }\n" + "inline $classname$* New() const$new_final$ { return New(NULL); }\n" "\n" - "$classname$* New(::google::protobuf::Arena* arena) const;\n"); + "$classname$* New(::google::protobuf::Arena* arena) const$new_final$;\n"); + + // For instances that derive from Message (rather than MessageLite), some + // methods are virtual and should be marked as final. + string use_final = HasDescriptorMethods(descriptor_->file(), options_) ? + " PROTOBUF_FINAL" : ""; if (HasGeneratedMethods(descriptor_->file(), options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, - "void CopyFrom(const ::google::protobuf::Message& from);\n" - "void MergeFrom(const ::google::protobuf::Message& from);\n"); + "void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;\n" + "void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;\n"); } else { printer->Print(vars, - "void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);\n"); + "void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)\n" + " PROTOBUF_FINAL;\n"); } - printer->Print(vars, - "void CopyFrom(const $classname$& from);\n" - "void MergeFrom(const $classname$& from);\n" - "void Clear();\n" - "bool IsInitialized() const;\n" - "\n" - "size_t ByteSizeLong() const;\n" - "bool MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input);\n" - "void SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const;\n"); + vars["clear_final"] = " PROTOBUF_FINAL"; + vars["is_initialized_final"] = " PROTOBUF_FINAL"; + vars["merge_partial_final"] = " PROTOBUF_FINAL"; + + printer->Print( + vars, + "void CopyFrom(const $classname$& from);\n" + "void MergeFrom(const $classname$& from);\n" + "void Clear()$clear_final$;\n" + "bool IsInitialized() const$is_initialized_final$;\n" + "\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"); // DiscardUnknownFields() is implemented in message.cc using reflections. We // need to implement this function in generated code for messages. if (!UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( - "void DiscardUnknownFields();\n"); + "void DiscardUnknownFields()$final$;\n", + "final", use_final); } if (HasFastArraySerialization(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n" - " bool deterministic, ::google::protobuf::uint8* output) const;\n" - "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {\n" + " bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;\n" + "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output)\n" + " const PROTOBUF_FINAL {\n" " return InternalSerializeWithCachedSizesToArray(false, output);\n" "}\n"); } } - // Check all FieldDescriptors including those in oneofs to estimate - // whether ::std::string is likely to be used, and depending on that - // estimate, set uses_string_ to true or false. That contols - // whether to force initialization of empty_string_ in SharedCtor(). - // It's often advantageous to do so to keep "is empty_string_ - // inited?" code from appearing all over the place. - vector<const FieldDescriptor*> descriptors; - for (int i = 0; i < descriptor_->field_count(); i++) { - descriptors.push_back(descriptor_->field(i)); - } - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - descriptors.push_back(descriptor_->oneof_decl(i)->field(j)); - } - } - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - const Descriptor* nested_type = descriptor_->nested_type(i); - if (IsMapEntryMessage(nested_type)) { - descriptors.push_back(nested_type->FindFieldByName("key")); - descriptors.push_back(nested_type->FindFieldByName("value")); - } - } - uses_string_ = false; - if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file(), options_)) { - uses_string_ = true; - } - for (int i = 0; i < descriptors.size(); i++) { - const FieldDescriptor* field = descriptors[i]; - if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { - switch (field->options().ctype()) { - default: uses_string_ = true; break; - } - } - } - printer->Print( - "int GetCachedSize() const { return _cached_size_; }\n" + "int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }\n" "private:\n" "void SharedCtor();\n" "void SharedDtor();\n" - "void SetCachedSize(int size) const;\n" - "void InternalSwap($classname$* other);\n" - "void UnsafeMergeFrom(const $classname$& from);\n", - "classname", classname_); + "void SetCachedSize(int size) const$final$;\n" + "void InternalSwap($classname$* other);\n", + "classname", classname_, + "final", use_final); if (SupportsArenas(descriptor_)) { printer->Print( "protected:\n" @@ -1225,7 +1219,7 @@ GenerateClassDefinition(io::Printer* printer) { "classname", classname_); } - if (UseUnknownFieldSet(descriptor_->file(), options_)) { + if (SupportsArenas(descriptor_)) { printer->Print( "private:\n" "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n" @@ -1233,29 +1227,29 @@ GenerateClassDefinition(io::Printer* printer) { "}\n" "inline void* MaybeArenaPtr() const {\n" " return _internal_metadata_.raw_arena_ptr();\n" - "}\n" - "public:\n" - "\n"); + "}\n"); } else { printer->Print( "private:\n" "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n" - " return _arena_ptr_;\n" - "}\n" - "inline ::google::protobuf::Arena* MaybeArenaPtr() const {\n" - " return _arena_ptr_;\n" + " return NULL;\n" "}\n" + "inline void* MaybeArenaPtr() const {\n" + " return NULL;\n" + "}\n"); + } + + printer->Print( "public:\n" "\n"); - } if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( - "::google::protobuf::Metadata GetMetadata() const;\n" + "::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;\n" "\n"); } else { printer->Print( - "::std::string GetTypeName() const;\n" + "::std::string GetTypeName() const PROTOBUF_FINAL;\n" "\n"); } @@ -1313,17 +1307,15 @@ GenerateClassDefinition(io::Printer* printer) { // messages without true field presence. if (HasFieldPresence(descriptor_->file()) || descriptor_->field(i)->containing_oneof()) { - printer->Print( - "inline void set_has_$name$();\n", - "name", FieldName(descriptor_->field(i))); + printer->Print("void set_has_$name$();\n", "name", + FieldName(descriptor_->field(i))); } // clear_has_***() generated only for non-oneof fields // in proto1/2. if (!descriptor_->field(i)->containing_oneof() && HasFieldPresence(descriptor_->file())) { - printer->Print( - "inline void clear_has_$name$();\n", - "name", FieldName(descriptor_->field(i))); + printer->Print("void clear_has_$name$();\n", "name", + FieldName(descriptor_->field(i))); } } } @@ -1353,7 +1345,7 @@ GenerateClassDefinition(io::Printer* printer) { // TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it. const string cached_size_decl = "mutable int _cached_size_;\n"; - const size_t sizeof_has_bits = HasBitsSize(descriptor_); + const size_t sizeof_has_bits = HasBitsSize(); const string has_bits_decl = sizeof_has_bits == 0 ? "" : "::google::protobuf::internal::HasBits<" + SimpleItoa(sizeof_has_bits / 4) + "> _has_bits_;\n"; @@ -1377,9 +1369,8 @@ GenerateClassDefinition(io::Printer* printer) { "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n"); } else { printer->Print( - "::google::protobuf::internal::ArenaStringPtr _unknown_fields_;\n" - "::google::protobuf::Arena* _arena_ptr_;\n" - "\n"); + "::google::protobuf::internal::InternalMetadataWithArenaLite " + "_internal_metadata_;\n"); } if (SupportsArenas(descriptor_)) { @@ -1404,33 +1395,12 @@ GenerateClassDefinition(io::Printer* printer) { // Field members: - // List fields which doesn't belong to any oneof - hash_map<string, int> fieldname_to_chunk; - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - const FieldDescriptor* field = descriptor_->field(i); - fieldname_to_chunk[FieldName(field)] = i / 8; - } - } - // Emit some private and static members - runs_of_fields_ = vector< vector<string> >(1); for (int i = 0; i < optimized_order_.size(); ++i) { const FieldDescriptor* field = optimized_order_[i]; const FieldGenerator& generator = field_generators_.get(field); generator.GenerateStaticMembers(printer); generator.GeneratePrivateMembers(printer); - if (CanInitializeByZeroing(field)) { - const string& fieldname = FieldName(field); - if (!runs_of_fields_.back().empty() && - (fieldname_to_chunk[runs_of_fields_.back().back()] != - fieldname_to_chunk[fieldname])) { - runs_of_fields_.push_back(vector<string>()); - } - runs_of_fields_.back().push_back(fieldname); - } else if (!runs_of_fields_.back().empty()) { - runs_of_fields_.push_back(vector<string>()); - } } // For each oneof generate a union @@ -1491,65 +1461,37 @@ GenerateClassDefinition(io::Printer* printer) { GlobalAddDescriptorsName(descriptor_->file()->name())); printer->Print( - "friend void $assigndescriptorsname$();\n" - "friend void $shutdownfilename$();\n" - "\n", - "assigndescriptorsname", - GlobalAssignDescriptorsName(descriptor_->file()->name()), - "shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name())); - - printer->Print( - "void InitAsDefaultInstance();\n", - "classname", classname_); + "friend const ::google::protobuf::uint32* $offsetfunname$();\n" + "friend void $shutdownfilename$();\n" + "\n", + "offsetfunname", GlobalOffsetTableName(descriptor_->file()->name()), + "shutdownfilename", GlobalShutdownFileName(descriptor_->file()->name())); printer->Outdent(); - printer->Print("};\n"); - - // This should ideally be put into the class scope, but Visual Studio just - // refuses to compile it and complains about "use of undefined XXX": - // https://ci.appveyor.com/project/protobuf/protobuf/build/1.0.2673/job/nrdf4tb9dau0sck5 - // A program as simple as "struct X { enum { value = sizeof(X) }; };" will - // trigger the same error. - printer->Print( - "extern ::google::protobuf::internal::ExplicitlyConstructed<$classname$> " - "$classname$_default_instance_;\n", - "classname", classname_); - + printer->Print("};"); GOOGLE_DCHECK(!need_to_emit_cached_size); } void MessageGenerator:: GenerateDependentInlineMethods(io::Printer* printer) { - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // map entry message doesn't need inline methods. Since map entry message - // cannot be a top level class, we just need to avoid calling - // GenerateInlineMethods here. - if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateDependentInlineMethods(printer); - printer->Print(kThinSeparator); - printer->Print("\n"); + if (IsMapEntryMessage(descriptor_)) return; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (descriptor_->field(i)->options().weak()) { + field_generators_.get(descriptor_->field(i)) + .GenerateDependentInlineAccessorDefinitions(printer); + } } - GenerateDependentFieldAccessorDefinitions(printer); } void MessageGenerator:: GenerateInlineMethods(io::Printer* printer, bool is_inline) { - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // map entry message doesn't need inline methods. Since map entry message - // cannot be a top level class, we just need to avoid calling - // GenerateInlineMethods here. - if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateInlineMethods(printer, is_inline); - printer->Print(kThinSeparator); - printer->Print("\n"); - } - + if (IsMapEntryMessage(descriptor_)) return; GenerateFieldAccessorDefinitions(printer, is_inline); // Generate oneof_case() functions. for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - map<string, string> vars; + std::map<string, string> vars; vars["class_name"] = classname_; vars["camel_oneof_name"] = UnderscoresToCamelCase( descriptor_->oneof_decl(i)->name(), true); @@ -1565,28 +1507,10 @@ GenerateInlineMethods(io::Printer* printer, bool is_inline) { "_oneof_case_[$oneof_index$]);\n" "}\n"); } - - printer->Print( - "inline const $classname$* $classname$::internal_default_instance() {\n" - " return &$classname$_default_instance_.get();\n" - "}\n", - "classname", classname_); } void MessageGenerator:: GenerateDescriptorDeclarations(io::Printer* printer) { - if (!IsMapEntryMessage(descriptor_)) { - printer->Print( - "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n" - "const ::google::protobuf::internal::GeneratedMessageReflection*\n" - " $name$_reflection_ = NULL;\n", - "name", classname_); - } else { - printer->Print( - "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n", - "name", classname_); - } - // Generate oneof default instance for reflection usage. if (descriptor_->oneof_decl_count() > 0) { printer->Print("struct $name$OneofInstance {\n", @@ -1604,140 +1528,31 @@ GenerateDescriptorDeclarations(io::Printer* printer) { } } - printer->Print("}* $name$_default_oneof_instance_ = NULL;\n", - "name", classname_); - } - - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateDescriptorDeclarations(printer); - } - - for (int i = 0; i < descriptor_->enum_type_count(); i++) { - printer->Print( - "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n", - "name", ClassName(descriptor_->enum_type(i), false)); + printer->Print("} $name$_default_oneof_instance_;\n", "name", classname_); } } -void MessageGenerator:: -GenerateDescriptorInitializer(io::Printer* printer, int index) { - // TODO(kenton): Passing the index to this method is redundant; just use - // descriptor_->index() instead. - map<string, string> vars; - vars["classname"] = classname_; - vars["index"] = SimpleItoa(index); - - // Obtain the descriptor from the parent's descriptor. - if (descriptor_->containing_type() == NULL) { - printer->Print(vars, - "$classname$_descriptor_ = file->message_type($index$);\n"); - } else { - vars["parent"] = ClassName(descriptor_->containing_type(), false); - printer->Print(vars, - "$classname$_descriptor_ = " - "$parent$_descriptor_->nested_type($index$);\n"); - } - +void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, + int has_offset) { if (IsMapEntryMessage(descriptor_)) return; - // Generate the offsets. - GenerateOffsets(printer); + std::map<string, string> vars; - const bool pass_pool_and_factory = false; - vars["fn"] = pass_pool_and_factory ? - "new ::google::protobuf::internal::GeneratedMessageReflection" : - "::google::protobuf::internal::GeneratedMessageReflection" - "::NewGeneratedMessageReflection"; - // Construct the reflection object. - printer->Print(vars, - "$classname$_reflection_ =\n" - " $fn$(\n" - " $classname$_descriptor_,\n" - " $classname$::internal_default_instance(),\n" - " $classname$_offsets_,\n"); - if (!HasFieldPresence(descriptor_->file())) { - // If we don't have field presence, then _has_bits_ does not exist. - printer->Print(vars, - " -1,\n"); - } else { - printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_),\n"); - } - - // Unknown field offset: either points to the unknown field set if embedded - // directly, or indicates that the unknown field set is stored as part of the - // internal metadata if not. - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(vars, - " -1,\n"); - } else { - printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _unknown_fields_),\n"); - } - - if (descriptor_->extension_range_count() > 0) { - printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _extensions_),\n"); - } else { - // No extensions. - printer->Print(vars, - " -1,\n"); - } - - if (descriptor_->oneof_decl_count() > 0) { - printer->Print(vars, - " $classname$_default_oneof_instance_,\n" - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _oneof_case_[0]),\n"); - } - - if (pass_pool_and_factory) { - printer->Print( - " ::google::protobuf::DescriptorPool::generated_pool(),\n"); - printer->Print(vars, - " ::google::protobuf::MessageFactory::generated_factory(),\n"); - } + vars["classname"] = classname_; + vars["offset"] = SimpleItoa(offset); + vars["has_bits_offsets"] = HasFieldPresence(descriptor_->file()) + ? SimpleItoa(offset + has_offset) + : "-1"; printer->Print(vars, - " sizeof($classname$),\n"); - - // Arena offset: either an offset to the metadata struct that contains the - // arena pointer and unknown field set (in a space-efficient way) if we use - // that implementation strategy, or an offset directly to the arena pointer if - // not (because e.g. we don't have an unknown field set). - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _internal_metadata_));\n"); - } else { - printer->Print(vars, - " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _arena_));\n"); - } - - // Handle nested types. - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateDescriptorInitializer(printer, i); - } - - for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateDescriptorInitializer(printer, i); - } + "{ $offset$, $has_bits_offsets$, sizeof($classname$)},\n"); } void MessageGenerator:: GenerateTypeRegistrations(io::Printer* printer) { // Register this message type with the message factory. - if (!IsMapEntryMessage(descriptor_)) { - printer->Print( - "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n" - " $classname$_descriptor_, " - "$classname$::internal_default_instance());\n", - "classname", classname_); - } else { - map<string, string> vars; + if (IsMapEntryMessage(descriptor_)) { + std::map<string, string> vars; CollectMapInfo(descriptor_, &vars); vars["classname"] = classname_; @@ -1750,31 +1565,27 @@ GenerateTypeRegistrations(io::Printer* printer) { vars["default_enum_value"] = "0"; } - printer->Print(vars, - "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n" - " $classname$_descriptor_,\n" - " ::google::protobuf::internal::MapEntry<\n" - " $key$,\n" - " $val$,\n" - " $key_wire_type$,\n" - " $val_wire_type$,\n" - " $default_enum_value$>::CreateDefaultInstance(\n" - " $classname$_descriptor_));\n"); - } - - // Handle nested types. - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateTypeRegistrations(printer); + vars["index_in_metadata"] = SimpleItoa(index_in_metadata_); + + printer->Print( + vars, + "const ::google::protobuf::Descriptor* $classname$_descriptor = " + "file_level_metadata[$index_in_metadata$].descriptor;\n" + "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n" + " $classname$_descriptor,\n" + " ::google::protobuf::internal::MapEntry<\n" + " $key$,\n" + " $val$,\n" + " $key_wire_type$,\n" + " $val_wire_type$,\n" + " $default_enum_value$>::CreateDefaultInstance(\n" + " $classname$_descriptor));\n"); } } void MessageGenerator:: GenerateDefaultInstanceAllocator(io::Printer* printer) { - // Force initialization of primitive values we depend on. - printer->Print( - StrCat( - uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "") - .c_str()); + if (IsMapEntryMessage(descriptor_)) return; // Construct the default instances of all fields, as they will be used // when creating the default instance of the entire message. @@ -1783,64 +1594,60 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { .GenerateDefaultInstanceAllocator(printer); } - if (IsMapEntryMessage(descriptor_)) return; - // Construct the default instance. We can't call InitAsDefaultInstance() yet // because we need to make sure all default instances that this one might // depend on are constructed first. - printer->Print("$classname$_default_instance_.DefaultConstruct();\n", + printer->Print("_$classname$_default_instance_.DefaultConstruct();\n", "classname", classname_); - - if ((descriptor_->oneof_decl_count() > 0) && - HasDescriptorMethods(descriptor_->file(), options_)) { - printer->Print( - "$classname$_default_oneof_instance_ = new $classname$OneofInstance();\n", - "classname", classname_); - } - - // Handle nested types. - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateDefaultInstanceAllocator(printer); - } - } void MessageGenerator:: GenerateDefaultInstanceInitializer(io::Printer* printer) { - printer->Print( - "$classname$_default_instance_.get_mutable()->InitAsDefaultInstance();" - "\n", - "classname", classname_); + if (IsMapEntryMessage(descriptor_)) return; - // Register extensions. - for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators_[i]->GenerateRegistration(printer); - } + // The default instance needs all of its embedded message pointers + // cross-linked to other default instances. We can't do this initialization + // in the constructor because some other default instances may not have been + // constructed yet at that time. + // TODO(kenton): Maybe all message fields (even for non-default messages) + // should be initialized to point at default instances rather than NULL? + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); - // Handle nested types. - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // map entry message doesn't need to initialize default instance manually. - // Since map entry message cannot be a top level class, we just need to - // avoid calling DefaultInstanceInitializer here. - if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateDefaultInstanceInitializer(printer); + if (!field->is_repeated() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + (field->containing_oneof() == NULL || + HasDescriptorMethods(descriptor_->file(), options_))) { + string name; + if (field->containing_oneof()) { + name = classname_ + "_default_oneof_instance_."; + } else { + name = "_" + classname_ + "_default_instance_.get_mutable()->"; + } + name += FieldName(field); + printer->Print( + "$name$_ = const_cast< $type$*>(\n" + " $type$::internal_default_instance());\n", + // Vars. + "name", name, "type", FieldMessageTypeName(field)); + } else if (field->containing_oneof() && + HasDescriptorMethods(descriptor_->file(), options_)) { + field_generators_.get(descriptor_->field(i)) + .GenerateConstructorCode(printer); + } } } void MessageGenerator:: GenerateShutdownCode(io::Printer* printer) { - printer->Print( - "$classname$_default_instance_.Shutdown();\n", - "classname", classname_); + if (IsMapEntryMessage(descriptor_)) return; + + printer->Print("_$classname$_default_instance_.Shutdown();\n", "classname", + classname_); + if (HasDescriptorMethods(descriptor_->file(), options_)) { - if (descriptor_->oneof_decl_count() > 0) { - printer->Print( - "delete $classname$_default_oneof_instance_;\n", - "classname", classname_); - } - printer->Print( - "delete $classname$_reflection_;\n", - "classname", classname_); + printer->Print("delete file_level_metadata[$index$].reflection;\n", "index", + SimpleItoa(index_in_metadata_)); } // Handle default instances of fields. @@ -1848,16 +1655,12 @@ GenerateShutdownCode(io::Printer* printer) { field_generators_.get(descriptor_->field(i)) .GenerateShutdownCode(printer); } - - // Handle nested types. - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateShutdownCode(printer); - } } void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { + if (IsMapEntryMessage(descriptor_)) return; + // mutable_unknown_fields wrapper function for LazyStringOutputStream // callback. if (PreserveUnknownFields(descriptor_) && @@ -1888,21 +1691,6 @@ GenerateClassMethods(io::Printer* printer) { "classname", classname_); } - for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateMethods(printer); - } - - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // map entry message doesn't need class methods. Since map entry message - // cannot be a top level class, we just need to avoid calling - // GenerateClassMethods here. - if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateClassMethods(printer); - printer->Print("\n"); - printer->Print(kThinSeparator); - printer->Print("\n"); - } - // Generate non-inline field definitions. for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(descriptor_->field(i)) @@ -1922,11 +1710,6 @@ GenerateClassMethods(io::Printer* printer) { "#endif // !defined(_MSC_VER) || _MSC_VER >= 1900\n" "\n"); - // Define extension identifiers. - for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators_[i]->GenerateDefinition(printer); - } - GenerateStructors(printer); printer->Print("\n"); @@ -1961,12 +1744,6 @@ GenerateClassMethods(io::Printer* printer) { GenerateIsInitialized(printer); printer->Print("\n"); - } else { - printer->Print( - "void $classname$::UnsafeMergeFrom(const $classname$& from) {\n" - " MergeFrom(from);\n" - "}\n", - "classname", classname_); } GenerateSwap(printer); @@ -1974,15 +1751,12 @@ GenerateClassMethods(io::Printer* printer) { if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( - "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" - " protobuf_AssignDescriptorsOnce();\n" - " ::google::protobuf::Metadata metadata;\n" - " metadata.descriptor = $classname$_descriptor_;\n" - " metadata.reflection = $classname$_reflection_;\n" - " return metadata;\n" - "}\n" - "\n", - "classname", classname_); + "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" + " protobuf_AssignDescriptorsOnce();\n" + " return file_level_metadata[$index$];\n" + "}\n" + "\n", + "classname", classname_, "index", SimpleItoa(index_in_metadata_)); } else { printer->Print( "::std::string $classname$::GetTypeName() const {\n" @@ -1995,22 +1769,49 @@ GenerateClassMethods(io::Printer* printer) { } -void MessageGenerator:: -GenerateOffsets(io::Printer* printer) { - printer->Print("static const int $classname$_offsets_[$field_count$] = {\n", - "classname", classname_, "field_count", - SimpleItoa(std::max(1, descriptor_->field_count() + - descriptor_->oneof_decl_count()))); - printer->Indent(); +std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( + io::Printer* printer) { + if (IsMapEntryMessage(descriptor_)) return std::make_pair(0, 0); + std::map<string, string> variables; + variables["classname"] = classname_; + if (HasFieldPresence(descriptor_->file())) { + printer->Print( + variables, + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_),\n"); + } else { + printer->Print("~0u, // no _has_bits_\n"); + } + printer->Print(variables, + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " + "_internal_metadata_),\n"); + if (descriptor_->extension_range_count() > 0) { + printer->Print( + variables, + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _extensions_),\n"); + } else { + printer->Print("~0u, // no _extensions_\n"); + } + if (descriptor_->oneof_decl_count() > 0) { + printer->Print(variables, + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " + "_oneof_case_[0]),\n"); + } else { + printer->Print("~0u, // no _oneof_case_\n"); + } + + const int kNumGenericOffsets = 4; // the number of fixed offsets above + const size_t offsets = kNumGenericOffsets + + descriptor_->field_count() + + descriptor_->oneof_decl_count(); + size_t entries = offsets; for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); if (field->containing_oneof()) { printer->Print( "PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(" - "$classname$_default_oneof_instance_, $name$_),\n", - "classname", classname_, - "name", FieldName(field)); + "(&$classname$_default_oneof_instance_), $name$_),\n", + "classname", classname_, "name", FieldName(field)); } else { printer->Print( "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " @@ -2028,8 +1829,14 @@ GenerateOffsets(io::Printer* printer) { "name", oneof->name()); } - printer->Outdent(); - printer->Print("};\n"); + if (HasFieldPresence(descriptor_->file())) { + entries += has_bit_indices_.size(); + for (int i = 0; i < has_bit_indices_.size(); i++) { + printer->Print("$index$,\n", "index", SimpleItoa(has_bit_indices_[i])); + } + } + + return std::make_pair(entries, offsets); } void MessageGenerator:: @@ -2043,66 +1850,26 @@ GenerateSharedConstructorCode(io::Printer* printer) { // We reproduce the logic used for laying out _cached_sized_ in the class // definition, as to initialize it in-order. if (HasFieldPresence(descriptor_->file()) && - (HasBitsSize(descriptor_) % 8) != 0) { + (HasBitsSize() % 8) != 0) { printer->Print("_cached_size_ = 0;\n"); need_to_clear_cached_size = false; } - if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - "_unknown_fields_.UnsafeSetDefault(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); - } - - const FieldDescriptor* last_start = NULL; - // RunMap maps from fields that start each run to the number of fields in that - // run. This is optimized for the common case that there are very few runs in - // a message and that most of the eligible fields appear together. - typedef hash_map<const FieldDescriptor*, size_t> RunMap; - RunMap runs; - - for (int i = 0; i < optimized_order_.size(); ++i) { - const FieldDescriptor* field = optimized_order_[i]; - // TODO(ckennelly): Scalar messages (raw pointers) can be initialized by - // zero as well. - if (CanInitializeByZeroing(field)) { - if (last_start == NULL) { - last_start = field; - } - - runs[last_start]++; - } else { - last_start = NULL; - } - } - - for (int i = 0; i < optimized_order_.size(); ++i) { - const FieldDescriptor* field = optimized_order_[i]; - RunMap::const_iterator it = runs.find(field); - - // We only apply the memset technique to runs of more than one field, as - // assignment is better than memset for generated code clarity. - if (it != runs.end() && it->second > 1) { - // Use a memset, then skip run_length fields. - const size_t run_length = it->second; - const string first_field_name = FieldName(field); - const string last_field_name = - FieldName(optimized_order_[i + run_length - 1]); - + // TODO(gerbens) Clean this hack, and why do i need a reference to a pointer?? + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + if (HasDescriptorMethods(descriptor_->file(), options_) && + IsMapEntryMessage(descriptor_->nested_type(i))) { printer->Print( - "::memset(&$first$_, 0, reinterpret_cast<char*>(&$last$_) -\n" - " reinterpret_cast<char*>(&$first$_) + sizeof($last$_));\n", - "first", first_field_name, - "last", last_field_name); - - i += run_length - 1; - // ++i at the top of the loop. - } else { - field_generators_.get(field).GenerateConstructorCode(printer); + "const ::google::protobuf::Descriptor*& $type$_descriptor = " + "file_level_metadata[$index$].descriptor;\n", + "type", ClassName(descriptor_->nested_type(i), false), "index", + SimpleItoa(nested_generators_[i]->index_in_metadata_)); } } + std::vector<bool> processed(optimized_order_.size(), false); + GenerateConstructorBody(printer, processed, false); + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( "clear_has_$oneof_name$();\n", @@ -2133,21 +1900,6 @@ GenerateSharedDestructorCode(io::Printer* printer) { "\n"); } - // Write the desctructor for _unknown_fields_ in lite runtime. - if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file(), options_)) { - if (SupportsArenas(descriptor_)) { - printer->Print( - "_unknown_fields_.Destroy(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" - " arena);\n"); - } else { - printer->Print( - "_unknown_fields_.DestroyNoArena(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); - } - } - // Write the destructors for each field except oneof members. // optimized_order_ does not contain oneof fields. for (int i = 0; i < optimized_order_.size(); i++) { @@ -2164,35 +1916,6 @@ GenerateSharedDestructorCode(io::Printer* printer) { "oneof_name", descriptor_->oneof_decl(i)->name()); } - // We need to delete all embedded messages. - // TODO(kenton): If we make unset messages point at default instances - // instead of NULL, then it would make sense to move this code into - // MessageFieldGenerator::GenerateDestructorCode(). - bool need_delete_message_field = false; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - - if (!field->is_repeated() && - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - // Skip oneof members - if (!field->containing_oneof()) { - if (!need_delete_message_field) { - need_delete_message_field = true; - printer->Print( - "if (this != &$classname$_default_instance_.get()) {\n", - "classname", classname_); - printer->Indent(); - } - printer->Print("delete $name$_;\n", "name", FieldName(field)); - } - } - } - if (need_delete_message_field) { - printer->Outdent(); - printer->Print( - "}\n"); - } - printer->Outdent(); printer->Print( "}\n" @@ -2219,12 +1942,31 @@ GenerateArenaDestructorCode(io::Printer* printer) { "classname", classname_); bool need_registration = false; - for (int i = 0; i < descriptor_->field_count(); i++) { - if (field_generators_.get(descriptor_->field(i)) + // Process non-oneof fields first. + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + if (field_generators_.get(field) .GenerateArenaDestructorCode(printer)) { need_registration = true; } } + + // Process oneof fields. + // + // Note: As of 10/5/2016, GenerateArenaDestructorCode does not emit anything + // and returns false for oneof fields. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + + for (int j = 0; j < oneof->field_count(); j++) { + const FieldDescriptor* field = oneof->field(j); + if (field_generators_.get(field) + .GenerateArenaDestructorCode(printer)) { + need_registration = true; + } + } + } + printer->Outdent(); printer->Print( "}\n"); @@ -2245,6 +1987,75 @@ GenerateArenaDestructorCode(io::Printer* printer) { } } +void MessageGenerator::GenerateConstructorBody(io::Printer* printer, + std::vector<bool> processed, + bool copy_constructor) const { + const FieldDescriptor* last_start = NULL; + // RunMap maps from fields that start each run to the number of fields in that + // run. This is optimized for the common case that there are very few runs in + // a message and that most of the eligible fields appear together. + typedef hash_map<const FieldDescriptor*, size_t> RunMap; + RunMap runs; + + for (int i = 0; i < optimized_order_.size(); ++i) { + const FieldDescriptor* field = optimized_order_[i]; + if ((copy_constructor && IsPOD(field)) || + (!copy_constructor && CanConstructByZeroing(field, options_))) { + if (last_start == NULL) { + last_start = field; + } + + runs[last_start]++; + } else { + last_start = NULL; + } + } + + string pod_template; + if (copy_constructor) { + pod_template = + "::memcpy(&$first$_, &from.$first$_,\n" + " reinterpret_cast<char*>(&$last$_) -\n" + " reinterpret_cast<char*>(&$first$_) + sizeof($last$_));\n"; + } else { + pod_template = + "::memset(&$first$_, 0, reinterpret_cast<char*>(&$last$_) -\n" + " reinterpret_cast<char*>(&$first$_) + sizeof($last$_));\n"; + } + + for (int i = 0; i < optimized_order_.size(); ++i) { + if (processed[i]) { + continue; + } + + const FieldDescriptor* field = optimized_order_[i]; + RunMap::const_iterator it = runs.find(field); + + // We only apply the memset technique to runs of more than one field, as + // assignment is better than memset for generated code clarity. + if (it != runs.end() && it->second > 1) { + // Use a memset, then skip run_length fields. + const size_t run_length = it->second; + const string first_field_name = FieldName(field); + const string last_field_name = + FieldName(optimized_order_[i + run_length - 1]); + + printer->Print(pod_template.c_str(), + "first", first_field_name, + "last", last_field_name); + + i += run_length - 1; + // ++i at the top of the loop. + } else { + if (copy_constructor) { + field_generators_.get(field).GenerateCopyConstructorCode(printer); + } else { + field_generators_.get(field).GenerateConstructorCode(printer); + } + } + } +} + void MessageGenerator:: GenerateStructors(io::Printer* printer) { string superclass; @@ -2260,11 +2071,7 @@ GenerateStructors(io::Printer* printer) { initializer_with_arena += ",\n _extensions_(arena)"; } - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - initializer_with_arena += ",\n _internal_metadata_(arena)"; - } else { - initializer_with_arena += ",\n _arena_ptr_(arena)"; - } + initializer_with_arena += ",\n _internal_metadata_(arena)"; // Initialize member variables with arena constructor. for (int i = 0; i < optimized_order_.size(); i++) { @@ -2282,8 +2089,7 @@ GenerateStructors(io::Printer* printer) { } string initializer_null; - initializer_null = (UseUnknownFieldSet(descriptor_->file(), options_) ? - ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)"); + initializer_null = ", _internal_metadata_(NULL)"; if (IsAnyMessage(descriptor_)) { initializer_null += ", _any_metadata_(&type_url_, &value_)"; } @@ -2291,7 +2097,9 @@ GenerateStructors(io::Printer* printer) { printer->Print( "$classname$::$classname$()\n" " : $superclass$()$initializer$ {\n" - " if (this != internal_default_instance()) $initdefaultsname$();\n" + " if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {\n" + " $initdefaultsname$();\n" + " }\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", @@ -2318,44 +2126,6 @@ GenerateStructors(io::Printer* printer) { GlobalInitDefaultsName(descriptor_->file()->name())); } - printer->Print( - "\n" - "void $classname$::InitAsDefaultInstance() {\n", - "classname", classname_); - - // The default instance needs all of its embedded message pointers - // cross-linked to other default instances. We can't do this initialization - // in the constructor because some other default instances may not have been - // constructed yet at that time. - // TODO(kenton): Maybe all message fields (even for non-default messages) - // should be initialized to point at default instances rather than NULL? - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - - if (!field->is_repeated() && - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - (field->containing_oneof() == NULL || - HasDescriptorMethods(descriptor_->file(), options_))) { - string name; - if (field->containing_oneof()) { - name = classname_ + "_default_oneof_instance_->"; - } - name += FieldName(field); - printer->Print( - " $name$_ = const_cast< $type$*>(\n" - " $type$::internal_default_instance());\n", - // Vars. - "name", name, "type", FieldMessageTypeName(field)); - } else if (field->containing_oneof() && - HasDescriptorMethods(descriptor_->file(), options_)) { - field_generators_.get(descriptor_->field(i)) - .GenerateConstructorCode(printer); - } - } - printer->Print( - "}\n" - "\n"); - // Generate the copy constructor. printer->Print( "$classname$::$classname$(const $classname$& from)\n" @@ -2363,24 +2133,113 @@ GenerateStructors(io::Printer* printer) { "classname", classname_, "superclass", superclass, "full_name", descriptor_->full_name()); - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - ",\n _internal_metadata_(NULL)"); - } else if (!UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print(",\n _arena_ptr_(NULL)"); + printer->Indent(); + printer->Indent(); + printer->Indent(); + + printer->Print( + ",\n_internal_metadata_(NULL)"); + + if (HasFieldPresence(descriptor_->file())) { + printer->Print(",\n_has_bits_(from._has_bits_)"); + } + + bool need_to_emit_cached_size = true; + const string cached_size_decl = ",\n_cached_size_(0)"; + // We reproduce the logic used for laying out _cached_sized_ in the class + // definition, as to initialize it in-order. + if (HasFieldPresence(descriptor_->file()) && + (HasBitsSize() % 8) != 0) { + printer->Print(cached_size_decl.c_str()); + need_to_emit_cached_size = false; } + + std::vector<bool> processed(optimized_order_.size(), false); + for (int i = 0; i < optimized_order_.size(); ++i) { + const FieldDescriptor* field = optimized_order_[i]; + + if (!(field->is_repeated() && !(field->is_map())) + ) { + continue; + } + + processed[i] = true; + printer->Print(",\n$name$_(from.$name$_)", + "name", FieldName(field)); + } + + if (need_to_emit_cached_size) { + printer->Print(cached_size_decl.c_str()); + need_to_emit_cached_size = false; + } + if (IsAnyMessage(descriptor_)) { - printer->Print(",\n _any_metadata_(&type_url_, &value_)"); + printer->Print(",\n_any_metadata_(&type_url_, &value_)"); } + + printer->Outdent(); + printer->Outdent(); printer->Print(" {\n"); + + printer->Print( + "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"); + + if (descriptor_->extension_range_count() > 0) { + printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); + } + + // TODO(gerbens) Clean this hack, and why do i need a reference to a pointer?? + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + if (HasDescriptorMethods(descriptor_->file(), options_) && + IsMapEntryMessage(descriptor_->nested_type(i))) { + printer->Print( + "const ::google::protobuf::Descriptor*& $type$_descriptor = " + "file_level_metadata[$index$].descriptor;\n", + "type", ClassName(descriptor_->nested_type(i), false), "index", + SimpleItoa(nested_generators_[i]->index_in_metadata_)); + } + } + + GenerateConstructorBody(printer, processed, true); + + // Copy oneof fields. Oneof field requires oneof case check. + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + printer->Print( + "clear_has_$oneofname$();\n" + "switch (from.$oneofname$_case()) {\n", + "oneofname", descriptor_->oneof_decl(i)->name()); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "case k$field_name$: {\n", + "field_name", UnderscoresToCamelCase(field->name(), true)); + printer->Indent(); + field_generators_.get(field).GenerateMergingCode(printer); + printer->Print( + "break;\n"); + printer->Outdent(); + printer->Print( + "}\n"); + } + printer->Print( + "case $cap_oneof_name$_NOT_SET: {\n" + " break;\n" + "}\n", + "oneof_index", + SimpleItoa(descriptor_->oneof_decl(i)->index()), + "cap_oneof_name", + ToUpper(descriptor_->oneof_decl(i)->name())); + printer->Outdent(); + printer->Print( + "}\n"); + } + + printer->Outdent(); printer->Print( - " SharedCtor();\n" - " UnsafeMergeFrom(from);\n" " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" "}\n" "\n", - "classname", classname_, - "superclass", superclass, "full_name", descriptor_->full_name()); // Generate the shared constructor code. @@ -2419,28 +2278,20 @@ GenerateStructors(io::Printer* printer) { printer->Print( "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" " protobuf_AssignDescriptorsOnce();\n" - " return $classname$_descriptor_;\n" + " return file_level_metadata[$index$].descriptor;\n" "}\n" "\n", - "classname", classname_, "initdefaultsname", - GlobalInitDefaultsName(descriptor_->file()->name())); + "index", SimpleItoa(index_in_metadata_), "classname", classname_); } printer->Print( "const $classname$& $classname$::default_instance() {\n" " $initdefaultsname$();\n" " return *internal_default_instance();\n" - "}\n", + "}\n\n", "classname", classname_, "initdefaultsname", GlobalInitDefaultsName(descriptor_->file()->name())); - printer->Print( - "\n" - "::google::protobuf::internal::ExplicitlyConstructed<$classname$> " - "$classname$_default_instance_;\n" - "\n", - "classname", classname_); - if (SupportsArenas(descriptor_)) { printer->Print( "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n" @@ -2484,154 +2335,173 @@ GenerateClear(io::Printer* printer) { printer->Print("_extensions_.Clear();\n"); } - // Step 2: Everything but extensions, repeateds, unions. - // These are handled in chunks of 8. The first chunk is - // the non-extensions-non-repeateds-non-unions in - // descriptor_->field(0), descriptor_->field(1), ... descriptor_->field(7), - // and the second chunk is the same for - // descriptor_->field(8), descriptor_->field(9), ... descriptor_->field(15), - // etc. - set<int> step2_indices; - hash_map<string, int> fieldname_to_chunk; - hash_map<int, string> memsets_for_chunk; - hash_map<int, int> memset_field_count_for_chunk; - hash_set<string> handled; // fields that appear anywhere in memsets_for_chunk - hash_map<int, uint32> fields_mask_for_chunk; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - if (!field->is_repeated() && !field->containing_oneof()) { - step2_indices.insert(i); - int chunk = i / 8; - fieldname_to_chunk[FieldName(field)] = chunk; - fields_mask_for_chunk[chunk] |= static_cast<uint32>(1) << (i % 32); - } - } - - // Step 2a: Greedily seek runs of fields that can be cleared by memset-to-0. - // The generated code uses two macros to help it clear runs of fields: - // ZR_HELPER_(f1) - ZR_HELPER_(f0) computes the difference, in bytes, of the - // positions of two fields in the Message. - // ZR_ zeroes a non-empty range of fields via memset. - const char* macros = - "#if defined(__clang__)\n" - "#define ZR_HELPER_(f) \\\n" - " _Pragma(\"clang diagnostic push\") \\\n" - " _Pragma(\"clang diagnostic ignored \\\"-Winvalid-offsetof\\\"\") \\\n" - " __builtin_offsetof($classname$, f) \\\n" - " _Pragma(\"clang diagnostic pop\")\n" - "#else\n" - "#define ZR_HELPER_(f) reinterpret_cast<char*>(\\\n" - " &reinterpret_cast<$classname$*>(16)->f)\n" - "#endif\n\n" - "#define ZR_(first, last) do {\\\n" - " ::memset(&(first), 0,\\\n" - " ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n" - "} while (0)\n\n"; - for (int i = 0; i < runs_of_fields_.size(); i++) { - const vector<string>& run = runs_of_fields_[i]; - if (run.size() < 2) continue; - const string& first_field_name = run[0]; - const string& last_field_name = run.back(); - int chunk = fieldname_to_chunk[run[0]]; - memsets_for_chunk[chunk].append( - "ZR_(" + first_field_name + "_, " + last_field_name + "_);\n"); - for (int j = 0; j < run.size(); j++) { - GOOGLE_DCHECK_EQ(chunk, fieldname_to_chunk[run[j]]); - handled.insert(run[j]); - } - memset_field_count_for_chunk[chunk] += run.size(); - } - const bool macros_are_needed = handled.size() > 0; - if (macros_are_needed) { - printer->Outdent(); - printer->Print(macros, - "classname", classname_); - printer->Indent(); - } - // Step 2b: Finish step 2, ignoring fields handled in step 2a. - int last_index = -1; - bool chunk_block_in_progress = false; - for (int i = 0; i < descriptor_->field_count(); i++) { - if (step2_indices.count(i) == 0) continue; - const FieldDescriptor* field = descriptor_->field(i); - const string fieldname = FieldName(field); - if (i / 8 != last_index / 8 || last_index < 0) { - // End previous chunk, if there was one. - if (chunk_block_in_progress) { - printer->Outdent(); - printer->Print("}\n"); - chunk_block_in_progress = false; + int last_i = -1; + for (int i = 0; i < optimized_order_.size(); ) { + // Detect infinite loops. + GOOGLE_CHECK_NE(i, last_i); + last_i = i; + + // Step 2: Repeated fields don't use _has_bits_; emit code to clear them + // here. + for (; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + const FieldGenerator& generator = field_generators_.get(field); + + if (!field->is_repeated()) { + break; } - // Start chunk. - const string& memsets = memsets_for_chunk[i / 8]; - uint32 mask = fields_mask_for_chunk[i / 8]; - int count = popcnt(mask); - GOOGLE_DCHECK_GE(count, 1); - if (count == 1 || - count == memset_field_count_for_chunk[i / 8]) { - // No "if" here because the chunk is trivial. + + if (use_dependent_base_ && IsFieldDependent(field)) { + printer->Print("clear_$name$();\n", "name", FieldName(field)); } else { - if (HasFieldPresence(descriptor_->file())) { - printer->Print( - "if (_has_bits_[$index$ / 32] & $mask$u) {\n", - "index", SimpleItoa(i / 8 * 8), - "mask", SimpleItoa(mask)); - printer->Indent(); - chunk_block_in_progress = true; - } + generator.GenerateMessageClearingCode(printer); } - printer->Print(memsets.c_str()); - } - last_index = i; - if (handled.count(fieldname) > 0) continue; - - // It's faster to just overwrite primitive types, but we should - // only clear strings and messages if they were set. - // TODO(kenton): Let the CppFieldGenerator decide this somehow. - bool should_check_bit = - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || - field->cpp_type() == FieldDescriptor::CPPTYPE_STRING; - - bool have_enclosing_if = false; - 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); - printer->Indent(); - have_enclosing_if = true; } - if (use_dependent_base_ && IsFieldDependent(field)) { - printer->Print("clear_$name$();\n", "name", fieldname); - } else { - field_generators_.get(field).GenerateClearingCode(printer); + // Step 3: Greedily seek runs of fields that can be cleared by + // memset-to-0. + int last_chunk = -1; + int last_chunk_start = -1; + int last_chunk_end = -1; + uint32 last_chunk_mask = 0; + + int memset_run_start = -1; + int memset_run_end = -1; + for (; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + + if (!CanInitializeByZeroing(field)) { + break; + } + + // "index" defines where in the _has_bits_ the field appears. + // "i" is our loop counter within optimized_order_. + int index = HasFieldPresence(descriptor_->file()) ? + has_bit_indices_[field->index()] : 0; + int chunk = index / 8; + + if (last_chunk == -1) { + last_chunk = chunk; + last_chunk_start = i; + } else if (chunk != last_chunk) { + // Emit the fields for this chunk so far. + break; + } + + if (memset_run_start == -1) { + memset_run_start = i; + } + + memset_run_end = i; + last_chunk_end = i; + last_chunk_mask |= static_cast<uint32>(1) << (index % 32); } - if (have_enclosing_if) { - printer->Outdent(); - printer->Print("}\n"); + // Step 4: Non-repeated, non-zero initializable fields. + for (; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + if (field->is_repeated() || CanInitializeByZeroing(field)) { + break; + } + + // "index" defines where in the _has_bits_ the field appears. + // "i" is our loop counter within optimized_order_. + int index = HasFieldPresence(descriptor_->file()) ? + has_bit_indices_[field->index()] : 0; + int chunk = index / 8; + + if (last_chunk == -1) { + last_chunk = chunk; + last_chunk_start = i; + } else if (chunk != last_chunk) { + // Emit the fields for this chunk so far. + break; + } + + last_chunk_end = i; + last_chunk_mask |= static_cast<uint32>(1) << (index % 32); } - } - if (chunk_block_in_progress) { - printer->Outdent(); - printer->Print("}\n"); - } - if (macros_are_needed) { - printer->Outdent(); - printer->Print("\n#undef ZR_HELPER_\n#undef ZR_\n\n"); - printer->Indent(); - } + if (last_chunk != -1) { + GOOGLE_DCHECK_NE(-1, last_chunk_start); + GOOGLE_DCHECK_NE(-1, last_chunk_end); + GOOGLE_DCHECK_NE(0, last_chunk_mask); - // Step 3: Repeated fields don't use _has_bits_; emit code to clear them here. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + const int count = popcnt(last_chunk_mask); + const bool have_outer_if = HasFieldPresence(descriptor_->file()) && + (last_chunk_start != last_chunk_end); - if (field->is_repeated()) { - if (use_dependent_base_ && IsFieldDependent(field)) { - printer->Print("clear_$name$();\n", "name", FieldName(field)); - } else { - field_generators_.get(field).GenerateClearingCode(printer); + if (have_outer_if) { + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, count); + GOOGLE_DCHECK_GE(8, count); + + printer->Print( + "if (_has_bits_[$index$ / 32] & $mask$u) {\n", + "index", SimpleItoa(last_chunk * 8), + "mask", SimpleItoa(last_chunk_mask)); + printer->Indent(); + } + + if (memset_run_start != -1) { + if (memset_run_start == memset_run_end) { + // For clarity, do not memset a single field. + const FieldGenerator& generator = + field_generators_.get(optimized_order_[memset_run_start]); + generator.GenerateMessageClearingCode(printer); + } else { + const string first_field_name = + FieldName(optimized_order_[memset_run_start]); + const string last_field_name = + FieldName(optimized_order_[memset_run_end]); + + printer->Print( + "::memset(&$first$_, 0, reinterpret_cast<char*>(&$last$_) -\n" + " reinterpret_cast<char*>(&$first$_) + sizeof($last$_));\n", + "first", first_field_name, + "last", last_field_name); + } + + // Advance last_chunk_start to skip over the fields we zeroed/memset. + last_chunk_start = memset_run_end + 1; + } + + // Go back and emit clears for each of the fields we processed. + for (int j = last_chunk_start; j <= last_chunk_end; j++) { + const FieldDescriptor* field = optimized_order_[j]; + const string fieldname = FieldName(field); + const FieldGenerator& generator = field_generators_.get(field); + + // It's faster to just overwrite primitive types, but we should only + // clear strings and messages if they were set. + // + // TODO(kenton): Let the CppFieldGenerator decide this somehow. + bool should_check_bit = + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || + field->cpp_type() == FieldDescriptor::CPPTYPE_STRING; + + bool have_enclosing_if = false; + 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); + printer->Indent(); + have_enclosing_if = true; + } + + generator.GenerateMessageClearingCode(printer); + + if (have_enclosing_if) { + printer->Outdent(); + printer->Print("}\n"); + } + } + + if (have_outer_if) { + printer->Outdent(); + printer->Print("}\n"); } } } @@ -2649,23 +2519,7 @@ GenerateClear(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - "if (_internal_metadata_.have_unknown_fields()) {\n" - " mutable_unknown_fields()->Clear();\n" - "}\n"); - } else { - if (SupportsArenas(descriptor_)) { - printer->Print( - "_unknown_fields_.ClearToEmpty(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" - " GetArenaNoVirtual());\n"); - } else { - printer->Print( - "_unknown_fields_.ClearToEmptyNoArena(\n" - " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); - } - } + printer->Print("_internal_metadata_.Clear();\n"); } printer->Outdent(); @@ -2676,7 +2530,7 @@ void MessageGenerator:: GenerateOneofClear(io::Printer* printer) { // Generated function clears the active field and union case (e.g. foo_case_). for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - map<string, string> oneof_vars; + std::map<string, string> oneof_vars; oneof_vars["classname"] = classname_; oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); oneof_vars["full_name"] = descriptor_->full_name(); @@ -2742,10 +2596,13 @@ GenerateSwap(io::Printer* printer) { " if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {\n" " InternalSwap(other);\n" " } else {\n" - " $classname$ temp;\n" - " temp.UnsafeMergeFrom(*this);\n" - " CopyFrom(*other);\n" - " other->CopyFrom(temp);\n" + " $classname$* temp = New(GetArenaNoVirtual());\n" + " temp->MergeFrom(*other);\n" + " other->CopyFrom(*this);\n" + " InternalSwap(temp);\n" + " if (GetArenaNoVirtual() == NULL) {\n" + " delete temp;\n" + " }\n" " }\n" "}\n" "void $classname$::UnsafeArenaSwap($classname$* other) {\n" @@ -2769,8 +2626,10 @@ GenerateSwap(io::Printer* printer) { printer->Indent(); if (HasGeneratedMethods(descriptor_->file(), options_)) { - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + for (int i = 0; i < optimized_order_.size(); i++) { + // optimized_order_ does not contain oneof fields, but the field + // generators for these fields do not emit swapping code on their own. + const FieldDescriptor* field = optimized_order_[i]; field_generators_.get(field).GenerateSwappingCode(printer); } @@ -2789,13 +2648,8 @@ GenerateSwap(io::Printer* printer) { } } - // Ignore PreserveUnknownFields here - always swap internal_metadata as it - // may contain more than just unknown fields. - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - } else { - printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); + if (PreserveUnknownFields(descriptor_)) { + printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n"); } printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); @@ -2819,7 +2673,7 @@ GenerateMergeFrom(io::Printer* printer) { "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n" "// @@protoc_insertion_point(generalized_merge_from_start:" "$full_name$)\n" - " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", + " GOOGLE_DCHECK_NE(&from, this);\n", "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); @@ -2838,7 +2692,7 @@ GenerateMergeFrom(io::Printer* printer) { "} else {\n" "// @@protoc_insertion_point(generalized_merge_from_cast_success:" "$full_name$)\n" - " UnsafeMergeFrom(*source);\n" + " MergeFrom(*source);\n" "}\n", "classname", classname_, "full_name", descriptor_->full_name()); @@ -2860,25 +2714,118 @@ GenerateMergeFrom(io::Printer* printer) { "void $classname$::MergeFrom(const $classname$& from) {\n" "// @@protoc_insertion_point(class_specific_merge_from_start:" "$full_name$)\n" - " if (GOOGLE_PREDICT_TRUE(&from != this)) {\n" - " UnsafeMergeFrom(from);\n" - " } else {\n" - " MergeFromFail(__LINE__);\n" - " }\n" - "}\n" - "\n" - "void $classname$::UnsafeMergeFrom(const $classname$& from) {\n" - " GOOGLE_DCHECK(&from != this);\n", + " GOOGLE_DCHECK_NE(&from, this);\n", "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); - // Merge Repeated fields. These fields do not require a - // check as we can simply iterate over them. - for (int i = 0; i < descriptor_->field_count(); ++i) { - const FieldDescriptor* field = descriptor_->field(i); + if (descriptor_->extension_range_count() > 0) { + printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); + } - if (field->is_repeated()) { - field_generators_.get(field).GenerateUnsafeMergingCode(printer); + printer->Print( + "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"); + + int last_i = -1; + for (int i = 0; i < optimized_order_.size(); ) { + // Detect infinite loops. + GOOGLE_CHECK_NE(i, last_i); + last_i = i; + + // Merge Repeated fields. These fields do not require a + // check as we can simply iterate over them. + for (; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + if (!field->is_repeated()) { + break; + } + + const FieldGenerator& generator = field_generators_.get(field); + generator.GenerateMergingCode(printer); + } + + // Merge Optional and Required fields (after a _has_bit check). + int last_chunk = -1; + int last_chunk_start = -1; + int last_chunk_end = -1; + uint32 last_chunk_mask = 0; + for (; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + if (field->is_repeated()) { + break; + } + + // "index" defines where in the _has_bits_ the field appears. + // "i" is our loop counter within optimized_order_. + int index = HasFieldPresence(descriptor_->file()) ? + has_bit_indices_[field->index()] : 0; + int chunk = index / 8; + + if (last_chunk == -1) { + last_chunk = chunk; + last_chunk_start = i; + } else if (chunk != last_chunk) { + // Emit the fields for this chunk so far. + break; + } + + last_chunk_end = i; + last_chunk_mask |= static_cast<uint32>(1) << (index % 32); + } + + if (last_chunk != -1) { + GOOGLE_DCHECK_NE(-1, last_chunk_start); + GOOGLE_DCHECK_NE(-1, last_chunk_end); + GOOGLE_DCHECK_NE(0, last_chunk_mask); + + const int count = popcnt(last_chunk_mask); + const bool have_outer_if = HasFieldPresence(descriptor_->file()) && + (last_chunk_start != last_chunk_end); + + if (have_outer_if) { + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, count); + GOOGLE_DCHECK_GE(8, count); + + printer->Print( + "if (from._has_bits_[$index$ / 32] & $mask$u) {\n", + "index", SimpleItoa(last_chunk * 8), + "mask", SimpleItoa(last_chunk_mask)); + printer->Indent(); + } + + // Go back and emit clears for each of the fields we processed. + for (int j = last_chunk_start; j <= last_chunk_end; j++) { + const FieldDescriptor* field = optimized_order_[j]; + const FieldGenerator& generator = field_generators_.get(field); + + bool have_enclosing_if = false; + if (HasFieldPresence(descriptor_->file())) { + printer->Print( + "if (from.has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + have_enclosing_if = true; + } else { + // Merge semantics without true field presence: primitive fields are + // merged only if non-zero (numeric) or non-empty (string). + have_enclosing_if = EmitFieldNonDefaultCondition( + printer, "from.", field); + } + + generator.GenerateMergingCode(printer); + + if (have_enclosing_if) { + printer->Outdent(); + printer->Print("}\n"); + } + } + + if (have_outer_if) { + printer->Outdent(); + printer->Print("}\n"); + } } } @@ -2912,78 +2859,6 @@ GenerateMergeFrom(io::Printer* printer) { "}\n"); } - // Merge Optional and Required fields (after a _has_bit check). - int last_index = -1; - - for (int i = 0; i < descriptor_->field_count(); ++i) { - const FieldDescriptor* field = descriptor_->field(i); - - if (!field->is_repeated() && !field->containing_oneof()) { - if (HasFieldPresence(descriptor_->file())) { - // See above in GenerateClear for an explanation of this. - if (i / 8 != last_index / 8 || last_index < 0) { - if (last_index >= 0) { - printer->Outdent(); - printer->Print("}\n"); - } - printer->Print( - "if (from._has_bits_[$index$ / 32] & " - "(0xffu << ($index$ % 32))) {\n", - "index", SimpleItoa(field->index())); - printer->Indent(); - } - } - - last_index = i; - - bool have_enclosing_if = false; - if (HasFieldPresence(descriptor_->file())) { - printer->Print( - "if (from.has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); - have_enclosing_if = true; - } else { - // Merge semantics without true field presence: primitive fields are - // merged only if non-zero (numeric) or non-empty (string). - have_enclosing_if = EmitFieldNonDefaultCondition( - printer, "from.", field); - } - - field_generators_.get(field).GenerateMergingCode(printer); - - if (have_enclosing_if) { - printer->Outdent(); - printer->Print("}\n"); - } - } - } - - if (HasFieldPresence(descriptor_->file()) && - last_index >= 0) { - printer->Outdent(); - printer->Print("}\n"); - } - - if (descriptor_->extension_range_count() > 0) { - printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); - } - - if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - printer->Print( - "if (from._internal_metadata_.have_unknown_fields()) {\n" - " ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(\n" - " from.unknown_fields(), &_internal_metadata_);\n" - "}\n"); - } else { - printer->Print( - "if (!from.unknown_fields().empty()) {\n" - " mutable_unknown_fields()->append(from.unknown_fields());\n" - "}\n"); - } - } - printer->Outdent(); printer->Print("}\n"); } @@ -3020,7 +2895,7 @@ GenerateCopyFrom(io::Printer* printer) { printer->Print( "if (&from == this) return;\n" "Clear();\n" - "UnsafeMergeFrom(from);\n"); + "MergeFrom(from);\n"); printer->Outdent(); printer->Print("}\n"); @@ -3061,7 +2936,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // on the CodedOutputStream. printer->Print( " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n" - " ::google::protobuf::NewPermanentCallback(\n" + " NewPermanentCallback(\n" " &MutableUnknownFieldsFor$classname$, this));\n" " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" " &unknown_fields_string, false);\n", @@ -3082,13 +2957,41 @@ GenerateMergeFromCodedStream(io::Printer* printer) { WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]); const int kCutoff0 = 127; // fits in 1-byte varint const int kCutoff1 = (127 << 7) + 127; // fits in 2-byte varint + + // We need to capture the last tag when parsing if this is a Group type, as + // our caller will verify (via CodedInputStream::LastTagWas) that the correct + // closing tag was received. + bool capture_last_tag = false; + const Descriptor* parent = descriptor_->containing_type(); + if (parent) { + for (int i = 0; i < parent->field_count(); i++) { + const FieldDescriptor* field = parent->field(i); + if (field->type() == FieldDescriptor::TYPE_GROUP && + field->message_type() == descriptor_) { + capture_last_tag = true; + break; + } + } + } + + for (int i = 0; i < descriptor_->file()->extension_count(); i++) { + const FieldDescriptor* field = descriptor_->file()->extension(i); + if (field->type() == FieldDescriptor::TYPE_GROUP && + field->message_type() == descriptor_) { + capture_last_tag = true; + break; + } + } + printer->Print("::std::pair< ::google::protobuf::uint32, bool> p = " - "input->ReadTagWithCutoff($max$);\n" + "input->ReadTagWithCutoff$lasttag$($max$);\n" "tag = p.first;\n" "if (!p.second) goto handle_unusual;\n", "max", SimpleItoa(maxtag <= kCutoff0 ? kCutoff0 : (maxtag <= kCutoff1 ? kCutoff1 : - maxtag))); + maxtag)), + "lasttag", !capture_last_tag ? "NoLastTag" : ""); + if (descriptor_->field_count() > 0) { // We don't even want to print the switch() if we have no fields because // MSVC dislikes switch() statements that contain only a default value. @@ -3098,6 +3001,13 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // of each case. However, this is actually a bit slower in practice as it // creates a jump table that is 8x larger and sparser, and meanwhile the // if()s are highly predictable. + // + // Historically, we inserted checks to peek at the next tag on the wire and + // jump directly to the next case statement. While this avoids the jump + // table that the switch uses, it greatly increases code size (20-60%) and + // inserts branches that may fail (especially for real world protos that + // interleave--in field number order--hot and cold fields). Loadtests + // confirmed that removing this optimization is performance neutral. printer->Print("switch (::google::protobuf::internal::WireFormatLite::" "GetTagFieldNumber(tag)) {\n"); @@ -3114,19 +3024,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } } - // need_label is true if we generated "goto parse_$name$" while handling the - // previous field. - bool need_label = false; - // Pay attention to whether we are in a run of fields from the same oneof. - // Motivation: it would be unusual to parse multiple values for a single - // oneof, since only the last would be used. - const FieldDescriptor* last_of_current_oneof = NULL; - // The following is valid iff last_of_current_oneof is non-NULL. - int index_of_last_of_current_oneof = -1; for (int i = 0; i < ordered_fields.size(); i++) { const FieldDescriptor* field = ordered_fields[i]; const bool loops = fields_with_parse_loop.count(i) > 0; - const bool next_field_loops = fields_with_parse_loop.count(i + 1) > 0; PrintFieldComment(printer, field); @@ -3140,17 +3040,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print("if (tag == $commontag$) {\n", "commontag", SimpleItoa(WireFormat::MakeTag(field))); - if (need_label || - (field->is_repeated() && !field->is_packed() && !loops)) { - printer->Print( - " parse_$name$:\n", - "name", field->name()); - } if (loops) { - printer->Print( - " DO_(input->IncrementRecursionDepth());\n" - " parse_loop_$name$:\n", - "name", field->name()); + printer->Print(" DO_(input->IncrementRecursionDepth());\n"); } printer->Indent(); @@ -3189,87 +3080,10 @@ GenerateMergeFromCodedStream(io::Printer* printer) { " goto handle_unusual;\n" "}\n"); - // switch() is slow since it can't be predicted well. Insert some if()s - // here that attempt to predict the next tag. - // For non-packed repeated fields, expect the same tag again. + // For repeated messages/groups, we need to decrement recursion depth. if (loops) { printer->Print( - "if (input->ExpectTag($tag$)) goto parse_loop_$name$;\n", - "tag", SimpleItoa(WireFormat::MakeTag(field)), - "name", field->name()); - } else if (field->is_repeated() && !field->is_packed()) { - printer->Print( - "if (input->ExpectTag($tag$)) goto parse_$name$;\n", - "tag", SimpleItoa(WireFormat::MakeTag(field)), - "name", field->name()); - } - - // Have we emitted "if (input->ExpectTag($next_tag$)) ..." yet? - bool emitted_goto_next_tag = false; - - // For repeated messages/groups, we need to decrement recursion depth, - // unless the next tag is also for a repeated message/group. - if (loops) { - if (next_field_loops) { - const FieldDescriptor* next_field = ordered_fields[i + 1]; - printer->Print( - "if (input->ExpectTag($next_tag$)) goto parse_loop_$next_name$;\n", - "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), - "next_name", next_field->name()); - emitted_goto_next_tag = true; - } - printer->Print( - "input->UnsafeDecrementRecursionDepth();\n"); - } - - // If there are more fields, expect the next one, unless we just parsed - // a oneof and the next field would be from the same oneof. (There's no - // reason to expect something that makes what we just read irrelevant, - // so guess something after the current string of fields from this oneof.) - need_label = false; - if (!emitted_goto_next_tag) { - // delta is the distance in ordered_fields[] from the current field to - // the field we'll guess is next. - int delta = last_of_current_oneof == NULL - ? 1 - : std::max(index_of_last_of_current_oneof - i, 1); - if (i == index_of_last_of_current_oneof) { - printer->Outdent(); - printer->Print( - " after_$last$:\n", - "last", FieldName(last_of_current_oneof)); - printer->Indent(); - last_of_current_oneof = NULL; - } else if (last_of_current_oneof == NULL) { - delta = 1; - // Check for the unlikely case that delta > 1 is better. - if (field->containing_oneof() != NULL) { - while (i + delta < ordered_fields.size() && - ordered_fields[i + delta]->containing_oneof() == - field->containing_oneof()) { - index_of_last_of_current_oneof = i + delta; - last_of_current_oneof = ordered_fields[i + delta]; - ++delta; - } - } - } - if (delta > 1) { - printer->Print( - "goto after_$last$;\n", - "last", FieldName(last_of_current_oneof)); - } else if (i + delta == descriptor_->field_count()) { - // Expect EOF. - // TODO(kenton): Expect group end-tag? - printer->Print( - "if (input->ExpectAtEnd()) goto success;\n"); - } else { - const FieldDescriptor* next_field = ordered_fields[i + delta]; - printer->Print( - "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n", - "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), - "next_name", next_field->name()); - need_label = delta == 1; - } + "input->UnsafeDecrementRecursionDepth();\n"); } printer->Print( @@ -3382,7 +3196,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } void MessageGenerator::GenerateSerializeOneofFields( - io::Printer* printer, const vector<const FieldDescriptor*>& fields, + io::Printer* printer, const std::vector<const FieldDescriptor*>& fields, bool to_array) { GOOGLE_CHECK(!fields.empty()); if (fields.size() == 1) { @@ -3450,7 +3264,7 @@ void MessageGenerator::GenerateSerializeOneField( void MessageGenerator::GenerateSerializeOneExtensionRange( io::Printer* printer, const Descriptor::ExtensionRange* range, bool to_array) { - map<string, string> vars; + std::map<string, string> vars; vars["start"] = SimpleItoa(range->start); vars["end"] = SimpleItoa(range->end); printer->Print(vars, @@ -3600,7 +3414,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { io::Printer* printer_; const bool to_array_; const bool eager_; - vector<const FieldDescriptor*> v_; + std::vector<const FieldDescriptor*> v_; }; std::vector<const FieldDescriptor*> ordered_fields = @@ -3663,30 +3477,29 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { } } -static vector<uint32> RequiredFieldsBitMask(const Descriptor* desc) { - vector<uint32> result; - uint32 mask = 0; - for (int i = 0; i < desc->field_count(); i++) { - if (i > 0 && i % 32 == 0) { - result.push_back(mask); - mask = 0; - } - if (desc->field(i)->is_required()) { - mask |= (1 << (i & 31)); +std::vector<uint32> MessageGenerator::RequiredFieldsBitMask() const { + const int array_size = HasBitsSize(); + std::vector<uint32> masks(array_size, 0); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (!field->is_required()) { + continue; } + + const int has_bit_index = has_bit_indices_[field->index()]; + masks[has_bit_index / 32] |= + static_cast<uint32>(1) << (has_bit_index % 32); } - if (mask != 0) { - result.push_back(mask); - } - return result; + return masks; } // Create an expression that evaluates to // "for all i, (_has_bits_[i] & masks[i]) == masks[i]" // masks is allowed to be shorter than _has_bits_, but at least one element of // masks must be non-zero. -static string ConditionalToCheckBitmasks(const vector<uint32>& masks) { - vector<string> parts; +static string ConditionalToCheckBitmasks(const std::vector<uint32>& masks) { + std::vector<string> parts; for (int i = 0; i < masks.size(); i++) { if (masks[i] == 0) continue; string m = StrCat("0x", strings::Hex(masks[i], strings::ZERO_PAD_8)); @@ -3735,8 +3548,8 @@ GenerateByteSize(io::Printer* printer) { "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); printer->Print("size_t total_size = 0;\n"); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; if (field->is_required()) { printer->Print("\n" "if (has_$name$()) {\n", @@ -3763,18 +3576,41 @@ GenerateByteSize(io::Printer* printer) { "size_t total_size = 0;\n" "\n"); + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "total_size += _extensions_.ByteSize();\n" + "\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"); + } + } + // Handle required fields (if any). We expect all of them to be // present, so emit one conditional that checks for that. If they are all // present then the fast path executes; otherwise the slow path executes. if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) { // The fast path works if all required fields are present. - vector<uint32> masks_for_has_bits = RequiredFieldsBitMask(descriptor_); + const std::vector<uint32> masks_for_has_bits = RequiredFieldsBitMask(); printer->Print((string("if (") + ConditionalToCheckBitmasks(masks_for_has_bits) + ") { // All required fields are present.\n").c_str()); printer->Indent(); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + // Oneof fields cannot be required, so optimized_order_ contains all of the + // fields that we need to potentially emit. + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; if (!field->is_required()) continue; PrintFieldComment(printer, field); field_generators_.get(field).GenerateByteSize(printer); @@ -3786,8 +3622,8 @@ GenerateByteSize(io::Printer* printer) { "}\n"); } else { // num_required_fields_ <= 1: no need to be tricky - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; if (!field->is_required()) continue; PrintFieldComment(printer, field); printer->Print("if (has_$name$()) {\n", @@ -3799,98 +3635,125 @@ GenerateByteSize(io::Printer* printer) { } } - // Handle optional fields (worry below about repeateds, oneofs, etc.). - // These are handled in chunks of 8. The first chunk is - // the non-requireds-non-repeateds-non-unions-non-extensions in - // descriptor_->field(0), descriptor_->field(1), ... descriptor_->field(7), - // and the second chunk is the same for - // descriptor_->field(8), descriptor_->field(9), ... descriptor_->field(15), - // etc. - hash_map<int, uint32> fields_mask_for_chunk; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - if (!field->is_required() && !field->is_repeated() && - !field->containing_oneof()) { - fields_mask_for_chunk[i / 8] |= static_cast<uint32>(1) << (i % 32); + int last_i = -1; + for (int i = 0; i < optimized_order_.size(); ) { + // Detect infinite loops. + GOOGLE_CHECK_NE(i, last_i); + last_i = i; + + // Skip required fields. + for (; i < optimized_order_.size() && + optimized_order_[i]->is_required(); i++) { } - } - int last_index = -1; - bool chunk_block_in_progress = false; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - if (!field->is_required() && !field->is_repeated() && - !field->containing_oneof()) { - // See above in GenerateClear for an explanation of this. - // TODO(kenton): Share code? Unclear how to do so without - // over-engineering. - if (i / 8 != last_index / 8 || last_index < 0) { - // End previous chunk, if there was one. - if (chunk_block_in_progress) { - printer->Outdent(); - printer->Print("}\n"); - chunk_block_in_progress = false; - } - // Start chunk. - uint32 mask = fields_mask_for_chunk[i / 8]; - int count = popcnt(mask); - GOOGLE_DCHECK_GE(count, 1); - if (count == 1) { - // No "if" here because the chunk is trivial. - } else { - if (HasFieldPresence(descriptor_->file())) { - printer->Print( - "if (_has_bits_[$index$ / 32] & $mask$u) {\n", - "index", SimpleItoa(i), - "mask", SimpleItoa(mask)); - printer->Indent(); - chunk_block_in_progress = true; - } - } + // Handle repeated fields. + for (; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + if (!field->is_repeated()) { + break; } - last_index = i; PrintFieldComment(printer, field); + const FieldGenerator& generator = field_generators_.get(field); + generator.GenerateByteSize(printer); + printer->Print("\n"); + } - bool have_enclosing_if = false; - if (HasFieldPresence(descriptor_->file())) { - printer->Print( - "if (has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); - have_enclosing_if = true; - } else { - // Without field presence: field is serialized only if it has a - // non-default value. - have_enclosing_if = EmitFieldNonDefaultCondition( - printer, "this->", field); + // Handle optional (non-repeated/oneof) fields. + // + // These are handled in chunks of 8. The first chunk is + // the non-requireds-non-repeateds-non-unions-non-extensions in + // descriptor_->field(0), descriptor_->field(1), ... descriptor_->field(7), + // and the second chunk is the same for + // descriptor_->field(8), descriptor_->field(9), ... + // descriptor_->field(15), + // etc. + int last_chunk = -1; + int last_chunk_start = -1; + int last_chunk_end = -1; + uint32 last_chunk_mask = 0; + for (; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + if (field->is_repeated() || field->is_required()) { + break; } - field_generators_.get(field).GenerateByteSize(printer); + // "index" defines where in the _has_bits_ the field appears. + // "i" is our loop counter within optimized_order_. + int index = HasFieldPresence(descriptor_->file()) ? + has_bit_indices_[field->index()] : 0; + int chunk = index / 8; + + if (last_chunk == -1) { + last_chunk = chunk; + last_chunk_start = i; + } else if (chunk != last_chunk) { + // Emit the fields for this chunk so far. + break; + } + + last_chunk_end = i; + last_chunk_mask |= static_cast<uint32>(1) << (index % 32); + } + + if (last_chunk != -1) { + GOOGLE_DCHECK_NE(-1, last_chunk_start); + GOOGLE_DCHECK_NE(-1, last_chunk_end); + GOOGLE_DCHECK_NE(0, last_chunk_mask); + + const int count = popcnt(last_chunk_mask); + const bool have_outer_if = HasFieldPresence(descriptor_->file()) && + (last_chunk_start != last_chunk_end); + + if (have_outer_if) { + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, count); + GOOGLE_DCHECK_GE(8, count); - if (have_enclosing_if) { - printer->Outdent(); printer->Print( - "}\n" - "\n"); + "if (_has_bits_[$index$ / 32] & $mask$u) {\n", + "index", SimpleItoa(last_chunk * 8), + "mask", SimpleItoa(last_chunk_mask)); + printer->Indent(); } - } - } - if (chunk_block_in_progress) { - printer->Outdent(); - printer->Print("}\n"); - } + // Go back and emit checks for each of the fields we processed. + for (int j = last_chunk_start; j <= last_chunk_end; j++) { + const FieldDescriptor* field = optimized_order_[j]; + const FieldGenerator& generator = field_generators_.get(field); - // Repeated fields don't use _has_bits_ so we count them in a separate - // pass. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + PrintFieldComment(printer, field); - if (field->is_repeated()) { - PrintFieldComment(printer, field); - field_generators_.get(field).GenerateByteSize(printer); - printer->Print("\n"); + bool have_enclosing_if = false; + if (HasFieldPresence(descriptor_->file())) { + printer->Print( + "if (has_$name$()) {\n", + "name", FieldName(field)); + printer->Indent(); + have_enclosing_if = true; + } else { + // Without field presence: field is serialized only if it has a + // non-default value. + have_enclosing_if = EmitFieldNonDefaultCondition( + printer, "this->", field); + } + + generator.GenerateByteSize(printer); + + if (have_enclosing_if) { + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + } + } + + if (have_outer_if) { + printer->Outdent(); + printer->Print("}\n"); + } } } @@ -3926,27 +3789,6 @@ GenerateByteSize(io::Printer* printer) { "}\n"); } - if (descriptor_->extension_range_count() > 0) { - printer->Print( - "total_size += _extensions_.ByteSize();\n" - "\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"); - } - } - // We update _cached_size_ even though this is a const method. In theory, // this is not thread-compatible, because concurrent writes have undefined // results. In practice, since any concurrent writes will be writing the @@ -3970,35 +3812,38 @@ GenerateIsInitialized(io::Printer* printer) { "classname", classname_); printer->Indent(); + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if (!_extensions_.IsInitialized()) {\n" + " return false;\n" + "}\n\n"); + } + if (HasFieldPresence(descriptor_->file())) { // Check that all required fields in this message are set. We can do this // most efficiently by checking 32 "has bits" at a time. - int has_bits_array_size = (descriptor_->field_count() + 31) / 32; - for (int i = 0; i < has_bits_array_size; i++) { - uint32 mask = 0; - for (int bit = 0; bit < 32; bit++) { - int index = i * 32 + bit; - if (index >= descriptor_->field_count()) break; - const FieldDescriptor* field = descriptor_->field(index); - - if (field->is_required()) { - mask |= 1 << bit; - } - } + const std::vector<uint32> masks = RequiredFieldsBitMask(); - if (mask != 0) { - printer->Print( - "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n", - "i", SimpleItoa(i), - "mask", StrCat(strings::Hex(mask, strings::ZERO_PAD_8))); + for (int i = 0; i < masks.size(); i++) { + uint32 mask = masks[i]; + if (mask == 0) { + continue; } + + // TODO(ckennelly): Consider doing something similar to ByteSizeLong(), + // where we check all of the required fields in a single branch (assuming + // that we aren't going to benefit from early termination). + printer->Print( + "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n", + "i", SimpleItoa(i), + "mask", StrCat(strings::Hex(mask, strings::ZERO_PAD_8))); } } - // Now check that all embedded messages are initialized. - printer->Print("\n"); - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); + // Now check that all non-oneof embedded messages are initialized. + for (int i = 0; i < optimized_order_.size(); i++) { + const FieldDescriptor* field = optimized_order_[i]; + // TODO(ckennelly): Push this down into a generator? if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && !ShouldIgnoreRequiredFieldCheck(field, options_) && HasRequiredFields(field->message_type(), options_)) { @@ -4008,7 +3853,56 @@ GenerateIsInitialized(io::Printer* printer) { " return false;\n", "name", FieldName(field)); } else { - if (field->options().weak() || !field->containing_oneof()) { + GOOGLE_CHECK(field->options().weak() || !field->containing_oneof()); + // For weak fields, use the data member (::google::protobuf::Message*) instead + // of the getter to avoid a link dependency on the weak message type + // which is only forward declared. + printer->Print( + "if (has_$name$()) {\n" + " if (!this->$name$_->IsInitialized()) return false;\n" + "}\n", + "name", FieldName(field)); + } + } + } + + // Go through the oneof fields, emitting a switch if any might have required + // fields. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + + bool has_required_fields = false; + for (int j = 0; j < oneof->field_count(); j++) { + const FieldDescriptor* field = oneof->field(j); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !ShouldIgnoreRequiredFieldCheck(field, options_) && + HasRequiredFields(field->message_type(), options_)) { + has_required_fields = true; + break; + } + } + + if (!has_required_fields) { + continue; + } + + printer->Print( + "switch ($oneofname$_case()) {\n", + "oneofname", oneof->name()); + printer->Indent(); + for (int j = 0; j < oneof->field_count(); j++) { + const FieldDescriptor* field = oneof->field(j); + printer->Print( + "case k$field_name$: {\n", + "field_name", UnderscoresToCamelCase(field->name(), true)); + printer->Indent(); + + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !ShouldIgnoreRequiredFieldCheck(field, options_) && + HasRequiredFields(field->message_type(), options_)) { + GOOGLE_CHECK(!(field->options().weak() || !field->containing_oneof())); + if (field->options().weak()) { // For weak fields, use the data member (::google::protobuf::Message*) instead // of the getter to avoid a link dependency on the weak message type // which is only forward declared. @@ -4025,15 +3919,22 @@ GenerateIsInitialized(io::Printer* printer) { "name", FieldName(field)); } } - } - } - if (descriptor_->extension_range_count() > 0) { + printer->Print( + "break;\n"); + printer->Outdent(); + printer->Print( + "}\n"); + } printer->Print( - "\n" - "if (!_extensions_.IsInitialized()) {\n" - " return false;\n" - "}\n"); + "case $cap_oneof_name$_NOT_SET: {\n" + " break;\n" + "}\n", + "cap_oneof_name", + ToUpper(oneof->name())); + printer->Outdent(); + printer->Print( + "}\n"); } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 3bdc0ed3..c5efff12 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -64,6 +64,12 @@ class MessageGenerator { MessageGenerator(const Descriptor* descriptor, const Options& options); ~MessageGenerator(); + // Appends the pre-order walk of the nested generators to list. + void Flatten(std::vector<MessageGenerator*>* list); + // Append the two types of nested generators to the corresponding vector. + void AddGenerators(std::vector<EnumGenerator*>* enum_generators, + std::vector<ExtensionGenerator*>* extension_generators); + // Header stuff. // Return names for forward declarations of this class and all its nested @@ -71,17 +77,7 @@ class MessageGenerator { // descriptor that was responsible for its inclusion in the map. This can be // used to associate the descriptor with the code generated for it. void FillMessageForwardDeclarations( - map<string, const Descriptor*>* class_names); - void FillEnumForwardDeclarations( - map<string, const EnumDescriptor*>* enum_names); - - // Generate definitions of all nested enums (must come before class - // definitions because those classes use the enums definitions). - void GenerateEnumDefinitions(io::Printer* printer); - - // Generate specializations of GetEnumDescriptor<MyEnum>(). - // Precondition: in ::google::protobuf namespace. - void GenerateGetEnumDescriptorSpecializations(io::Printer* printer); + std::map<string, const Descriptor*>* class_names); // Generate definitions for this class and all its nested types. void GenerateClassDefinition(io::Printer* printer); @@ -99,10 +95,6 @@ class MessageGenerator { // will be initialized by the methods below. void GenerateDescriptorDeclarations(io::Printer* printer); - // Generate code that initializes the global variable storing the message's - // descriptor. - void GenerateDescriptorInitializer(io::Printer* printer, int index); - // Generate code that calls MessageFactory::InternalRegisterGeneratedMessage() // for all types. void GenerateTypeRegistrations(io::Printer* printer); @@ -130,8 +122,10 @@ class MessageGenerator { void GenerateDependentFieldAccessorDefinitions(io::Printer* printer); void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline); - // Generate the field offsets array. - void GenerateOffsets(io::Printer* printer); + // Generate the field offsets array. Returns the a pair of the total numer + // 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); // Generate constructors and destructor. void GenerateStructors(io::Printer* printer); @@ -168,7 +162,7 @@ class MessageGenerator { // Generate a switch statement to serialize 2+ fields from the same oneof. // Or, if fields.size() == 1, just call GenerateSerializeOneField(). void GenerateSerializeOneofFields( - io::Printer* printer, const vector<const FieldDescriptor*>& fields, + io::Printer* printer, const std::vector<const FieldDescriptor*>& fields, bool to_array); void GenerateSerializeOneExtensionRange( io::Printer* printer, const Descriptor::ExtensionRange* range, @@ -177,19 +171,26 @@ class MessageGenerator { // Generates has_foo() functions and variables for singular field has-bits. void GenerateSingularFieldHasBits(const FieldDescriptor* field, - map<string, string> vars, + std::map<string, string> vars, io::Printer* printer); // Generates has_foo() functions and variables for oneof field has-bits. void GenerateOneofHasBits(io::Printer* printer, bool is_inline); // Generates has_foo_bar() functions for oneof members. void GenerateOneofMemberHasBits(const FieldDescriptor* field, - const map<string, string>& vars, + const std::map<string, string>& vars, io::Printer* printer); // Generates the clear_foo() method for a field. void GenerateFieldClear(const FieldDescriptor* field, - const map<string, string>& vars, + const std::map<string, string>& vars, io::Printer* printer); + void GenerateConstructorBody(io::Printer* printer, + std::vector<bool> already_processed, + bool copy_constructor) const; + + size_t HasBitsSize() const; + std::vector<uint32> RequiredFieldsBitMask() const; + const Descriptor* descriptor_; string classname_; Options options_; @@ -198,15 +199,17 @@ class MessageGenerator { // This is reused to initialize the fields in-order for cache efficiency. // // optimized_order_ excludes oneof fields. - vector<const FieldDescriptor *> optimized_order_; - vector< vector<string> > runs_of_fields_; // that might be trivially cleared + std::vector<const FieldDescriptor *> optimized_order_; + std::vector<int> has_bit_indices_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > nested_generators_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_; google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_; int num_required_fields_; - bool uses_string_; bool use_dependent_base_; + int index_in_metadata_; + + friend class FileGenerator; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index ca7bae02..91449657 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -45,7 +45,7 @@ namespace cpp { namespace { void SetMessageVariables(const FieldDescriptor* descriptor, - map<string, string>* variables, + std::map<string, string>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = FieldMessageTypeName(descriptor); @@ -218,7 +218,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { return; } - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); // For the CRTP base class, all mutation methods are dependent, and so // they must be in the header. variables["dependent_classname"] = @@ -349,7 +349,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, // for dependent fields we cannot access its internal_default_instance, // because the type is incomplete. // TODO(gerbens) deprecate dependent base class. - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$const $type$& $classname$::$name$() const {\n" @@ -360,7 +360,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, return; } - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$const $type$& $classname$::$name$() const {\n" @@ -469,7 +469,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; if (!HasFieldPresence(descriptor_->file())) { // If we don't have has-bits, message presence is indicated only by ptr != @@ -486,6 +486,26 @@ GenerateClearingCode(io::Printer* printer) const { } void MessageFieldGenerator:: +GenerateMessageClearingCode(io::Printer* printer) const { + std::map<string, string> variables(variables_); + variables["type"] = FieldMessageTypeName(descriptor_); + + if (!HasFieldPresence(descriptor_->file())) { + // If we don't have has-bits, message presence is indicated only by ptr != + // NULL. Thus on clear, we need to delete the object. + printer->Print(variables_, + "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) {\n" + " delete $name$_;\n" + "}\n" + "$name$_ = NULL;\n"); + } else { + printer->Print(variables_, + "GOOGLE_DCHECK($name$_ != NULL);\n" + "$name$_->$type$::Clear();\n"); + } +} + +void MessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, "mutable_$name$()->$type$::MergeFrom(from.$name$());\n"); @@ -497,11 +517,51 @@ GenerateSwappingCode(io::Printer* printer) const { } 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"); +} + +void MessageFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { printer->Print(variables_, "$name$_ = NULL;\n"); } void MessageFieldGenerator:: +GenerateCopyConstructorCode(io::Printer* printer) const { + // For non-Arena enabled messages, everything always goes on the heap. + // + // For Arena enabled messages, the logic is a bit more convoluted. + // + // In the copy constructor, we call InternalMetadataWithArena::MergeFrom, + // which does *not* copy the Arena pointer. In the generated MergeFrom + // (see MessageFieldGenerator::GenerateMergingCode), we: + // -> copy the has bits (but this is done in bulk by a memcpy in the copy + // constructor) + // -> check whether the destination field pointer is NULL (it will be, since + // we're initializing it and would have called SharedCtor) and if so: + // -> call _slow_mutable_$name$(), which calls either + // ::google::protobuf::Arena::CreateMessage<>(GetArenaNoVirtual()), or + // ::google::protobuf::Arena::Create<>(GetArenaNoVirtual()) + // + // At this point, GetArenaNoVirtual returns NULL since the Arena pointer + // wasn't copied, so both of these methods allocate the submessage on the + // heap. + + printer->Print(variables_, + "if (from.has_$name$()) {\n" + " $name$_ = new $type$(*from.$name$_);\n" + "} else {\n" + " $name$_ = NULL;\n" + "}\n"); +} + +void MessageFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { printer->Print(variables_, @@ -581,7 +641,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { if (!dependent_base_) { return; } - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = "inline "; variables["dependent_classname"] = DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; @@ -601,7 +661,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, if (dependent_base_) { return; } - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; variables["dependent_classname"] = variables["classname"]; variables["this_message"] = ""; @@ -615,16 +675,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MessageOneofFieldGenerator:: GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["field_member"] = variables["oneof_prefix"] + variables["name"] + "_"; //printer->Print(variables, } -void MessageOneofFieldGenerator:: -InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables, - io::Printer* printer) const { +void MessageOneofFieldGenerator::InternalGenerateInlineAccessorDefinitions( + const std::map<string, string>& variables, io::Printer* printer) const { printer->Print(variables, "$tmpl$" "$inline$ " @@ -794,7 +853,7 @@ InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables, void MessageOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; if (SupportsArenas(descriptor_)) { printer->Print(variables, @@ -808,11 +867,22 @@ GenerateClearingCode(io::Printer* printer) const { } void MessageOneofFieldGenerator:: +GenerateMessageClearingCode(io::Printer* printer) const { + GenerateClearingCode(printer); +} + +void MessageOneofFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { // Don't print any swapping code. Swapping the union will swap this field. } void MessageOneofFieldGenerator:: +GenerateDestructorCode(io::Printer* printer) const { + // We inherit from MessageFieldGenerator, so we need to override the default + // behavior. +} + +void MessageOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { // Don't print any constructor code. The field is in a union. We allocate // space only when this field is used. @@ -884,7 +954,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { if (!dependent_field_) { return; } - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); // For the CRTP base class, all mutation methods are dependent, and so // they must be in the header. variables["dependent_classname"] = @@ -915,7 +985,6 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { " return $this_message$$name$_.Add();\n" "}\n"); - if (dependent_getter_) { printer->Print(variables, "template <class T>\n" @@ -939,7 +1008,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; if (!dependent_getter_) { @@ -989,7 +1058,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void RepeatedMessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; printer->Print(variables, "$this_message$$name$_.Clear();\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index d8d9279c..9ca91153 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -59,23 +59,26 @@ class MessageFieldGenerator : public FieldGenerator { bool is_inline) const; void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; + void GenerateMessageClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; + void GenerateDestructorCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; protected: - void GenerateArenaManipulationCode(const map<string, string>& variables, + void GenerateArenaManipulationCode(const std::map<string, string>& variables, io::Printer* printer) const; virtual void GenerateGetterDeclaration(io::Printer* printer) const; const FieldDescriptor* descriptor_; const bool dependent_field_; - map<string, string> variables_; + std::map<string, string> variables_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); @@ -94,7 +97,12 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { bool is_inline) const; void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; + + // MessageFieldGenerator, from which we inherit, overrides this so we need to + // override it as well. + void GenerateMessageClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; + void GenerateDestructorCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; protected: @@ -102,7 +110,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { private: void InternalGenerateInlineAccessorDefinitions( - const map<string, string>& variables, io::Printer* printer) const; + const std::map<string, string>& variables, io::Printer* printer) const; const bool dependent_base_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); @@ -125,6 +133,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const {} void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; @@ -137,7 +146,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { const FieldDescriptor* descriptor_; const bool dependent_field_; const bool dependent_getter_; - map<string, string> variables_; + std::map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 54b3d24a..889271e9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -80,7 +80,7 @@ int FixedSize(FieldDescriptor::Type type) { } void SetPrimitiveVariables(const FieldDescriptor* descriptor, - map<string, string>* variables, + std::map<string, string>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type()); @@ -122,7 +122,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$$type$ $classname$::$name$() const {\n" @@ -157,6 +157,11 @@ GenerateConstructorCode(io::Printer* printer) const { } void PrimitiveFieldGenerator:: +GenerateCopyConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = from.$name$_;\n"); +} + +void PrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "$set_hasbit$\n" @@ -206,7 +211,7 @@ PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() {} void PrimitiveOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$$type$ $classname$::$name$() const {\n" @@ -240,7 +245,7 @@ void PrimitiveOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { printer->Print( variables_, - " $classname$_default_oneof_instance_->$name$_ = $default$;\n"); + " $classname$_default_oneof_instance_.$name$_ = $default$;\n"); } void PrimitiveOneofFieldGenerator:: @@ -297,7 +302,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$$type$ $classname$::$name$(int index) const {\n" @@ -336,11 +341,6 @@ GenerateMergingCode(io::Printer* printer) const { } void RepeatedPrimitiveFieldGenerator:: -GenerateUnsafeMergingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.UnsafeMergeFrom(from.$name$_);\n"); -} - -void RepeatedPrimitiveFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } @@ -351,6 +351,11 @@ GenerateConstructorCode(io::Printer* printer) const { } void RepeatedPrimitiveFieldGenerator:: +GenerateCopyConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.CopyFrom(from.$name$_);\n"); +} + +void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index 23cc697e..44c9ff3e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -59,6 +59,7 @@ class PrimitiveFieldGenerator : public FieldGenerator { void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; @@ -66,7 +67,7 @@ class PrimitiveFieldGenerator : public FieldGenerator { protected: const FieldDescriptor* descriptor_; - map<string, string> variables_; + std::map<string, string> variables_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); @@ -103,9 +104,9 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; - virtual void GenerateUnsafeMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; @@ -114,7 +115,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { private: const FieldDescriptor* descriptor_; - map<string, string> variables_; + std::map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc index 6030f7ce..d6b1ddc5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.cc +++ b/src/google/protobuf/compiler/cpp/cpp_service.cc @@ -143,7 +143,7 @@ void ServiceGenerator::GenerateMethodSignatures( VirtualOrNon virtual_or_non, io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); - map<string, string> sub_vars; + std::map<string, string> sub_vars; sub_vars["name"] = method->name(); sub_vars["input_type"] = ClassName(method->input_type(), true); sub_vars["output_type"] = ClassName(method->output_type(), true); @@ -161,7 +161,7 @@ void ServiceGenerator::GenerateMethodSignatures( void ServiceGenerator::GenerateDescriptorInitializer( io::Printer* printer, int index) { - map<string, string> vars; + std::map<string, string> vars; vars["classname"] = descriptor_->name(); vars["index"] = SimpleItoa(index); @@ -172,19 +172,20 @@ void ServiceGenerator::GenerateDescriptorInitializer( // =================================================================== void ServiceGenerator::GenerateImplementation(io::Printer* printer) { - printer->Print(vars_, - "$classname$::~$classname$() {}\n" - "\n" - "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n" - " protobuf_AssignDescriptorsOnce();\n" - " return $classname$_descriptor_;\n" - "}\n" - "\n" - "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n" - " protobuf_AssignDescriptorsOnce();\n" - " return $classname$_descriptor_;\n" - "}\n" - "\n"); + vars_["index"] = SimpleItoa(index_in_metadata_); + printer->Print( + vars_, + "$classname$::~$classname$() {}\n" + "\n" + "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" + " return file_level_service_descriptors[$index$];\n" + "}\n" + "\n" + "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n" + " return descriptor();\n" + "}\n" + "\n"); // Generate methods of the interface. GenerateNotImplementedMethods(printer); @@ -212,7 +213,7 @@ void ServiceGenerator::GenerateImplementation(io::Printer* printer) { void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); - map<string, string> sub_vars; + std::map<string, string> sub_vars; sub_vars["classname"] = descriptor_->name(); sub_vars["name"] = method->name(); sub_vars["index"] = SimpleItoa(i); @@ -232,18 +233,20 @@ void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { } void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { - printer->Print(vars_, - "void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" - " ::google::protobuf::RpcController* controller,\n" - " const ::google::protobuf::Message* request,\n" - " ::google::protobuf::Message* response,\n" - " ::google::protobuf::Closure* done) {\n" - " GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n" - " switch(method->index()) {\n"); + printer->Print( + vars_, + "void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" + " ::google::protobuf::RpcController* controller,\n" + " const ::google::protobuf::Message* request,\n" + " ::google::protobuf::Message* response,\n" + " ::google::protobuf::Closure* done) {\n" + " GOOGLE_DCHECK_EQ(method->service(), " + "file_level_service_descriptors[$index$]);\n" + " switch(method->index()) {\n"); for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); - map<string, string> sub_vars; + std::map<string, string> sub_vars; sub_vars["name"] = method->name(); sub_vars["index"] = SimpleItoa(i); sub_vars["input_type"] = ClassName(method->input_type(), true); @@ -289,7 +292,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, const Descriptor* type = (which == REQUEST) ? method->input_type() : method->output_type(); - map<string, string> sub_vars; + std::map<string, string> sub_vars; sub_vars["index"] = SimpleItoa(i); sub_vars["type"] = ClassName(type, true); @@ -312,7 +315,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); - map<string, string> sub_vars; + std::map<string, string> sub_vars; sub_vars["classname"] = descriptor_->name(); sub_vars["name"] = method->name(); sub_vars["index"] = SimpleItoa(i); diff --git a/src/google/protobuf/compiler/cpp/cpp_service.h b/src/google/protobuf/compiler/cpp/cpp_service.h index ede2fd80..33c02547 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.h +++ b/src/google/protobuf/compiler/cpp/cpp_service.h @@ -105,8 +105,11 @@ class ServiceGenerator { void GenerateStubMethods(io::Printer* printer); const ServiceDescriptor* descriptor_; - map<string, string> vars_; + std::map<string, string> vars_; + int index_in_metadata_; + + friend class FileGenerator; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index aee3d1ea..a9505e3d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -46,20 +46,19 @@ namespace cpp { namespace { void SetStringVariables(const FieldDescriptor* descriptor, - map<string, string>* variables, + std::map<string, string>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["default"] = DefaultValue(descriptor); (*variables)["default_length"] = SimpleItoa(descriptor->default_value_string().length()); - string default_variable_string = + string default_variable_string = "_default_" + FieldName(descriptor) + "_"; + (*variables)["default_variable_name"] = default_variable_string; + (*variables)["default_variable"] = descriptor->default_value_string().empty() ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()" - : "_default_" + FieldName(descriptor) + "_"; - (*variables)["default_variable"] = default_variable_string; - (*variables)["default_value_init"] = - descriptor->default_value_string().empty() - ? "" : "*" + default_variable_string; + : "&" + (*variables)["classname"] + "::" + default_variable_string + + ".get()"; (*variables)["pointer_type"] = descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; // NOTE: Escaped here to unblock proto1->proto2 migration. @@ -104,7 +103,9 @@ GeneratePrivateMembers(io::Printer* printer) const { void StringFieldGenerator:: GenerateStaticMembers(io::Printer* printer) const { if (!descriptor_->default_value_string().empty()) { - printer->Print(variables_, "static ::std::string* $default_variable$;\n"); + printer->Print(variables_, + "static ::google::protobuf::internal::ExplicitlyConstructed< ::std::string>" + " $default_variable_name$;\n"); } } @@ -165,117 +166,121 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void StringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; if (SupportsArenas(descriptor_)) { - printer->Print(variables, - "$inline$const ::std::string& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.Get($default_variable$);\n" - "}\n" - "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" - " $set_hasbit$\n" - " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "$inline$void $classname$::set_$name$(const char* value) {\n" - " $set_hasbit$\n" - " $name$_.Set($default_variable$, $string_piece$(value),\n" - " GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" - "$inline$" - "void $classname$::set_$name$(const $pointer_type$* value,\n" - " size_t size) {\n" - " $set_hasbit$\n" - " $name$_.Set($default_variable$, $string_piece$(\n" - " reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" - "}\n" - "$inline$::std::string* $classname$::mutable_$name$() {\n" - " $set_hasbit$\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" - "}\n" - "$inline$::std::string* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" - " $clear_hasbit$\n" - " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n" - "}\n" - "$inline$::std::string* $classname$::unsafe_arena_release_$name$() {\n" - " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" - " $clear_hasbit$\n" - " return $name$_.UnsafeArenaRelease($default_variable$,\n" - " GetArenaNoVirtual());\n" - "}\n" - "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" - " if ($name$ != NULL) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n" - " $name$_.SetAllocated($default_variable$, $name$,\n" - " GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n" - "$inline$void $classname$::unsafe_arena_set_allocated_$name$(\n" - " ::std::string* $name$) {\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" - " if ($name$ != NULL) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n" - " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" - " $name$, GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" - "$full_name$)\n" - "}\n"); + printer->Print( + variables, + "$inline$const ::std::string& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.Get();\n" + "}\n" + "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" + " $set_hasbit$\n" + " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "$inline$void $classname$::set_$name$(const char* value) {\n" + " $set_hasbit$\n" + " $name$_.Set($default_variable$, $string_piece$(value),\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n" + "$inline$" + "void $classname$::set_$name$(const $pointer_type$* value,\n" + " size_t size) {\n" + " $set_hasbit$\n" + " $name$_.Set($default_variable$, $string_piece$(\n" + " reinterpret_cast<const char*>(value), size), " + "GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "$inline$::std::string* $classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" + "}\n" + "$inline$::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" + " $clear_hasbit$\n" + " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n" + "}\n" + "$inline$::std::string* $classname$::unsafe_arena_release_$name$() {\n" + " // " + "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" + " $clear_hasbit$\n" + " return $name$_.UnsafeArenaRelease($default_variable$,\n" + " GetArenaNoVirtual());\n" + "}\n" + "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if ($name$ != NULL) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " $name$_.SetAllocated($default_variable$, $name$,\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n" + "$inline$void $classname$::unsafe_arena_set_allocated_$name$(\n" + " ::std::string* $name$) {\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" + " if ($name$ != NULL) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" + " $name$, GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" + "}\n"); } else { // No-arena case. - printer->Print(variables, - "$inline$const ::std::string& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.GetNoArena($default_variable$);\n" - "}\n" - "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" - " $set_hasbit$\n" - " $name$_.SetNoArena($default_variable$, value);\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "$inline$void $classname$::set_$name$(const char* value) {\n" - " $set_hasbit$\n" - " $name$_.SetNoArena($default_variable$, $string_piece$(value));\n" - " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" - "$inline$" - "void $classname$::set_$name$(const $pointer_type$* value, " - "size_t size) {\n" - " $set_hasbit$\n" - " $name$_.SetNoArena($default_variable$,\n" - " $string_piece$(reinterpret_cast<const char*>(value), size));\n" - " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" - "}\n" - "$inline$::std::string* $classname$::mutable_$name$() {\n" - " $set_hasbit$\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_.MutableNoArena($default_variable$);\n" - "}\n" - "$inline$::std::string* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" - " $clear_hasbit$\n" - " return $name$_.ReleaseNoArena($default_variable$);\n" - "}\n" - "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" - " if ($name$ != NULL) {\n" - " $set_hasbit$\n" - " } else {\n" - " $clear_hasbit$\n" - " }\n" - " $name$_.SetAllocatedNoArena($default_variable$, $name$);\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n"); + printer->Print( + variables, + "$inline$const ::std::string& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.GetNoArena();\n" + "}\n" + "$inline$void $classname$::set_$name$(const ::std::string& value) {\n" + " $set_hasbit$\n" + " $name$_.SetNoArena($default_variable$, value);\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "$inline$void $classname$::set_$name$(const char* value) {\n" + " $set_hasbit$\n" + " $name$_.SetNoArena($default_variable$, $string_piece$(value));\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n" + "$inline$" + "void $classname$::set_$name$(const $pointer_type$* value, " + "size_t size) {\n" + " $set_hasbit$\n" + " $name$_.SetNoArena($default_variable$,\n" + " $string_piece$(reinterpret_cast<const char*>(value), size));\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "$inline$::std::string* $classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.MutableNoArena($default_variable$);\n" + "}\n" + "$inline$::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" + " $clear_hasbit$\n" + " return $name$_.ReleaseNoArena($default_variable$);\n" + "}\n" + "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if ($name$ != NULL) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " $name$_.SetAllocatedNoArena($default_variable$, $name$);\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); } } @@ -284,7 +289,8 @@ GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { if (!descriptor_->default_value_string().empty()) { // Initialized in GenerateDefaultInstanceAllocator. printer->Print(variables_, - "::std::string* $classname$::$default_variable$ = NULL;\n"); + "::google::protobuf::internal::ExplicitlyConstructed< ::std::string> " + "$classname$::$default_variable_name$;\n"); } } @@ -314,6 +320,52 @@ GenerateClearingCode(io::Printer* printer) const { } void StringFieldGenerator:: +GenerateMessageClearingCode(io::Printer* printer) const { + // Two-dimension specialization here: supporting arenas, field presence, or + // not, and default value is the empty string or not. Complexity here ensures + // the minimal number of branches / amount of extraneous code at runtime + // (given that the below methods are inlined one-liners)! + + // If we have field presence, then the Clear() method of the protocol buffer + // will have checked that this field is set. If so, we can avoid redundant + // checks against default_variable. + const bool must_be_present = HasFieldPresence(descriptor_->file()); + + if (must_be_present) { + printer->Print(variables_, + "GOOGLE_DCHECK(!$name$_.IsDefault($default_variable$));\n"); + } + + if (SupportsArenas(descriptor_)) { + if (descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n"); + } + } else if (must_be_present) { + // When Arenas are disabled and field presence has been checked, we can + // safely treat the ArenaStringPtr as a string*. + if (descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "(*$name$_.UnsafeRawStringPointer())->clear();\n"); + } else { + printer->Print(variables_, + "(*$name$_.UnsafeRawStringPointer())->assign(*$default_variable$);\n"); + } + } else { + if (descriptor_->default_value_string().empty()) { + printer->Print(variables_, + "$name$_.ClearToEmptyNoArena($default_variable$);\n"); + } else { + printer->Print(variables_, + "$name$_.ClearToDefaultNoArena($default_variable$);\n"); + } + } +} + +void StringFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) { // TODO(gpike): improve this @@ -337,6 +389,34 @@ GenerateConstructorCode(io::Printer* printer) const { } void StringFieldGenerator:: +GenerateCopyConstructorCode(io::Printer* printer) const { + GenerateConstructorCode(printer); + + if (HasFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if (from.has_$name$()) {\n"); + } else { + printer->Print(variables_, + "if (from.$name$().size() > 0) {\n"); + } + + printer->Indent(); + + if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) { + // TODO(gpike): improve this + printer->Print(variables_, + "$name$_.Set($default_variable$, from.$name$(),\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print(variables_, + "$name$_.AssignWithDefault($default_variable$, from.$name$_);\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void StringFieldGenerator:: GenerateDestructorCode(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { // The variable |arena| is defined by the enclosing code. @@ -353,8 +433,9 @@ void StringFieldGenerator:: GenerateDefaultInstanceAllocator(io::Printer* printer) const { if (!descriptor_->default_value_string().empty()) { printer->Print(variables_, - "$classname$::$default_variable$ =\n" - " new ::std::string($default$, $default_length$);\n"); + "$classname$::$default_variable_name$.DefaultConstruct();\n" + "*$classname$::$default_variable_name$.get_mutable() = " + "::std::string($default$, $default_length$);\n"); } } @@ -362,7 +443,7 @@ void StringFieldGenerator:: GenerateShutdownCode(io::Printer* printer) const { if (!descriptor_->default_value_string().empty()) { printer->Print(variables_, - "delete $classname$::$default_variable$;\n"); + "$classname$::$default_variable_name$.Shutdown();\n"); } } @@ -427,185 +508,190 @@ StringOneofFieldGenerator::~StringOneofFieldGenerator() {} void StringOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; if (SupportsArenas(descriptor_)) { - printer->Print(variables, - "$inline$const ::std::string& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " if (has_$name$()) {\n" - " return $oneof_prefix$$name$_.Get($default_variable$);\n" - " }\n" - " return *$default_variable$;\n" - "}\n" - "$inline$void $classname$::set_$name$(const ::std::string& value) {\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($default_variable$, value,\n" - " GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "$inline$void $classname$::set_$name$(const char* value) {\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($default_variable$,\n" - " $string_piece$(value), GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" - "$inline$" - "void $classname$::set_$name$(const $pointer_type$* value,\n" - " size_t size) {\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($default_variable$, $string_piece$(\n" - " reinterpret_cast<const char*>(value), size),\n" - " GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" - "}\n" - "$inline$::std::string* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" - " }\n" - " return $oneof_prefix$$name$_.Mutable($default_variable$,\n" - " GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - "}\n" - "$inline$::std::string* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " return $oneof_prefix$$name$_.Release($default_variable$,\n" - " GetArenaNoVirtual());\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n" - "$inline$::std::string* $classname$::unsafe_arena_release_$name$() {\n" - " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " return $oneof_prefix$$name$_.UnsafeArenaRelease(\n" - " $default_variable$, GetArenaNoVirtual());\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n" - "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" - " if (!has_$name$()) {\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" - " }\n" - " clear_$oneof_name$();\n" - " if ($name$ != NULL) {\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_.SetAllocated($default_variable$, $name$,\n" - " GetArenaNoVirtual());\n" - " }\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n" - "$inline$void $classname$::unsafe_arena_set_allocated_$name$(" - "::std::string* $name$) {\n" - " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" - " if (!has_$name$()) {\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" - " }\n" - " clear_$oneof_name$();\n" - " if ($name$) {\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, " - "$name$, GetArenaNoVirtual());\n" - " }\n" - " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" - "$full_name$)\n" - "}\n"); + printer->Print( + variables, + "$inline$const ::std::string& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " if (has_$name$()) {\n" + " return $oneof_prefix$$name$_.Get();\n" + " }\n" + " return *$default_variable$;\n" + "}\n" + "$inline$void $classname$::set_$name$(const ::std::string& value) {\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($default_variable$, value,\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "$inline$void $classname$::set_$name$(const char* value) {\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($default_variable$,\n" + " $string_piece$(value), GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n" + "$inline$" + "void $classname$::set_$name$(const $pointer_type$* value,\n" + " size_t size) {\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($default_variable$, $string_piece$(\n" + " reinterpret_cast<const char*>(value), size),\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "$inline$::std::string* $classname$::mutable_$name$() {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " return $oneof_prefix$$name$_.Mutable($default_variable$,\n" + " GetArenaNoVirtual());\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + "}\n" + "$inline$::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " return $oneof_prefix$$name$_.Release($default_variable$,\n" + " GetArenaNoVirtual());\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "$inline$::std::string* $classname$::unsafe_arena_release_$name$() {\n" + " // " + "@@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " return $oneof_prefix$$name$_.UnsafeArenaRelease(\n" + " $default_variable$, GetArenaNoVirtual());\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if (!has_$name$()) {\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " clear_$oneof_name$();\n" + " if ($name$ != NULL) {\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.SetAllocated($default_variable$, $name$,\n" + " GetArenaNoVirtual());\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n" + "$inline$void $classname$::unsafe_arena_set_allocated_$name$(" + "::std::string* $name$) {\n" + " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" + " if (!has_$name$()) {\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " clear_$oneof_name$();\n" + " if ($name$) {\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, " + "$name$, GetArenaNoVirtual());\n" + " }\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" + "}\n"); } else { // No-arena case. - printer->Print(variables, - "$inline$const ::std::string& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " if (has_$name$()) {\n" - " return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n" - " }\n" - " return *$default_variable$;\n" - "}\n" - "$inline$void $classname$::set_$name$(const ::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$_.SetNoArena($default_variable$, value);\n" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" - "$inline$void $classname$::set_$name$(const char* value) {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" - " }\n" - " $oneof_prefix$$name$_.SetNoArena($default_variable$,\n" - " $string_piece$(value));\n" - " // @@protoc_insertion_point(field_set_char:$full_name$)\n" - "}\n" - "$inline$" - "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" - " }\n" - " $oneof_prefix$$name$_.SetNoArena($default_variable$, $string_piece$(\n" - " reinterpret_cast<const char*>(value), size));\n" - " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" - "}\n" - "$inline$::std::string* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" - " }\n" - " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n" - "}\n" - "$inline$::std::string* $classname$::$release_name$() {\n" - " // @@protoc_insertion_point(field_release:$full_name$)\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n" - "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" - " if (!has_$name$()) {\n" - " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" - " }\n" - " clear_$oneof_name$();\n" - " if ($name$ != NULL) {\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_.SetAllocatedNoArena($default_variable$,\n" - " $name$);\n" - " }\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" - "}\n"); + printer->Print( + variables, + "$inline$const ::std::string& $classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " if (has_$name$()) {\n" + " return $oneof_prefix$$name$_.GetNoArena();\n" + " }\n" + " return *$default_variable$;\n" + "}\n" + "$inline$void $classname$::set_$name$(const ::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$_.SetNoArena($default_variable$, value);\n" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "$inline$void $classname$::set_$name$(const char* value) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.SetNoArena($default_variable$,\n" + " $string_piece$(value));\n" + " // @@protoc_insertion_point(field_set_char:$full_name$)\n" + "}\n" + "$inline$" + "void $classname$::set_$name$(const $pointer_type$* value, size_t " + "size) {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " $oneof_prefix$$name$_.SetNoArena($default_variable$, " + "$string_piece$(\n" + " reinterpret_cast<const char*>(value), size));\n" + " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" + "}\n" + "$inline$::std::string* $classname$::mutable_$name$() {\n" + " if (!has_$name$()) {\n" + " clear_$oneof_name$();\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n" + "}\n" + "$inline$::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "$inline$void $classname$::set_allocated_$name$(::std::string* $name$) {\n" + " if (!has_$name$()) {\n" + " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n" + " }\n" + " clear_$oneof_name$();\n" + " if ($name$ != NULL) {\n" + " set_has_$name$();\n" + " $oneof_prefix$$name$_.SetAllocatedNoArena($default_variable$,\n" + " $name$);\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); } } void StringOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); if (dependent_field_) { variables["this_message"] = DependentBaseDownCast(); // This clearing code may be in the dependent base class. If the default @@ -614,8 +700,9 @@ GenerateClearingCode(io::Printer* printer) const { // default value's global singleton instance. See SetStringVariables() for // possible values of default_variable. if (!descriptor_->default_value_string().empty()) { - variables["default_variable"] = - DependentBaseDownCast() + variables["default_variable"]; + variables["default_variable"] = "&" + DependentBaseDownCast() + + variables["default_variable_name"] + + ".get()"; } } else { variables["this_message"] = ""; @@ -632,15 +719,21 @@ GenerateClearingCode(io::Printer* printer) const { } void StringOneofFieldGenerator:: +GenerateMessageClearingCode(io::Printer* printer) const { + return GenerateClearingCode(printer); +} + +void StringOneofFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { // Don't print any swapping code. Swapping the union will swap this field. } void StringOneofFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - printer->Print(variables_, - " $classname$_default_oneof_instance_->$name$_.UnsafeSetDefault(" - "$default_variable$);\n"); + printer->Print( + variables_, + "$classname$_default_oneof_instance_.$name$_.UnsafeSetDefault(\n" + " $default_variable$);\n"); } void StringOneofFieldGenerator:: @@ -733,7 +826,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { - map<string, string> variables(variables_); + std::map<string, string> variables(variables_); variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, "$inline$const ::std::string& $classname$::$name$(int index) const {\n" @@ -800,11 +893,6 @@ GenerateMergingCode(io::Printer* printer) const { } void RepeatedStringFieldGenerator:: -GenerateUnsafeMergingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.UnsafeMergeFrom(from.$name$_);\n"); -} - -void RepeatedStringFieldGenerator:: GenerateSwappingCode(io::Printer* printer) const { printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n"); } @@ -815,6 +903,11 @@ GenerateConstructorCode(io::Printer* printer) const { } void RepeatedStringFieldGenerator:: +GenerateCopyConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.CopyFrom(from.$name$_);"); +} + +void RepeatedStringFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 1dea7663..af263c1a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -58,9 +58,11 @@ class StringFieldGenerator : public FieldGenerator { bool is_inline) const; void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; + void GenerateMessageClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateDestructorCode(io::Printer* printer) const; void GenerateDefaultInstanceAllocator(io::Printer* printer) const; void GenerateShutdownCode(io::Printer* printer) const; @@ -71,7 +73,7 @@ class StringFieldGenerator : public FieldGenerator { protected: const FieldDescriptor* descriptor_; - map<string, string> variables_; + std::map<string, string> variables_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); @@ -87,6 +89,10 @@ class StringOneofFieldGenerator : public StringFieldGenerator { void GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; + + // StringFieldGenerator, from which we inherit, overrides this so we need to + // override it as well. + void GenerateMessageClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateDestructorCode(io::Printer* printer) const; @@ -110,9 +116,9 @@ class RepeatedStringFieldGenerator : public FieldGenerator { bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; - void GenerateUnsafeMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + void GenerateCopyConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; @@ -120,7 +126,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator { private: const FieldDescriptor* descriptor_; - map<string, string> variables_; + std::map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index d214ef0a..8eaddb87 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -67,6 +67,7 @@ #include <google/protobuf/compiler/importer.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/arena.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/dynamic_message.h> @@ -199,14 +200,14 @@ TEST(GeneratedMessageTest, FloatingPointDefaults) { EXPECT_EQ(-1.5f, extreme_default.negative_float()); EXPECT_EQ(2.0e8f, extreme_default.large_float()); EXPECT_EQ(-8e-28f, extreme_default.small_negative_float()); - EXPECT_EQ(numeric_limits<double>::infinity(), + EXPECT_EQ(std::numeric_limits<double>::infinity(), extreme_default.inf_double()); - EXPECT_EQ(-numeric_limits<double>::infinity(), + EXPECT_EQ(-std::numeric_limits<double>::infinity(), extreme_default.neg_inf_double()); EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double()); - EXPECT_EQ(numeric_limits<float>::infinity(), + EXPECT_EQ(std::numeric_limits<float>::infinity(), extreme_default.inf_float()); - EXPECT_EQ(-numeric_limits<float>::infinity(), + EXPECT_EQ(-std::numeric_limits<float>::infinity(), extreme_default.neg_inf_float()); EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float()); } @@ -518,6 +519,26 @@ TEST(GeneratedMessageTest, CopyConstructor) { TestUtil::ExpectAllFieldsSet(message2); } +TEST(GeneratedMessageTest, CopyConstructorWithArenas) { + Arena arena; + unittest::TestAllTypes* message1 = + Arena::CreateMessage<unittest::TestAllTypes>(&arena); + TestUtil::SetAllFields(message1); + + unittest::TestAllTypes message2_stack(*message1); + TestUtil::ExpectAllFieldsSet(message2_stack); + + google::protobuf::scoped_ptr<unittest::TestAllTypes> message2_heap( + new unittest::TestAllTypes(*message1)); + TestUtil::ExpectAllFieldsSet(*message2_heap); + + arena.Reset(); + + // Verify that the copies are still intact. + TestUtil::ExpectAllFieldsSet(message2_stack); + TestUtil::ExpectAllFieldsSet(*message2_heap); +} + TEST(GeneratedMessageTest, CopyAssignmentOperator) { unittest::TestAllTypes message1; TestUtil::SetAllFields(&message1); @@ -600,14 +621,16 @@ TEST(GeneratedMessageTest, NonEmptyMergeFrom) { #if !defined(PROTOBUF_TEST_NO_DESCRIPTORS) || \ !defined(GOOGLE_PROTOBUF_NO_RTTI) #ifdef PROTOBUF_HAS_DEATH_TEST +#ifndef NDEBUG TEST(GeneratedMessageTest, MergeFromSelf) { unittest::TestAllTypes message; - EXPECT_DEATH(message.MergeFrom(message), "Check failed:.*pb[.]cc"); + EXPECT_DEATH(message.MergeFrom(message), "pb[.]cc.*Check failed:"); EXPECT_DEATH(message.MergeFrom(implicit_cast<const Message&>(message)), - "Check failed:.*pb[.]cc"); + "pb[.]cc.*Check failed:"); } +#endif // NDEBUG #endif // PROTOBUF_HAS_DEATH_TEST #endif // !PROTOBUF_TEST_NO_DESCRIPTORS || !GOOGLE_PROTOBUF_NO_RTTI diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc index edd30780..03f6b12b 100644 --- a/src/google/protobuf/compiler/cpp/metadata_test.cc +++ b/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -156,7 +156,7 @@ const char kSmallTestFile[] = // couldn't). const GeneratedCodeInfo::Annotation* FindAnnotationOnPath( const GeneratedCodeInfo& info, const string& source_file, - const vector<int>& path) { + const std::vector<int>& path) { for (int i = 0; i < info.annotation_size(); ++i) { const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i); if (annotation->source_file() != source_file || @@ -197,7 +197,7 @@ TEST_F(CppMetadataTest, CapturesEnumNames) { EXPECT_TRUE( CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); EXPECT_EQ("Enum", file.enum_type(0).name()); - vector<int> enum_path; + std::vector<int> enum_path; enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber); enum_path.push_back(0); const GeneratedCodeInfo::Annotation* enum_annotation = @@ -226,7 +226,7 @@ TEST_F(CppMetadataTest, CapturesMessageNames) { EXPECT_TRUE( CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); EXPECT_EQ("Message", file.message_type(0).name()); - vector<int> message_path; + std::vector<int> message_path; message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber); message_path.push_back(0); const GeneratedCodeInfo::Annotation* message_annotation = |