diff options
author | kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2009-04-25 02:53:47 +0000 |
---|---|---|
committer | kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2009-04-25 02:53:47 +0000 |
commit | d37d46dfbcedadeb439ad0367f8afcf8867dca43 (patch) | |
tree | b896df229f7c671637924c156d5a759ba50a3190 /src/google/protobuf/compiler/cpp | |
parent | 709ea28f3264aa5632e5577a4080671173fc6166 (diff) |
Integrate recent changes from Google-internal code tree. See CHANGES.txt
for details.
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
19 files changed, 865 insertions, 434 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 77e50332..875cbef8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -100,6 +100,19 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n" "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n" "\n"); + + // The _Name and _Parse methods + printer->Print(vars, + "inline const ::std::string& $classname$_Name($classname$ value) {\n" + " return ::google::protobuf::internal::NameOfEnum(\n" + " $classname$_descriptor(), value);\n" + "}\n"); + printer->Print(vars, + "inline bool $classname$_Parse(\n" + " const ::std::string& name, $classname$* value) {\n" + " return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n" + " $classname$_descriptor(), name, value);\n" + "}\n"); } void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { @@ -122,6 +135,13 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { "static inline bool $nested_name$_IsValid(int value) {\n" " return $classname$_IsValid(value);\n" "}\n" + "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" + " return $classname$_Name(value);\n" + "}\n" + "static inline bool $nested_name$_Parse(const ::std::string& name,\n" + " $nested_name$* value) {\n" + " return $classname$_Parse(name, value);\n" + "}\n" "static const $nested_name$ $nested_name$_MIN =\n" " $classname$_$nested_name$_MIN;\n" "static const $nested_name$ $nested_name$_MAX =\n" @@ -147,12 +167,10 @@ void EnumGenerator::GenerateDescriptorInitializer( void EnumGenerator::GenerateMethods(io::Printer* printer) { map<string, string> vars; vars["classname"] = classname_; - vars["builddescriptorsname"] = - GlobalBuildDescriptorsName(descriptor_->file()->name()); printer->Print(vars, "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" - " if ($classname$_descriptor_ == NULL) $builddescriptorsname$();\n" + " protobuf_AssignDescriptorsOnce();\n" " return $classname$_descriptor_;\n" "}\n" "bool $classname$_IsValid(int value) {\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index a78bf887..b90eb372 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -116,8 +116,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void EnumFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_($default$)"); +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); } void EnumFieldGenerator:: @@ -128,15 +128,22 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "if ($type$_IsValid(value)) {\n" " set_$name$(static_cast< $type$ >(value));\n" "} else {\n" - " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n" "}\n"); } void EnumFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::WriteEnum(" - "$number$, this->$name$(), output));\n"); + "::google::protobuf::internal::WireFormat::WriteEnum(" + "$number$, this->$name$(), output);\n"); +} + +void EnumFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormat::WriteEnumToArray(" + "$number$, this->$name$(), target);\n"); } void EnumFieldGenerator:: @@ -217,12 +224,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void RepeatedEnumFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_()"); - if (descriptor_->options().packed() && - descriptor_->file()->options().optimize_for() == FileOptions::SPEED) { - printer->Print(variables_, ",\n_$name$_cached_byte_size_()"); - } +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. } void RepeatedEnumFieldGenerator:: @@ -248,7 +251,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n" "} else {\n" - " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n" "}\n"); } } @@ -259,22 +262,51 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" - " DO_(::google::protobuf::internal::WireFormat::WriteTag(" - "$number$, ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED," - "output));\n" - " DO_(output->WriteVarint32(_$name$_cached_byte_size_));\n" + " ::google::protobuf::internal::WireFormat::WriteTag(" + "$number$, " + "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, " + "output);\n" + " output->WriteVarint32(_$name$_cached_byte_size_);\n" + "}\n"); + } + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::WriteEnumNoTag(" + "this->$name$(i), output);\n"); + } else { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::WriteEnum(" + "$number$, this->$name$(i), output);\n"); + } + printer->Print("}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " target = ::google::protobuf::internal::WireFormat::WriteTagToArray(" + "$number$, " + "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, " + "target);\n" + " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(" + "_$name$_cached_byte_size_, target);\n" "}\n"); } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); if (descriptor_->options().packed()) { printer->Print(variables_, - " DO_(::google::protobuf::internal::WireFormat::WriteEnumNoTag(" - "this->$name$(i), output));\n"); + " target = ::google::protobuf::internal::WireFormat::WriteEnumNoTagToArray(" + "this->$name$(i), target);\n"); } else { printer->Print(variables_, - " DO_(::google::protobuf::internal::WireFormat::WriteEnum(" - "$number$, this->$name$(i), output));\n"); + " target = ::google::protobuf::internal::WireFormat::WriteEnumToArray(" + "$number$, this->$name$(i), target);\n"); } printer->Print("}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index f67b7ac0..20dd57bb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -56,9 +56,10 @@ class EnumFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(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; private: @@ -80,9 +81,10 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(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; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 3f212b93..61ebda73 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -36,6 +36,7 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/descriptor.pb.h> namespace google { namespace protobuf { @@ -55,7 +56,9 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, case FieldDescriptor::CPPTYPE_ENUM: type_traits_.append("EnumTypeTraits< "); type_traits_.append(ClassName(descriptor_->enum_type(), true)); - type_traits_.append(" >"); + type_traits_.append(", "); + type_traits_.append(ClassName(descriptor_->enum_type(), true)); + type_traits_.append("_IsValid>"); break; case FieldDescriptor::CPPTYPE_STRING: type_traits_.append("StringTypeTraits"); @@ -81,6 +84,8 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { vars["number" ] = SimpleItoa(descriptor_->number()); vars["type_traits" ] = type_traits_; vars["name" ] = descriptor_->name(); + vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); + vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; vars["constant_name"] = FieldConstantName(descriptor_); // If this is a class member, it needs to be declared "static". Otherwise, @@ -95,19 +100,39 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { printer->Print(vars, "static const int $constant_name$ = $number$;\n" "$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" - " ::google::protobuf::internal::$type_traits$ > $name$;\n"); + " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" + " $name$;\n" + ); } void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { + // If this is a class member, it needs to be declared in its class scope. + string scope = (descriptor_->extension_scope() == NULL) ? "" : + ClassName(descriptor_->extension_scope(), false) + "::"; + string name = scope + descriptor_->name(); + map<string, string> vars; vars["extendee" ] = ClassName(descriptor_->containing_type(), true); vars["type_traits" ] = type_traits_; - vars["name" ] = descriptor_->name(); + vars["name" ] = name; vars["constant_name"] = FieldConstantName(descriptor_); - - // If this is a class member, it needs to be declared in its class scope. - vars["scope"] = (descriptor_->extension_scope() == NULL) ? "" : - ClassName(descriptor_->extension_scope(), false) + "::"; + vars["default" ] = DefaultValue(descriptor_); + vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); + vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; + vars["scope" ] = scope; + + if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + // We need to declare a global string which will contain the default value. + // We cannot declare it at class scope because that would require exposing + // it in the header which would be annoying for other reasons. So we + // replace :: with _ in the name and declare it as a global. + string global_name = StringReplace(name, "::", "_", true); + vars["global_name"] = global_name; + printer->Print(vars, + "const ::std::string $global_name$_default($default$);\n"); + // Update the default to refer to the string global. + vars["default"] = global_name + "_default"; + } // Likewise, class members need to declare the field constant variable. if (descriptor_->extension_scope() != NULL) { @@ -119,8 +144,46 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { printer->Print(vars, "::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" - " ::google::protobuf::internal::$type_traits$ > $scope$$name$(" - "$constant_name$);\n"); + " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" + " $name$($constant_name$, $default$);\n"); +} + +void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { + map<string, string> vars; + vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["number" ] = SimpleItoa(descriptor_->number()); + vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); + vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false"; + vars["is_packed" ] = (descriptor_->is_repeated() && + descriptor_->options().packed()) + ? "true" : "false"; + + switch (descriptor_->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); + printer->Print( + " &$type$_IsValid);\n", + "type", ClassName(descriptor_->enum_type(), true)); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); + printer->Print( + " &$type$::default_instance());\n", + "type", ClassName(descriptor_->message_type(), true)); + break; + default: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$);\n"); + break; + } } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h index a9e58c18..3068b091 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/src/google/protobuf/compiler/cpp/cpp_extension.h @@ -66,6 +66,9 @@ class ExtensionGenerator { // Source file stuff. void GenerateDefinition(io::Printer* printer); + // Generate code to register the extension. + void GenerateRegistration(io::Printer* printer); + private: const FieldDescriptor* descriptor_; string type_traits_; diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index e5f8258f..7e7c7f83 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -94,16 +94,13 @@ class FieldGenerator { // message.cc under the GenerateSwap method. virtual void GenerateSwappingCode(io::Printer* printer) const = 0; - // Generate any initializers needed for the private members declared by - // GeneratePrivateMembers(). These go into the message class's - // constructor's initializer list. For each initializer, this method - // must print the comma and newline separating it from the *previous* - // initializer, not the *next* initailizer. That is, print a ",\n" first, - // e.g.: - // printer->Print(",\n$name$_($default$)"); - virtual void GenerateInitializer(io::Printer* printer) const = 0; - - // Generate any code that needs to go in the class's destructor. + // Generate initialization code for private members declared by + // GeneratePrivateMembers(). These go into the message class's SharedCtor() + // method, invoked by each of the generated constructors. + virtual void GenerateConstructorCode(io::Printer* printer) const = 0; + + // Generate any code that needs to go in the class's SharedDtor() method, + // invoked by the destructor. // Most field types don't need this, so the default implementation is empty. virtual void GenerateDestructorCode(io::Printer* printer) const {} @@ -115,6 +112,12 @@ class FieldGenerator { // message's SerializeWithCachedSizes() method. virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0; + // Generate lines to serialize this field directly to the array "target", + // which are placed within the message's SerializeWithCachedSizesToArray() + // method. This must also advance "target" past the written bytes. + virtual void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const = 0; + // Generate lines to compute the serialized size of this field, which // are placed in the message's ByteSize() method. virtual void GenerateByteSize(io::Printer* printer) const = 0; diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 6487979f..dcc48552 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -143,17 +143,20 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // Open namespace. GenerateNamespaceOpeners(printer); - // Forward-declare the AssignGlobalDescriptors function, so that we can - // declare it to be a friend of each class. + // Forward-declare the AddDescriptors and AssignDescriptors functions, so + // that we can declare them to be friends of each class. printer->Print( "\n" "// Internal implementation detail -- do not call these.\n" - "void $dllexport_decl$ $builddescriptorsname$();\n" - "void $builddescriptorsname$_AssignGlobalDescriptors(\n" - " ::google::protobuf::FileDescriptor* file);\n" - "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()), + "void $dllexport_decl$ $adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "dllexport_decl", dllexport_decl_); + printer->Print( + // Note that we don't put dllexport_decl on this because it is only called + // by the .pb.cc file in which it is defined. + "void $assigndescriptorsname$();\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); // Generate forward declarations of classes. for (int i = 0; i < file_->message_type_count(); i++) { @@ -232,6 +235,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "\n" "#include \"$basename$.pb.h\"\n" + "#include <google/protobuf/stubs/once.h>\n" "#include <google/protobuf/descriptor.h>\n" "#include <google/protobuf/io/coded_stream.h>\n" "#include <google/protobuf/reflection_ops.h>\n" @@ -296,23 +300,46 @@ void FileGenerator::GenerateSource(io::Printer* printer) { } void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { - // BuildDescriptors() is a file-level procedure which initializes all of - // the Descriptor objects for this file. It runs the first time one of the - // descriptors is accessed. This will always be at static initialization - // time, because every message has a statically-initialized default instance, - // and the constructor for a message class accesses its descriptor. See the - // constructor and the descriptor() method of message classes. + // AddDescriptors() is a file-level procedure which adds the encoded + // FileDescriptorProto for this .proto file to the global DescriptorPool + // for generated files (DescriptorPool::generated_pool()). It always runs + // at static initialization time, so all files will be registered before + // main() starts. This procedure also constructs default instances and + // registers extensions. // - // We also construct the reflection object for each class inside - // BuildDescriptors(). + // Its sibling, AssignDescriptors(), actually pulls the compiled + // FileDescriptor from the DescriptorPool and uses it to populate all of + // the global variables which store pointers to the descriptor objects. + // It also constructs the reflection objects. It is called the first time + // anyone calls descriptor() or GetReflection() on one of the types defined + // in the file. - // First we generate a method to assign the global descriptors. printer->Print( "\n" - "void $builddescriptorsname$_AssignGlobalDescriptors(" - "const ::google::protobuf::FileDescriptor* file) {\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + "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())); + + // 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()); + + // 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); } @@ -322,29 +349,63 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_->service_count(); i++) { service_generators_[i]->GenerateDescriptorInitializer(printer, i); } + + 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. + printer->Print( + "namespace {\n" + "\n" + "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n" + "inline void protobuf_AssignDescriptorsOnce() {\n" + " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n" + " &$assigndescriptorsname$);\n" + "}\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); + + // protobuf_RegisterTypes(): Calls + // MessageFactory::InternalRegisterGeneratedType() for each message type. + printer->Print( + "void protobuf_RegisterTypes() {\n" + " protobuf_AssignDescriptorsOnce();\n"); + printer->Indent(); + for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + message_generators_[i]->GenerateTypeRegistrations(printer); } printer->Outdent(); printer->Print( - "}\n"); + "}\n" + "\n" + "} // namespace\n"); + // ----------------------------------------------------------------- + + // Now generate the AddDescriptors() function. printer->Print( "\n" - "void $builddescriptorsname$() {\n" + "void $adddescriptorsname$() {\n" + // We don't need any special synchronization here because this code is + // called at static init time before any threads exist. " static bool already_here = false;\n" " if (already_here) return;\n" " already_here = true;\n" " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - " ::google::protobuf::DescriptorPool* pool =\n" - " ::google::protobuf::DescriptorPool::internal_generated_pool();\n" "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); printer->Indent(); - // Call the BuildDescriptors() methods for all of our dependencies, to make - // sure they get initialized first. + // Call the AddDescriptors() methods for all of our dependencies, to make + // sure they get added first. for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dependency = file_->dependency(i); // Print the namespace prefix for the dependency. @@ -355,10 +416,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { printer->Print("$name$::", "name", dependency_package_parts[i]); } - // Call its BuildDescriptors function. + // Call its AddDescriptors function. printer->Print( "$name$();\n", - "name", GlobalBuildDescriptorsName(dependency->name())); + "name", GlobalAddDescriptorsName(dependency->name())); } // Embed the descriptor. We simply serialize the entire FileDescriptorProto @@ -370,7 +431,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { file_proto.SerializeToString(&file_data); printer->Print( - "pool->InternalBuildGeneratedFile("); + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); // Only write 40 bytes per line. static const int kBytesPerLine = 40; @@ -379,24 +440,41 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "data", CEscape(file_data.substr(i, kBytesPerLine))); } printer->Print( - ", $size$,\n" - "&$builddescriptorsname$_AssignGlobalDescriptors);\n", - "size", SimpleItoa(file_data.size()), - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + ", $size$);\n", + "size", SimpleItoa(file_data.size())); + + // Call MessageFactory::InternalRegisterGeneratedFile(). + printer->Print( + "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n" + " \"$filename$\", &protobuf_RegisterTypes);\n", + "filename", file_->name()); + + // 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++) { + message_generators_[i]->GenerateDefaultInstanceAllocator(printer); + } + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistration(printer); + } + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + } printer->Outdent(); printer->Print( "}\n" "\n" - "// Force BuildDescriptors() to be called at static initialization time.\n" + "// Force AddDescriptors() to be called at static initialization time.\n" "struct StaticDescriptorInitializer_$filename$ {\n" " StaticDescriptorInitializer_$filename$() {\n" - " $builddescriptorsname$();\n" + " $adddescriptorsname$();\n" " }\n" "} static_descriptor_initializer_$filename$_;\n" "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()), + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "filename", FilenameIdentifier(file_->name())); } diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index d536bea4..214daff9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -38,6 +38,7 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> namespace google { namespace protobuf { @@ -213,6 +214,41 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { return ""; } +string DefaultValue(const FieldDescriptor* field) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return SimpleItoa(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return SimpleItoa(field->default_value_uint32()) + "u"; + case FieldDescriptor::CPPTYPE_INT64: + return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; + case FieldDescriptor::CPPTYPE_UINT64: + return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return SimpleDtoa(field->default_value_double()); + case FieldDescriptor::CPPTYPE_FLOAT: + return SimpleFtoa(field->default_value_float()); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_ENUM: + // Lazy: Generate a static_cast because we don't have a helper function + // that constructs the full name of an enum value. + return strings::Substitute( + "static_cast< $0 >($1)", + ClassName(field->enum_type(), true), + field->default_value_enum()->number()); + case FieldDescriptor::CPPTYPE_STRING: + return "\"" + CEscape(field->default_value_string()) + "\""; + case FieldDescriptor::CPPTYPE_MESSAGE: + return ClassName(field->message_type(), true) + "::default_instance()"; + } + // Can't actually get here; make compiler happy. (We could add a default + // case above but then we wouldn't get the nice compiler warning when a + // new type is added.) + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + // Convert a file name into a valid identifier. string FilenameIdentifier(const string& filename) { string result; @@ -230,9 +266,14 @@ string FilenameIdentifier(const string& filename) { return result; } -// Return the name of the BuildDescriptors() function for a given file. -string GlobalBuildDescriptorsName(const string& filename) { - return "protobuf_BuildDesc_" + FilenameIdentifier(filename); +// Return the name of the AddDescriptors() function for a given file. +string GlobalAddDescriptorsName(const string& filename) { + return "protobuf_AddDesc_" + FilenameIdentifier(filename); +} + +// Return the name of the AssignDescriptors() function for a given file. +string GlobalAssignDescriptorsName(const string& filename) { + return "protobuf_AssignDesc_" + FilenameIdentifier(filename); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 30c6e7d0..2260a934 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -90,11 +90,17 @@ const char* PrimitiveTypeName(FieldDescriptor::CppType type); // methods of WireFormat. For example, TYPE_INT32 becomes "Int32". const char* DeclaredTypeMethodName(FieldDescriptor::Type type); +// Get code that evaluates to the field's default value. +string DefaultValue(const FieldDescriptor* field); + // Convert a file name into a valid identifier. string FilenameIdentifier(const string& filename); -// Return the name of the BuildDescriptors() function for a given file. -string GlobalBuildDescriptorsName(const string& filename); +// Return the name of the AddDescriptors() function for a given file. +string GlobalAddDescriptorsName(const string& filename); + +// Return the name of the AssignDescriptors() function for a given file. +string GlobalAssignDescriptorsName(const string& filename); } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 2ec49234..44546bd0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -223,104 +223,10 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } if (descriptor_->extension_range_count() > 0) { - // Generate accessors for extensions. - - // Normally I'd generate prototypes here and generate the actual - // definitions of these methods in GenerateFieldAccessorDefinitions, but - // the prototypes for these silly methods are so absurdly complicated that - // it meant way too much repitition. - // - // We use "_proto_TypeTraits" as a type name below because "TypeTraits" - // causes problems if the class has a nested message or enum type with that - // name and "_TypeTraits" is technically reserved for the C++ library since - // it starts with an underscore followed by a capital letter. + // Generate accessors for extensions. We just call a macro located in + // extension_set.h since the accessors about 80 lines of static code. printer->Print( - // Has, Size, Clear - "template <typename _proto_TypeTraits>\n" - "inline bool HasExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) const {\n" - " return _extensions_.Has(id.number());\n" - "}\n" - "\n" - "template <typename _proto_TypeTraits>\n" - "inline void ClearExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) {\n" - " _extensions_.ClearExtension(id.number());\n" - "}\n" - "\n" - "template <typename _proto_TypeTraits>\n" - "inline int ExtensionSize(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) const {\n" - " return _extensions_.ExtensionSize(id.number());\n" - "}\n" - "\n" - - // Singular accessors - "template <typename _proto_TypeTraits>\n" - "inline typename _proto_TypeTraits::ConstType GetExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) const {\n" - " return _proto_TypeTraits::Get(id.number(), _extensions_);\n" - "}\n" - "\n" - "template <typename _proto_TypeTraits>\n" - "inline typename _proto_TypeTraits::MutableType MutableExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) {\n" - " return _proto_TypeTraits::Mutable(id.number(), &_extensions_);\n" - "}\n" - "\n" - "template <typename _proto_TypeTraits>\n" - "inline void SetExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " typename _proto_TypeTraits::ConstType value) {\n" - " _proto_TypeTraits::Set(id.number(), value, &_extensions_);\n" - "}\n" - "\n" - - // Repeated accessors - "template <typename _proto_TypeTraits>\n" - "inline typename _proto_TypeTraits::ConstType GetExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " int index) const {\n" - " return _proto_TypeTraits::Get(id.number(), _extensions_, index);\n" - "}\n" - "\n" - "template <typename _proto_TypeTraits>\n" - "inline typename _proto_TypeTraits::MutableType MutableExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " int index) {\n" - " return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_);\n" - "}\n" - "\n" - "template <typename _proto_TypeTraits>\n" - "inline void SetExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " int index, typename _proto_TypeTraits::ConstType value) {\n" - " _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);\n" - "}\n" - "\n" - "template <typename _proto_TypeTraits>\n" - "inline typename _proto_TypeTraits::MutableType AddExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) {\n" - " return _proto_TypeTraits::Add(id.number(), &_extensions_);\n" - "}\n" - "\n" - "template <typename _proto_TypeTraits>\n" - "inline void AddExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " typename _proto_TypeTraits::ConstType value) {\n" - " _proto_TypeTraits::Add(id.number(), value, &_extensions_);\n" - "}\n", + "GOOGLE_PROTOBUF_EXTENSION_ACCESSORS($classname$)\n", "classname", classname_); } } @@ -391,8 +297,6 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = dllexport_decl_ + " "; } - vars["builddescriptorsname"] = - GlobalBuildDescriptorsName(descriptor_->file()->name()); printer->Print(vars, "class $dllexport$$classname$ : public ::google::protobuf::Message {\n" @@ -433,18 +337,30 @@ GenerateClassDefinition(io::Printer* printer) { "void CopyFrom(const $classname$& from);\n" "void MergeFrom(const $classname$& from);\n" "void Clear();\n" - "bool IsInitialized() const;\n" - "int ByteSize() const;\n" - "\n" - "bool MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input);\n" - "bool SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const;\n"); + "bool IsInitialized() const;\n"); + + if (!descriptor_->options().message_set_wire_format()) { + // For message_set_wire_format, we don't generate parsing or + // serialization code even if optimize_for = SPEED, since MessageSet + // encoding is somewhat more complicated than normal extension encoding + // and we'd like to avoid having to implement it in multiple places. + // WireFormat's implementation is probably good enough. + printer->Print(vars, + "\n" + "int ByteSize() const;\n" + "bool MergePartialFromCodedStream(\n" + " ::google::protobuf::io::CodedInputStream* input);\n" + "void SerializeWithCachedSizes(\n" + " ::google::protobuf::io::CodedOutputStream* output) const;\n" + "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n"); + } } printer->Print(vars, "int GetCachedSize() const { return _cached_size_; }\n" "private:\n" + "void SharedCtor();\n" + "void SharedDtor();\n" "void SetCachedSize(int size) const { _cached_size_ = size; }\n" "public:\n" "\n" @@ -505,11 +421,17 @@ GenerateClassDefinition(io::Printer* printer) { .GeneratePrivateMembers(printer); } - // Generate offsets and _has_bits_ boilerplate. - printer->Print(vars, - "friend void $builddescriptorsname$_AssignGlobalDescriptors(\n" - " const ::google::protobuf::FileDescriptor* file);\n"); + // Declare AddDescriptors() and BuildDescriptors() as friends so that they + // can assign private static variables like default_instance_ and reflection_. + printer->Print( + "friend void $adddescriptorsname$();\n" + "friend void $assigndescriptorsname$();\n", + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name()), + "assigndescriptorsname", + GlobalAssignDescriptorsName(descriptor_->file()->name())); + // Generate offsets and _has_bits_ boilerplate. if (descriptor_->field_count() > 0) { printer->Print(vars, "::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n"); @@ -592,12 +514,6 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { "$parent$_descriptor_->nested_type($index$);\n"); } - // 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(vars, - "$classname$::default_instance_ = new $classname$();\n"); - // Generate the offsets. GenerateOffsets(printer); @@ -622,6 +538,7 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { } printer->Print(vars, " ::google::protobuf::DescriptorPool::generated_pool(),\n" + " ::google::protobuf::MessageFactory::generated_factory(),\n" " sizeof($classname$));\n"); // Handle nested types. @@ -632,11 +549,35 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { for (int i = 0; i < descriptor_->enum_type_count(); i++) { enum_generators_[i]->GenerateDescriptorInitializer(printer, i); } +} +void MessageGenerator:: +GenerateTypeRegistrations(io::Printer* printer) { // Register this message type with the message factory. - printer->Print(vars, + printer->Print( "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n" - " $classname$_descriptor_, $classname$::default_instance_);\n"); + " $classname$_descriptor_, &$classname$::default_instance());\n", + "classname", classname_); + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateTypeRegistrations(printer); + } +} + +void MessageGenerator:: +GenerateDefaultInstanceAllocator(io::Printer* printer) { + // 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_ = new $classname$();\n", + "classname", classname_); + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateDefaultInstanceAllocator(printer); + } } void MessageGenerator:: @@ -645,6 +586,11 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) { "$classname$::default_instance_->InitAsDefaultInstance();\n", "classname", classname_); + // Register extensions. + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistration(printer); + } + // Handle nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { nested_generators_[i]->GenerateDefaultInstanceInitializer(printer); @@ -695,14 +641,24 @@ GenerateClassMethods(io::Printer* printer) { GenerateClear(printer); printer->Print("\n"); - GenerateMergeFromCodedStream(printer); - printer->Print("\n"); + if (!descriptor_->options().message_set_wire_format()) { + // For message_set_wire_format, we don't generate parsing or + // serialization code even if optimize_for = SPEED, since MessageSet + // encoding is somewhat more complicated than normal extension encoding + // and we'd like to avoid having to implement it in multiple places. + // WireFormat's implementation is probably good enough. + GenerateMergeFromCodedStream(printer); + printer->Print("\n"); - GenerateSerializeWithCachedSizes(printer); - printer->Print("\n"); + GenerateSerializeWithCachedSizes(printer); + printer->Print("\n"); - GenerateByteSize(printer); - printer->Print("\n"); + GenerateSerializeWithCachedSizesToArray(printer); + printer->Print("\n"); + + GenerateByteSize(printer); + printer->Print("\n"); + } GenerateMergeFrom(printer); printer->Print("\n"); @@ -723,12 +679,10 @@ GenerateClassMethods(io::Printer* printer) { "}\n" "\n" "const ::google::protobuf::Reflection* $classname$::GetReflection() const {\n" - " if ($classname$_reflection_ == NULL) $builddescriptorsname$();\n" + " protobuf_AssignDescriptorsOnce();\n" " return $classname$_reflection_;\n" "}\n", - "classname", classname_, - "builddescriptorsname", - GlobalBuildDescriptorsName(descriptor_->file()->name())); + "classname", classname_); } void MessageGenerator:: @@ -757,28 +711,68 @@ GenerateInitializerList(io::Printer* printer) { printer->Indent(); printer->Print( - "::google::protobuf::Message(),\n"); + "::google::protobuf::Message()"); - if (descriptor_->extension_range_count() > 0) { - printer->Print( - "_extensions_(&$classname$_descriptor_,\n" - " ::google::protobuf::DescriptorPool::generated_pool(),\n" - " ::google::protobuf::MessageFactory::generated_factory()),\n", - "classname", classname_); - } + printer->Outdent(); + printer->Outdent(); +} + +void MessageGenerator:: +GenerateSharedConstructorCode(io::Printer* printer) { + printer->Print( + "void $classname$::SharedCtor() {\n", + "classname", classname_); + printer->Indent(); printer->Print( - "_unknown_fields_(),\n" - "_cached_size_(0)"); + "_cached_size_ = 0;\n"); - // Write the initializers for each field. for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(descriptor_->field(i)) - .GenerateInitializer(printer); + .GenerateConstructorCode(printer); } + printer->Print( + "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void MessageGenerator:: +GenerateSharedDestructorCode(io::Printer* printer) { + printer->Print( + "void $classname$::SharedDtor() {\n", + "classname", classname_); + printer->Indent(); + // Write the destructors for each field. + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateDestructorCode(printer); + } + + printer->Print( + "if (this != default_instance_) {\n"); + + // 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(). + 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) { + printer->Print(" delete $name$_;\n", + "name", FieldName(field)); + } + } + printer->Outdent(); + printer->Print( + " }\n" + "}\n" + "\n"); } void MessageGenerator:: @@ -790,7 +784,7 @@ GenerateStructors(io::Printer* printer) { "classname", classname_); GenerateInitializerList(printer); printer->Print(" {\n" - " ::memset(_has_bits_, 0, sizeof(_has_bits_));\n" + " SharedCtor();\n" "}\n"); printer->Print( @@ -826,54 +820,33 @@ GenerateStructors(io::Printer* printer) { "classname", classname_); GenerateInitializerList(printer); printer->Print(" {\n" - " ::memset(_has_bits_, 0, sizeof(_has_bits_));\n" + " SharedCtor();\n" " MergeFrom(from);\n" "}\n" "\n"); + // Generate the shared constructor code. + GenerateSharedConstructorCode(printer); + // Generate the destructor. printer->Print( - "$classname$::~$classname$() {\n", + "$classname$::~$classname$() {\n" + " SharedDtor();\n" + "}\n" + "\n", "classname", classname_); - printer->Indent(); - - // Write the destructors for each field. - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateDestructorCode(printer); - } + // Generate the shared destructor code. + GenerateSharedDestructorCode(printer); printer->Print( - "if (this != default_instance_) {\n"); - - // 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(). - 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) { - printer->Print(" delete $name$_;\n", - "name", FieldName(field)); - } - } - - printer->Outdent(); - - printer->Print( - " }\n" - "}\n" - "\n" "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" - " if ($classname$_descriptor_ == NULL) $builddescriptorsname$();\n" + " protobuf_AssignDescriptorsOnce();\n" " return $classname$_descriptor_;\n" "}\n" "\n" "const $classname$& $classname$::default_instance() {\n" - " if (default_instance_ == NULL) $builddescriptorsname$();\n" + " if (default_instance_ == NULL) $adddescriptorsname$();" " return *default_instance_;\n" "}\n" "\n" @@ -883,8 +856,8 @@ GenerateStructors(io::Printer* printer) { " return new $classname$;\n" "}\n", "classname", classname_, - "builddescriptorsname", - GlobalBuildDescriptorsName(descriptor_->file()->name())); + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); } void MessageGenerator:: @@ -1127,24 +1100,6 @@ GenerateCopyFrom(io::Printer* printer) { void MessageGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) { - if (descriptor_->options().message_set_wire_format()) { - // For message_set_wire_format, we don't generate a parser, for two - // reasons: - // - WireFormat already needs to special-case this, and we'd like to - // avoid having multiple implementations of MessageSet wire format - // lying around the code base. - // - All fields are extensions, and extension parsing falls back to - // reflection anyway, so it wouldn't be any faster. - printer->Print( - "bool $classname$::MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input) {\n" - " return ::google::protobuf::internal::WireFormat::ParseAndMergePartial(\n" - " input, this);\n" - "}\n", - "classname", classname_); - return; - } - printer->Print( "bool $classname$::MergePartialFromCodedStream(\n" " ::google::protobuf::io::CodedInputStream* input) {\n" @@ -1267,7 +1222,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } } printer->Print(") {\n" - " DO_(_extensions_.ParseField(tag, input, this));\n" + " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" + " mutable_unknown_fields()));\n" " continue;\n" "}\n"); } @@ -1295,7 +1251,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } void MessageGenerator::GenerateSerializeOneField( - io::Printer* printer, const FieldDescriptor* field) { + io::Printer* printer, const FieldDescriptor* field, bool to_array) { PrintFieldComment(printer, field); if (!field->is_repeated()) { @@ -1305,7 +1261,12 @@ void MessageGenerator::GenerateSerializeOneField( printer->Indent(); } - field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); + if (to_array) { + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( + printer); + } else { + field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); + } if (!field->is_repeated()) { printer->Outdent(); @@ -1315,25 +1276,66 @@ void MessageGenerator::GenerateSerializeOneField( } void MessageGenerator::GenerateSerializeOneExtensionRange( - io::Printer* printer, const Descriptor::ExtensionRange* range) { + io::Printer* printer, const Descriptor::ExtensionRange* range, + bool to_array) { map<string, string> vars; vars["start"] = SimpleItoa(range->start); vars["end"] = SimpleItoa(range->end); printer->Print(vars, - "// Extension range [$start$, $end$)\n" - "DO_(_extensions_.SerializeWithCachedSizes(\n" - " $start$, $end$, *this, output));\n\n"); + "// Extension range [$start$, $end$)\n"); + if (to_array) { + printer->Print(vars, + "target = _extensions_.SerializeWithCachedSizesToArray(\n" + " $start$, $end$, target);\n\n"); + } else { + printer->Print(vars, + "_extensions_.SerializeWithCachedSizes(\n" + " $start$, $end$, output);\n\n"); + } } void MessageGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) { printer->Print( - "bool $classname$::SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const {\n" - "#define DO_(EXPRESSION) if (!(EXPRESSION)) return false\n", + "void $classname$::SerializeWithCachedSizes(\n" + " ::google::protobuf::io::CodedOutputStream* output) const {\n", + "classname", classname_); + printer->Indent(); + + printer->Print( + "::google::protobuf::uint8* raw_buffer = " + "output->GetDirectBufferForNBytesAndAdvance(_cached_size_);\n" + "if (raw_buffer != NULL) {\n" + " $classname$::SerializeWithCachedSizesToArray(raw_buffer);\n" + " return;\n" + "}\n" + "\n", + "classname", classname_); + GenerateSerializeWithCachedSizesBody(printer, false); + + printer->Outdent(); + printer->Print( + "}\n"); +} + +void MessageGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) { + printer->Print( + "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n" + " ::google::protobuf::uint8* target) const {\n", "classname", classname_); printer->Indent(); + GenerateSerializeWithCachedSizesBody(printer, true); + + printer->Outdent(); + printer->Print( + " return target;\n" + "}\n"); +} + +void MessageGenerator:: +GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { scoped_array<const FieldDescriptor*> ordered_fields( SortFieldsByNumber(descriptor_)); @@ -1350,35 +1352,35 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) { i < descriptor_->field_count() || j < sorted_extensions.size(); ) { if (i == descriptor_->field_count()) { - GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + GenerateSerializeOneExtensionRange(printer, + sorted_extensions[j++], + to_array); } else if (j == sorted_extensions.size()) { - GenerateSerializeOneField(printer, ordered_fields[i++]); + GenerateSerializeOneField(printer, ordered_fields[i++], to_array); } else if (ordered_fields[i]->number() < sorted_extensions[j]->start) { - GenerateSerializeOneField(printer, ordered_fields[i++]); + GenerateSerializeOneField(printer, ordered_fields[i++], to_array); } else { - GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + GenerateSerializeOneExtensionRange(printer, + sorted_extensions[j++], + to_array); } } printer->Print("if (!unknown_fields().empty()) {\n"); printer->Indent(); - if (descriptor_->options().message_set_wire_format()) { + if (to_array) { printer->Print( - "DO_(::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n" - " unknown_fields(), output));\n"); + "target = " + "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n" + " unknown_fields(), target);\n"); } else { printer->Print( - "DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" - " unknown_fields(), output));\n"); + "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" + " unknown_fields(), output);\n"); } printer->Outdent(); - printer->Print( - "}\n" - "return true;\n"); - printer->Outdent(); printer->Print( - "#undef DO_\n" "}\n"); } @@ -1449,23 +1451,16 @@ GenerateByteSize(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { printer->Print( - "total_size += _extensions_.ByteSize(*this);\n" + "total_size += _extensions_.ByteSize();\n" "\n"); } printer->Print("if (!unknown_fields().empty()) {\n"); printer->Indent(); - if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "total_size +=\n" - " ::google::protobuf::internal::WireFormat::ComputeUnknownMessageSetItemsSize(\n" - " unknown_fields());\n"); - } else { - printer->Print( - "total_size +=\n" - " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" - " unknown_fields());\n"); - } + printer->Print( + "total_size +=\n" + " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" + " unknown_fields());\n"); printer->Outdent(); printer->Print("}\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index d6669a34..31aa1c4c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -86,7 +86,16 @@ class MessageGenerator { // descriptor. void GenerateDescriptorInitializer(io::Printer* printer, int index); - // Generates code that initializes the message's default instance. + // Generate code that calls MessageFactory::InternalRegisterGeneratedMessage() + // for all types. + void GenerateTypeRegistrations(io::Printer* printer); + + // Generates code that allocates the message's default instance. + void GenerateDefaultInstanceAllocator(io::Printer* printer); + + // Generates code that initializes the message's default instance. This + // is separate from allocating because all default instances must be + // allocated before any can be initialized. void GenerateDefaultInstanceInitializer(io::Printer* printer); // Generate all non-inline methods for this class. @@ -103,6 +112,15 @@ class MessageGenerator { // Generate constructors and destructor. void GenerateStructors(io::Printer* printer); + // The compiler typically generates multiple copies of each constructor and + // destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx + // Placing common code in a separate method reduces the generated code size. + // + // Generate the shared constructor code. + void GenerateSharedConstructorCode(io::Printer* printer); + // Generate the shared destructor code. + void GenerateSharedDestructorCode(io::Printer* printer); + // Generate the member initializer list for the constructors. The member // initializer list is shared between the default constructor and the copy // constructor. @@ -112,6 +130,9 @@ class MessageGenerator { void GenerateClear(io::Printer* printer); void GenerateMergeFromCodedStream(io::Printer* printer); void GenerateSerializeWithCachedSizes(io::Printer* printer); + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer); + void GenerateSerializeWithCachedSizesBody(io::Printer* printer, + bool to_array); void GenerateByteSize(io::Printer* printer); void GenerateMergeFrom(io::Printer* printer); void GenerateCopyFrom(io::Printer* printer); @@ -120,9 +141,11 @@ class MessageGenerator { // Helpers for GenerateSerializeWithCachedSizes(). void GenerateSerializeOneField(io::Printer* printer, - const FieldDescriptor* field); + const FieldDescriptor* field, + bool unbounded); void GenerateSerializeOneExtensionRange( - io::Printer* printer, const Descriptor::ExtensionRange* range); + io::Printer* printer, const Descriptor::ExtensionRange* range, + bool unbounded); const Descriptor* descriptor_; string classname_; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index e2d2370b..2a7eb3f8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -116,8 +116,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void MessageFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_(NULL)"); +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = NULL;\n"); } void MessageFieldGenerator:: @@ -136,8 +136,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void MessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" - "$number$, this->$name$(), output));\n"); + "::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" + "$number$, this->$name$(), output);\n"); +} + +void MessageFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$NoVirtualToArray(" + "$number$, this->$name$(), target);\n"); } void MessageFieldGenerator:: @@ -212,8 +220,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_()"); +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. } void RepeatedMessageFieldGenerator:: @@ -233,8 +241,18 @@ void RepeatedMessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n" - " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" - "$number$, this->$name$(i), output));\n" + " ::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" + "$number$, this->$name$(i), output);\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$NoVirtualToArray(" + "$number$, this->$name$(i), target);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 7ce4c32b..f5147278 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -56,9 +56,10 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(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; private: @@ -80,9 +81,10 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(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; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 57244c5d..44d0b97c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -79,35 +79,6 @@ int FixedSize(FieldDescriptor::Type type) { return -1; } -string DefaultValue(const FieldDescriptor* field) { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return SimpleItoa(field->default_value_int32()); - case FieldDescriptor::CPPTYPE_UINT32: - return SimpleItoa(field->default_value_uint32()) + "u"; - case FieldDescriptor::CPPTYPE_INT64: - return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; - case FieldDescriptor::CPPTYPE_UINT64: - return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field->default_value_double()); - case FieldDescriptor::CPPTYPE_FLOAT: - return SimpleFtoa(field->default_value_float()); - case FieldDescriptor::CPPTYPE_BOOL: - return field->default_value_bool() ? "true" : "false"; - - case FieldDescriptor::CPPTYPE_ENUM: - case FieldDescriptor::CPPTYPE_STRING: - case FieldDescriptor::CPPTYPE_MESSAGE: - GOOGLE_LOG(FATAL) << "Shouldn't get here."; - return ""; - } - // Can't actually get here; make compiler happy. (We could add a default - // case above but then we wouldn't get the nice compiler warning when a - // new type is added.) - return ""; -} - // TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of // repeat code between this and the other field types. void SetPrimitiveVariables(const FieldDescriptor* descriptor, @@ -180,8 +151,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void PrimitiveFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_($default$)"); +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); } void PrimitiveFieldGenerator:: @@ -195,8 +166,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(), output));\n"); + "::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(), output);\n"); +} + +void PrimitiveFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormat::Write$declared_type$ToArray(" + "$number$, this->$name$(), target);\n"); } void PrimitiveFieldGenerator:: @@ -282,12 +260,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void RepeatedPrimitiveFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_()"); - if (descriptor_->options().packed() && - descriptor_->file()->options().optimize_for() == FileOptions::SPEED) { - printer->Print(variables_, ",\n_$name$_cached_byte_size_()"); - } +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. } void RepeatedPrimitiveFieldGenerator:: @@ -324,22 +298,53 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" - " DO_(::google::protobuf::internal::WireFormat::WriteTag(" - "$number$, ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED," - "output));\n" - " DO_(output->WriteVarint32(_$name$_cached_byte_size_));\n" + " ::google::protobuf::internal::WireFormat::WriteTag(" + "$number$, " + "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, " + "output);\n" + " output->WriteVarint32(_$name$_cached_byte_size_);\n" + "}\n"); + } + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::Write$declared_type$NoTag(" + "this->$name$(i), output);\n"); + } else { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(i), output);\n"); + } + printer->Print("}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " target = ::google::protobuf::internal::WireFormat::WriteTagToArray(" + "$number$, " + "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, " + "target);\n" + " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(" + "_$name$_cached_byte_size_, target);\n" "}\n"); } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); if (descriptor_->options().packed()) { printer->Print(variables_, - " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoTag(" - "this->$name$(i), output));\n"); + " target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$NoTagToArray(" + "this->$name$(i), target);\n"); } else { printer->Print(variables_, - " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(i), output));\n"); + " target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$ToArray(" + "$number$, this->$name$(i), target);\n"); } printer->Print("}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index c7f7f310..6b96614c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -56,9 +56,10 @@ class PrimitiveFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(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; private: @@ -80,9 +81,10 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(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; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc index 59dbac1f..7689fa13 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.cc +++ b/src/google/protobuf/compiler/cpp/cpp_service.cc @@ -176,10 +176,12 @@ void ServiceGenerator::GenerateImplementation(io::Printer* printer) { "$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"); @@ -279,7 +281,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, printer->Print(vars_, " const ::google::protobuf::MethodDescriptor* method) const {\n" - " GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n" + " GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" " switch(method->index()) {\n"); for (int i = 0; i < descriptor_->method_count(); i++) { @@ -320,7 +322,7 @@ void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { " const $input_type$* request,\n" " $output_type$* response,\n" " ::google::protobuf::Closure* done) {\n" - " channel_->CallMethod($classname$_descriptor_->method($index$),\n" + " channel_->CallMethod(descriptor()->method($index$),\n" " controller, request, response, done);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 8e10e9b0..05858da4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -61,6 +61,8 @@ void SetStringVariables(const FieldDescriptor* descriptor, (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["pointer_type"] = + descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; } } // namespace @@ -111,13 +113,8 @@ GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, "inline const ::std::string& $name$() const;\n" "inline void set_$name$(const ::std::string& value);\n" - "inline void set_$name$(const char* value);\n"); - if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { - printer->Print(variables_, - "inline void set_$name$(const void* value, size_t size);\n"); - } - - printer->Print(variables_, + "inline void set_$name$(const char* value);\n" + "inline void set_$name$(const $pointer_type$* value, size_t size);\n" "inline ::std::string* mutable_$name$();\n"); if (descriptor_->options().has_ctype()) { @@ -146,20 +143,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $name$_ = new ::std::string;\n" " }\n" " $name$_->assign(value);\n" - "}\n"); - - if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { - printer->Print(variables_, - "inline void $classname$::set_$name$(const void* value, size_t size) {\n" - " _set_bit($index$);\n" - " if ($name$_ == &_default_$name$_) {\n" - " $name$_ = new ::std::string;\n" - " }\n" - " $name$_->assign(reinterpret_cast<const char*>(value), size);\n" - "}\n"); - } - - printer->Print(variables_, + "}\n" + "inline " + "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" + " _set_bit($index$);\n" + " if ($name$_ == &_default_$name$_) {\n" + " $name$_ = new ::std::string;\n" + " }\n" + " $name$_->assign(reinterpret_cast<const char*>(value), size);\n" + "}\n" "inline ::std::string* $classname$::mutable_$name$() {\n" " _set_bit($index$);\n" " if ($name$_ == &_default_$name$_) {\n"); @@ -213,9 +205,9 @@ GenerateSwappingCode(io::Printer* printer) const { } void StringFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { +GenerateConstructorCode(io::Printer* printer) const { printer->Print(variables_, - ",\n$name$_(const_cast< ::std::string*>(&_default_$name$_))"); + "$name$_ = const_cast< ::std::string*>(&_default_$name$_);\n"); } void StringFieldGenerator:: @@ -236,8 +228,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void StringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(), output));\n"); + "::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(), output);\n"); +} + +void StringFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormat::Write$declared_type$ToArray(" + "$number$, this->$name$(), target);\n"); } void StringFieldGenerator:: @@ -281,15 +280,12 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "inline ::std::string* mutable_$name$(int index);\n" "inline void set_$name$(int index, const ::std::string& value);\n" "inline void set_$name$(int index, const char* value);\n" + "inline " + "void set_$name$(int index, const $pointer_type$* value, size_t size);\n" "inline ::std::string* add_$name$();\n" "inline void add_$name$(const ::std::string& value);\n" - "inline void add_$name$(const char* value);\n"); - - if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { - printer->Print(variables_, - "inline void set_$name$(int index, const void* value, size_t size);\n" - "inline void add_$name$(const void* value, size_t size);\n"); - } + "inline void add_$name$(const char* value);\n" + "inline void add_$name$(const $pointer_type$* value, size_t size);\n"); if (descriptor_->options().has_ctype()) { printer->Outdent(); @@ -321,6 +317,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "inline void $classname$::set_$name$(int index, const char* value) {\n" " $name$_.Mutable(index)->assign(value);\n" "}\n" + "inline void " + "$classname$::set_$name$" + "(int index, const $pointer_type$* value, size_t size) {\n" + " $name$_.Mutable(index)->assign(\n" + " reinterpret_cast<const char*>(value), size);\n" + "}\n" "inline ::std::string* $classname$::add_$name$() {\n" " return $name$_.Add();\n" "}\n" @@ -329,19 +331,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "inline void $classname$::add_$name$(const char* value) {\n" " $name$_.Add()->assign(value);\n" + "}\n" + "inline void " + "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" + " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" "}\n"); - - if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { - printer->Print(variables_, - "inline void " - "$classname$::set_$name$(int index, const void* value, size_t size) {\n" - " $name$_.Mutable(index)->assign(\n" - " reinterpret_cast<const char*>(value), size);\n" - "}\n" - "inline void $classname$::add_$name$(const void* value, size_t size) {\n" - " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" - "}\n"); - } } void RepeatedStringFieldGenerator:: @@ -360,8 +354,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void RepeatedStringFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_()"); +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. } void RepeatedStringFieldGenerator:: @@ -375,8 +369,18 @@ void RepeatedStringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n" - " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(i), output));\n" + " ::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(i), output);\n" + "}\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$ToArray(" + "$number$, this->$name$(i), target);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 2244bd77..7f45107d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -57,10 +57,11 @@ class StringFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateDestructorCode(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; private: @@ -82,9 +83,10 @@ class RepeatedStringFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(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; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index c7e4ee3d..ea9cc32d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -52,6 +52,8 @@ #include <google/protobuf/test_util.h> #include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h> #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/descriptor.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/dynamic_message.h> @@ -61,6 +63,7 @@ #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> +#include <google/protobuf/stubs/stl_util-inl.h> namespace google { namespace protobuf { @@ -86,6 +89,8 @@ class MockErrorCollector : public MultiFileErrorCollector { } }; +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + // Test that generated code has proper descriptors: // Parse a descriptor directly (using google::protobuf::compiler::Importer) and // compare it to the one that was produced by generated code. @@ -115,6 +120,8 @@ TEST(GeneratedDescriptorTest, IdenticalDescriptors) { generated_decsriptor_proto.DebugString()); } +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + // =================================================================== TEST(GeneratedMessageTest, Defaults) { @@ -222,6 +229,22 @@ TEST(GeneratedMessageTest, ClearOneField) { TestUtil::ExpectAllFieldsSet(message); } +TEST(GeneratedMessageTest, StringCharStarLength) { + // Verify that we can use a char*,length to set one of the string fields. + unittest::TestAllTypes message; + message.set_optional_string("abcdef", 3); + EXPECT_EQ("abc", message.optional_string()); + + // Verify that we can use a char*,length to add to a repeated string field. + message.add_repeated_string("abcdef", 3); + EXPECT_EQ(1, message.repeated_string_size()); + EXPECT_EQ("abc", message.repeated_string(0)); + + // Verify that we can use a char*,length to set a repeated string field. + message.set_repeated_string(0, "wxyz", 2); + EXPECT_EQ("wx", message.repeated_string(0)); +} + TEST(GeneratedMessageTest, CopyFrom) { unittest::TestAllTypes message1, message2; @@ -346,6 +369,8 @@ TEST(GeneratedMessageTest, UpcastCopyFrom) { TestUtil::ExpectAllFieldsSet(message2); } +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + TEST(GeneratedMessageTest, DynamicMessageCopyFrom) { // Test copying from a DynamicMessage, which must fall back to using // reflection. @@ -366,6 +391,8 @@ TEST(GeneratedMessageTest, DynamicMessageCopyFrom) { TestUtil::ExpectAllFieldsSet(message2); } +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + TEST(GeneratedMessageTest, NonEmptyMergeFrom) { // Test merging with a non-empty message. Code is a modified form // of that found in google/protobuf/reflection_ops_unittest.cc. @@ -403,24 +430,75 @@ TEST(GeneratedMessageTest, MergeFromSelf) { #endif // GTEST_HAS_DEATH_TEST -TEST(GeneratedMessageTest, Serialization) { +// Test the generated SerializeWithCachedSizesToArray(), +TEST(GeneratedMessageTest, SerializationToArray) { unittest::TestAllTypes message1, message2; string data; - TestUtil::SetAllFields(&message1); - message1.SerializeToString(&data); + int size = message1.ByteSize(); + data.resize(size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&data)); + uint8* end = + message1.TestAllTypes::SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); TestUtil::ExpectAllFieldsSet(message2); +} +TEST(GeneratedMessageTest, PackedFieldsSerializationToArray) { unittest::TestPackedTypes packed_message1, packed_message2; string packed_data; TestUtil::SetPackedFields(&packed_message1); - packed_message1.SerializeToString(&packed_data); + int packed_size = packed_message1.ByteSize(); + packed_data.resize(packed_size); + uint8* start = reinterpret_cast<uint8*>(string_as_array(&packed_data)); + uint8* end = + packed_message1.TestPackedTypes::SerializeWithCachedSizesToArray(start); + EXPECT_EQ(packed_size, end - start); EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); TestUtil::ExpectPackedFieldsSet(packed_message2); } +// Test the generated SerializeWithCachedSizes() by forcing the buffer to write +// one byte at a time. +TEST(GeneratedMessageTest, SerializationToStream) { + unittest::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + int size = message1.ByteSize(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.TestAllTypes::SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(message2); + +} + +TEST(GeneratedMessageTest, PackedFieldsSerializationToStream) { + unittest::TestPackedTypes message1, message2; + TestUtil::SetPackedFields(&message1); + int size = message1.ByteSize(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.TestPackedTypes::SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(message2); +} + TEST(GeneratedMessageTest, Required) { // Test that IsInitialized() returns false if required fields are missing. @@ -547,6 +625,8 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) { EXPECT_EQ(5, message.friend_()); } +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + TEST(GeneratedMessageTest, TestOptimizedForSize) { // We rely on the tests in reflection_ops_unittest and wire_format_unittest // to really test that reflection-based methods work. Here we are mostly @@ -614,6 +694,8 @@ TEST(GeneratedMessageTest, TestSpaceUsed) { message1.SpaceUsed()); } +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + // =================================================================== TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) { @@ -682,8 +764,37 @@ TEST(GeneratedEnumTest, MinAndMax) { } } +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GeneratedEnumTest, Name) { + // "Names" in the presence of dup values are a bit arbitrary. + EXPECT_EQ("FOO1", unittest::TestEnumWithDupValue_Name(unittest::FOO1)); + EXPECT_EQ("FOO1", unittest::TestEnumWithDupValue_Name(unittest::FOO2)); + + EXPECT_EQ("SPARSE_A", unittest::TestSparseEnum_Name(unittest::SPARSE_A)); + EXPECT_EQ("SPARSE_B", unittest::TestSparseEnum_Name(unittest::SPARSE_B)); + EXPECT_EQ("SPARSE_C", unittest::TestSparseEnum_Name(unittest::SPARSE_C)); + EXPECT_EQ("SPARSE_D", unittest::TestSparseEnum_Name(unittest::SPARSE_D)); + EXPECT_EQ("SPARSE_E", unittest::TestSparseEnum_Name(unittest::SPARSE_E)); + EXPECT_EQ("SPARSE_F", unittest::TestSparseEnum_Name(unittest::SPARSE_F)); + EXPECT_EQ("SPARSE_G", unittest::TestSparseEnum_Name(unittest::SPARSE_G)); +} + +TEST(GeneratedEnumTest, Parse) { + unittest::TestEnumWithDupValue dup_value = unittest::FOO1; + EXPECT_TRUE(unittest::TestEnumWithDupValue_Parse("FOO1", &dup_value)); + EXPECT_EQ(unittest::FOO1, dup_value); + EXPECT_TRUE(unittest::TestEnumWithDupValue_Parse("FOO2", &dup_value)); + EXPECT_EQ(unittest::FOO2, dup_value); + EXPECT_FALSE(unittest::TestEnumWithDupValue_Parse("FOO", &dup_value)); +} + +#endif // PROTOBUF_TEST_NO_DESCRIPTORS + // =================================================================== +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + // Support code for testing services. class GeneratedServiceTest : public testing::Test { protected: @@ -977,6 +1088,27 @@ TEST_F(GeneratedServiceTest, NotImplemented) { EXPECT_TRUE(controller.called_); } +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +// This test must run last. It verifies that descriptors were or were not +// initialized depending on whether PROTOBUF_TEST_NO_DESCRIPTORS was defined. +// When this is defined, we skip all tests which are expected to trigger +// descriptor initialization. This verifies that everything else still works +// if descriptors are not initialized. +TEST(DescriptorInitializationTest, Initialized) { +#ifdef PROTOBUF_TEST_NO_DESCRIPTORS + bool should_have_descriptors = false; +#else + bool should_have_descriptors = true; +#endif + + EXPECT_EQ(should_have_descriptors, + DescriptorPool::generated_pool()->InternalIsFileLoaded( + "google/protobuf/unittest.proto")); +} + } // namespace cpp_unittest } // namespace cpp |