aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/cpp
diff options
context:
space:
mode:
authorGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-04-25 02:53:47 +0000
committerGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-04-25 02:53:47 +0000
commitd37d46dfbcedadeb439ad0367f8afcf8867dca43 (patch)
treeb896df229f7c671637924c156d5a759ba50a3190 /src/google/protobuf/compiler/cpp
parent709ea28f3264aa5632e5577a4080671173fc6166 (diff)
Integrate recent changes from Google-internal code tree. See CHANGES.txt
for details.
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc24
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc72
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.cc81
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_extension.h3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h23
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc152
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc47
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc455
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h29
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc34
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc99
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_service.cc6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc100
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc140
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