aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler
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
parent709ea28f3264aa5632e5577a4080671173fc6166 (diff)
Integrate recent changes from Google-internal code tree. See CHANGES.txt
for details.
Diffstat (limited to 'src/google/protobuf/compiler')
-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
-rw-r--r--src/google/protobuf/compiler/importer.cc34
-rw-r--r--src/google/protobuf/compiler/importer.h10
-rw-r--r--src/google/protobuf/compiler/importer_unittest.cc28
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc20
-rw-r--r--src/google/protobuf/compiler/java/java_service.cc281
-rw-r--r--src/google/protobuf/compiler/java/java_service.h33
-rw-r--r--src/google/protobuf/compiler/parser.cc9
-rw-r--r--src/google/protobuf/compiler/parser.h15
-rw-r--r--src/google/protobuf/compiler/parser_unittest.cc44
28 files changed, 1281 insertions, 492 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
diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc
index 30e106e8..8a07dfc4 100644
--- a/src/google/protobuf/compiler/importer.cc
+++ b/src/google/protobuf/compiler/importer.cc
@@ -387,9 +387,22 @@ DiskSourceTree::DiskFileToVirtualFile(
return SUCCESS;
}
+bool DiskSourceTree::VirtualFileToDiskFile(const string& virtual_file,
+ string* disk_file) {
+ scoped_ptr<io::ZeroCopyInputStream> stream(OpenVirtualFile(virtual_file,
+ disk_file));
+ return stream != NULL;
+}
+
io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) {
- if (filename != CanonicalizePath(filename) ||
- ContainsParentReference(filename)) {
+ return OpenVirtualFile(filename, NULL);
+}
+
+io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
+ const string& virtual_file,
+ string* disk_file) {
+ if (virtual_file != CanonicalizePath(virtual_file) ||
+ ContainsParentReference(virtual_file)) {
// We do not allow importing of paths containing things like ".." or
// consecutive slashes since the compiler expects files to be uniquely
// identified by file name.
@@ -397,16 +410,21 @@ io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) {
}
for (int i = 0; i < mappings_.size(); i++) {
- string disk_file;
- if (ApplyMapping(filename, mappings_[i].virtual_path,
- mappings_[i].disk_path, &disk_file)) {
- io::ZeroCopyInputStream* stream = OpenDiskFile(disk_file);
- if (stream != NULL) return stream;
+ string temp_disk_file;
+ if (ApplyMapping(virtual_file, mappings_[i].virtual_path,
+ mappings_[i].disk_path, &temp_disk_file)) {
+ io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file);
+ if (stream != NULL) {
+ if (disk_file != NULL) {
+ *disk_file = temp_disk_file;
+ }
+ return stream;
+ }
if (errno == EACCES) {
// The file exists but is not readable.
// TODO(kenton): Find a way to report this more nicely.
- GOOGLE_LOG(WARNING) << "Read access is denied for file: " << disk_file;
+ GOOGLE_LOG(WARNING) << "Read access is denied for file: " << temp_disk_file;
return NULL;
}
}
diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h
index e2177e1c..7a2efc29 100644
--- a/src/google/protobuf/compiler/importer.h
+++ b/src/google/protobuf/compiler/importer.h
@@ -267,6 +267,11 @@ class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree {
string* virtual_file,
string* shadowing_disk_file);
+ // Given a virtual path, find the path to the file on disk.
+ // Return true and update disk_file with the on-disk path if the file exists.
+ // Return false and leave disk_file untouched if the file doesn't exist.
+ bool VirtualFileToDiskFile(const string& virtual_file, string* disk_file);
+
// implements SourceTree -------------------------------------------
io::ZeroCopyInputStream* Open(const string& filename);
@@ -280,6 +285,11 @@ class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree {
};
vector<Mapping> mappings_;
+ // Like Open(), but returns the on-disk path in disk_file if disk_file is
+ // non-NULL and the file could be successfully opened.
+ io::ZeroCopyInputStream* OpenVirtualFile(const string& virtual_file,
+ string* disk_file);
+
// Like Open() but given the actual on-disk path.
io::ZeroCopyInputStream* OpenDiskFile(const string& filename);
diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc
index 51aeb90c..56fad56e 100644
--- a/src/google/protobuf/compiler/importer_unittest.cc
+++ b/src/google/protobuf/compiler/importer_unittest.cc
@@ -565,6 +565,34 @@ TEST_F(DiskSourceTreeTest, DiskFileToVirtualFileCanonicalization) {
EXPECT_EQ("dir5/bar", virtual_file);
}
+TEST_F(DiskSourceTreeTest, VirtualFileToDiskFile) {
+ // Test VirtualFileToDiskFile.
+
+ AddFile(dirnames_[0] + "/foo", "Hello World!");
+ AddFile(dirnames_[1] + "/foo", "This file should be hidden.");
+ AddFile(dirnames_[1] + "/quux", "This file should not be hidden.");
+ source_tree_.MapPath("bar", dirnames_[0]);
+ source_tree_.MapPath("bar", dirnames_[1]);
+
+ // Existent files, shadowed and non-shadowed case.
+ string disk_file;
+ EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", &disk_file));
+ EXPECT_EQ(dirnames_[0] + "/foo", disk_file);
+ EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/quux", &disk_file));
+ EXPECT_EQ(dirnames_[1] + "/quux", disk_file);
+
+ // Nonexistent file in existent directory and vice versa.
+ string not_touched = "not touched";
+ EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("bar/baz", &not_touched));
+ EXPECT_EQ("not touched", not_touched);
+ EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", &not_touched));
+ EXPECT_EQ("not touched", not_touched);
+
+ // Accept NULL as output parameter.
+ EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", NULL));
+ EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", NULL));
+}
+
} // namespace
} // namespace compiler
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index c2e0c115..c9cbd13f 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -466,6 +466,17 @@ GenerateParseFromMethods(io::Printer* printer) {
" return newBuilder().mergeFrom(input, extensionRegistry)\n"
" .buildParsed();\n"
"}\n"
+ "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n"
+ " throws java.io.IOException {\n"
+ " return newBuilder().mergeDelimitedFrom(input).buildParsed();\n"
+ "}\n"
+ "public static $classname$ parseDelimitedFrom(\n"
+ " java.io.InputStream input,\n"
+ " com.google.protobuf.ExtensionRegistry extensionRegistry)\n"
+ " throws java.io.IOException {\n"
+ " return newBuilder().mergeDelimitedFrom(input, extensionRegistry)\n"
+ " .buildParsed();\n"
+ "}\n"
"public static $classname$ parseFrom(\n"
" com.google.protobuf.CodedInputStream input)\n"
" throws java.io.IOException {\n"
@@ -579,7 +590,8 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
printer->Print(
"public $classname$ build() {\n"
- " if (!isInitialized()) {\n"
+ // If result == null, we'll throw an appropriate exception later.
+ " if (result != null && !isInitialized()) {\n"
" throw new com.google.protobuf.UninitializedMessageException(\n"
" result);\n"
" }\n"
@@ -595,7 +607,11 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
" return buildPartial();\n"
"}\n"
"\n"
- "public $classname$ buildPartial() {\n",
+ "public $classname$ buildPartial() {\n"
+ " if (result == null) {\n"
+ " throw new IllegalStateException(\n"
+ " \"build() has already been called on this Builder.\");"
+ " }\n",
"classname", ClassName(descriptor_));
printer->Indent();
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index 5308dd20..5545bf7f 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -57,45 +57,111 @@ void ServiceGenerator::Generate(io::Printer* printer) {
"classname", descriptor_->name());
printer->Indent();
- // Generate abstract method declarations.
- for (int i = 0; i < descriptor_->method_count(); i++) {
- const MethodDescriptor* method = descriptor_->method(i);
- map<string, string> vars;
- vars["name"] = UnderscoresToCamelCase(method);
- vars["input"] = ClassName(method->input_type());
- vars["output"] = ClassName(method->output_type());
- printer->Print(vars,
- "public abstract void $name$(\n"
- " com.google.protobuf.RpcController controller,\n"
- " $input$ request,\n"
- " com.google.protobuf.RpcCallback<$output$> done);\n");
- }
+ printer->Print(
+ "protected $classname$() {}\n\n",
+ "classname", descriptor_->name());
+
+ GenerateInterface(printer);
+
+ GenerateNewReflectiveServiceMethod(printer);
+ GenerateNewReflectiveBlockingServiceMethod(printer);
+
+ GenerateAbstractMethods(printer);
// Generate getDescriptor() and getDescriptorForType().
printer->Print(
- "\n"
"public static final\n"
" com.google.protobuf.Descriptors.ServiceDescriptor\n"
" getDescriptor() {\n"
" return $file$.getDescriptor().getServices().get($index$);\n"
- "}\n"
- "public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
- " getDescriptorForType() {\n"
- " return getDescriptor();\n"
"}\n",
"file", ClassName(descriptor_->file()),
"index", SimpleItoa(descriptor_->index()));
+ GenerateGetDescriptorForType(printer);
// Generate more stuff.
GenerateCallMethod(printer);
GenerateGetPrototype(REQUEST, printer);
GenerateGetPrototype(RESPONSE, printer);
GenerateStub(printer);
+ GenerateBlockingStub(printer);
printer->Outdent();
printer->Print("}\n\n");
}
+void ServiceGenerator::GenerateGetDescriptorForType(io::Printer* printer) {
+ printer->Print(
+ "public final com.google.protobuf.Descriptors.ServiceDescriptor\n"
+ " getDescriptorForType() {\n"
+ " return getDescriptor();\n"
+ "}\n");
+}
+
+void ServiceGenerator::GenerateInterface(io::Printer* printer) {
+ printer->Print("public interface Interface {\n");
+ printer->Indent();
+ GenerateAbstractMethods(printer);
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+void ServiceGenerator::GenerateNewReflectiveServiceMethod(
+ io::Printer* printer) {
+ printer->Print(
+ "public static com.google.protobuf.Service newReflectiveService(\n"
+ " final Interface impl) {\n"
+ " return new $classname$() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->method_count(); i++) {
+ const MethodDescriptor* method = descriptor_->method(i);
+ printer->Print("@Override\n");
+ GenerateMethodSignature(printer, method, IS_CONCRETE);
+ printer->Print(
+ " {\n"
+ " impl.$method$(controller, request, done);\n"
+ "}\n\n",
+ "method", UnderscoresToCamelCase(method));
+ }
+
+ printer->Outdent();
+ printer->Print("};\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod(
+ io::Printer* printer) {
+ printer->Print(
+ "public static com.google.protobuf.BlockingService\n"
+ " newReflectiveBlockingService(final BlockingInterface impl) {\n"
+ " return new com.google.protobuf.BlockingService() {\n");
+ printer->Indent();
+ printer->Indent();
+
+ GenerateGetDescriptorForType(printer);
+
+ GenerateCallBlockingMethod(printer);
+ GenerateGetPrototype(REQUEST, printer);
+ GenerateGetPrototype(RESPONSE, printer);
+
+ printer->Outdent();
+ printer->Print("};\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+}
+
+void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) {
+ for (int i = 0; i < descriptor_->method_count(); i++) {
+ const MethodDescriptor* method = descriptor_->method(i);
+ GenerateMethodSignature(printer, method, IS_ABSTRACT);
+ printer->Print(";\n\n");
+ }
+}
+
void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
printer->Print(
"\n"
@@ -131,7 +197,49 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
printer->Print(
"default:\n"
- " throw new java.lang.RuntimeException(\"Can't get here.\");\n");
+ " throw new java.lang.AssertionError(\"Can't get here.\");\n");
+
+ printer->Outdent();
+ printer->Outdent();
+
+ printer->Print(
+ " }\n"
+ "}\n"
+ "\n");
+}
+
+void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) {
+ printer->Print(
+ "\n"
+ "public final com.google.protobuf.Message callBlockingMethod(\n"
+ " com.google.protobuf.Descriptors.MethodDescriptor method,\n"
+ " com.google.protobuf.RpcController controller,\n"
+ " com.google.protobuf.Message request)\n"
+ " throws com.google.protobuf.ServiceException {\n"
+ " if (method.getService() != getDescriptor()) {\n"
+ " throw new java.lang.IllegalArgumentException(\n"
+ " \"Service.callBlockingMethod() given method descriptor for \" +\n"
+ " \"wrong service type.\");\n"
+ " }\n"
+ " switch(method.getIndex()) {\n");
+ printer->Indent();
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->method_count(); i++) {
+ const MethodDescriptor* method = descriptor_->method(i);
+ map<string, string> vars;
+ vars["index"] = SimpleItoa(i);
+ vars["method"] = UnderscoresToCamelCase(method);
+ vars["input"] = ClassName(method->input_type());
+ vars["output"] = ClassName(method->output_type());
+ printer->Print(vars,
+ "case $index$:\n"
+ " return impl.$method$(controller, ($input$)request);\n");
+ }
+
+ printer->Print(
+ "default:\n"
+ " throw new java.lang.AssertionError(\"Can't get here.\");\n");
printer->Outdent();
printer->Outdent();
@@ -144,6 +252,10 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
io::Printer* printer) {
+ /*
+ * TODO(cpovirk): The exception message says "Service.foo" when it may be
+ * "BlockingService.foo." Consider fixing.
+ */
printer->Print(
"public final com.google.protobuf.Message\n"
" get$request_or_response$Prototype(\n"
@@ -171,7 +283,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
printer->Print(
"default:\n"
- " throw new java.lang.RuntimeException(\"Can't get here.\");\n");
+ " throw new java.lang.AssertionError(\"Can't get here.\");\n");
printer->Outdent();
printer->Outdent();
@@ -189,7 +301,8 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) {
" return new Stub(channel);\n"
"}\n"
"\n"
- "public static final class Stub extends $classname$ {\n",
+ "public static final class Stub extends $classname$ implements Interface {"
+ "\n",
"classname", ClassName(descriptor_));
printer->Indent();
@@ -206,33 +319,125 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) {
for (int i = 0; i < descriptor_->method_count(); i++) {
const MethodDescriptor* method = descriptor_->method(i);
+ printer->Print("\n");
+ GenerateMethodSignature(printer, method, IS_CONCRETE);
+ printer->Print(" {\n");
+ printer->Indent();
+
map<string, string> vars;
vars["index"] = SimpleItoa(i);
- vars["method"] = UnderscoresToCamelCase(method);
- vars["input"] = ClassName(method->input_type());
vars["output"] = ClassName(method->output_type());
printer->Print(vars,
- "\n"
- "public void $method$(\n"
- " com.google.protobuf.RpcController controller,\n"
- " $input$ request,\n"
- " com.google.protobuf.RpcCallback<$output$> done) {\n"
- " channel.callMethod(\n"
- " getDescriptor().getMethods().get($index$),\n"
- " controller,\n"
- " request,\n"
- " $output$.getDefaultInstance(),\n"
- " com.google.protobuf.RpcUtil.generalizeCallback(\n"
- " done,\n"
- " $output$.class,\n"
- " $output$.getDefaultInstance()));\n"
- "}\n");
+ "channel.callMethod(\n"
+ " getDescriptor().getMethods().get($index$),\n"
+ " controller,\n"
+ " request,\n"
+ " $output$.getDefaultInstance(),\n"
+ " com.google.protobuf.RpcUtil.generalizeCallback(\n"
+ " done,\n"
+ " $output$.class,\n"
+ " $output$.getDefaultInstance()));\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+}
+
+void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) {
+ printer->Print(
+ "public static BlockingInterface newBlockingStub(\n"
+ " com.google.protobuf.BlockingRpcChannel channel) {\n"
+ " return new BlockingStub(channel);\n"
+ "}\n"
+ "\n");
+
+ printer->Print(
+ "public interface BlockingInterface {");
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->method_count(); i++) {
+ const MethodDescriptor* method = descriptor_->method(i);
+ GenerateBlockingMethodSignature(printer, method);
+ printer->Print(";\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+
+ printer->Print(
+ "private static final class BlockingStub implements BlockingInterface {\n");
+ printer->Indent();
+
+ printer->Print(
+ "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n"
+ " this.channel = channel;\n"
+ "}\n"
+ "\n"
+ "private final com.google.protobuf.BlockingRpcChannel channel;\n");
+
+ for (int i = 0; i < descriptor_->method_count(); i++) {
+ const MethodDescriptor* method = descriptor_->method(i);
+ GenerateBlockingMethodSignature(printer, method);
+ printer->Print(" {\n");
+ printer->Indent();
+
+ map<string, string> vars;
+ vars["index"] = SimpleItoa(i);
+ vars["output"] = ClassName(method->output_type());
+ printer->Print(vars,
+ "return ($output$) channel.callBlockingMethod(\n"
+ " getDescriptor().getMethods().get($index$),\n"
+ " controller,\n"
+ " request,\n"
+ " $output$.getDefaultInstance());\n");
+
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
}
printer->Outdent();
printer->Print("}\n");
}
+void ServiceGenerator::GenerateMethodSignature(io::Printer* printer,
+ const MethodDescriptor* method,
+ IsAbstract is_abstract) {
+ map<string, string> vars;
+ vars["name"] = UnderscoresToCamelCase(method);
+ vars["input"] = ClassName(method->input_type());
+ vars["output"] = ClassName(method->output_type());
+ vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : "";
+ printer->Print(vars,
+ "public $abstract$ void $name$(\n"
+ " com.google.protobuf.RpcController controller,\n"
+ " $input$ request,\n"
+ " com.google.protobuf.RpcCallback<$output$> done)");
+}
+
+void ServiceGenerator::GenerateBlockingMethodSignature(
+ io::Printer* printer,
+ const MethodDescriptor* method) {
+ map<string, string> vars;
+ vars["method"] = UnderscoresToCamelCase(method);
+ vars["input"] = ClassName(method->input_type());
+ vars["output"] = ClassName(method->output_type());
+ printer->Print(vars,
+ "\n"
+ "public $output$ $method$(\n"
+ " com.google.protobuf.RpcController controller,\n"
+ " $input$ request)\n"
+ " throws com.google.protobuf.ServiceException");
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h
index 83404174..e07eebf7 100644
--- a/src/google/protobuf/compiler/java/java_service.h
+++ b/src/google/protobuf/compiler/java/java_service.h
@@ -57,9 +57,28 @@ class ServiceGenerator {
void Generate(io::Printer* printer);
private:
+
+ // Generate the getDescriptorForType() method.
+ void GenerateGetDescriptorForType(io::Printer* printer);
+
+ // Generate a Java interface for the service.
+ void GenerateInterface(io::Printer* printer);
+
+ // Generate newReflectiveService() method.
+ void GenerateNewReflectiveServiceMethod(io::Printer* printer);
+
+ // Generate newReflectiveBlockingService() method.
+ void GenerateNewReflectiveBlockingServiceMethod(io::Printer* printer);
+
+ // Generate abstract method declarations for all methods.
+ void GenerateAbstractMethods(io::Printer* printer);
+
// Generate the implementation of Service.callMethod().
void GenerateCallMethod(io::Printer* printer);
+ // Generate the implementation of BlockingService.callBlockingMethod().
+ void GenerateCallBlockingMethod(io::Printer* printer);
+
// Generate the implementations of Service.get{Request,Response}Prototype().
enum RequestOrResponse { REQUEST, RESPONSE };
void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer);
@@ -67,6 +86,20 @@ class ServiceGenerator {
// Generate a stub implementation of the service.
void GenerateStub(io::Printer* printer);
+ // Generate a method signature, possibly abstract, without body or trailing
+ // semicolon.
+ enum IsAbstract { IS_ABSTRACT, IS_CONCRETE };
+ void GenerateMethodSignature(io::Printer* printer,
+ const MethodDescriptor* method,
+ IsAbstract is_abstract);
+
+ // Generate a blocking stub interface and implementation of the service.
+ void GenerateBlockingStub(io::Printer* printer);
+
+ // Generate the method signature for one method of a blocking stub.
+ void GenerateBlockingMethodSignature(io::Printer* printer,
+ const MethodDescriptor* method);
+
const ServiceDescriptor* descriptor_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator);
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index e1c0d0d1..e9e01545 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -97,7 +97,8 @@ Parser::Parser()
error_collector_(NULL),
source_location_table_(NULL),
had_errors_(false),
- require_syntax_identifier_(false) {
+ require_syntax_identifier_(false),
+ stop_after_syntax_identifier_(false) {
}
Parser::~Parser() {
@@ -309,10 +310,12 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) {
// identifier.
return false;
}
- } else {
+ } else if (!stop_after_syntax_identifier_) {
syntax_identifier_ = "proto2";
}
+ if (stop_after_syntax_identifier_) return !had_errors_;
+
// Repeatedly parse statements until we reach the end of the file.
while (!AtEnd()) {
if (!ParseTopLevelStatement(file)) {
@@ -341,7 +344,7 @@ bool Parser::ParseSyntaxIdentifier() {
syntax_identifier_ = syntax;
- if (syntax != "proto2") {
+ if (syntax != "proto2" && !stop_after_syntax_identifier_) {
AddError(syntax_token.line, syntax_token.column,
"Unrecognized syntax identifier \"" + syntax + "\". This parser "
"only recognizes \"proto2\".");
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index b670f740..72c96d04 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -90,7 +90,7 @@ class LIBPROTOBUF_EXPORT Parser {
// Returns the identifier used in the "syntax = " declaration, if one was
// seen during the last call to Parse(), or the empty string otherwise.
- const string& GetSyntaxIndentifier() { return syntax_identifier_; }
+ const string& GetSyntaxIdentifier() { return syntax_identifier_; }
// If set true, input files will be required to begin with a syntax
// identifier. Otherwise, files may omit this. If a syntax identifier
@@ -100,6 +100,18 @@ class LIBPROTOBUF_EXPORT Parser {
require_syntax_identifier_ = value;
}
+ // Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop
+ // parsing as soon as it has seen the syntax identifier, or lack thereof.
+ // This is useful for quickly identifying the syntax of the file without
+ // parsing the whole thing. If this is enabled, no error will be recorded
+ // if the syntax identifier is something other than "proto2" (since
+ // presumably the caller intends to deal with that), but other kinds of
+ // errors (e.g. parse errors) will still be reported. When this is enabled,
+ // you may pass a NULL FileDescriptorProto to Parse().
+ void SetStopAfterSyntaxIdentifier(bool value) {
+ stop_after_syntax_identifier_ = value;
+ }
+
private:
// =================================================================
// Error recovery helpers
@@ -281,6 +293,7 @@ class LIBPROTOBUF_EXPORT Parser {
SourceLocationTable* source_location_table_;
bool had_errors_;
bool require_syntax_identifier_;
+ bool stop_after_syntax_identifier_;
string syntax_identifier_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 2d48c5ae..c4f08e7f 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -176,6 +176,38 @@ class ParserTest : public testing::Test {
// ===================================================================
+TEST_F(ParserTest, StopAfterSyntaxIdentifier) {
+ SetupParser(
+ "// blah\n"
+ "syntax = \"foobar\";\n"
+ "this line will not be parsed\n");
+ parser_->SetStopAfterSyntaxIdentifier(true);
+ EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
+ EXPECT_EQ("", error_collector_.text_);
+ EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) {
+ SetupParser(
+ "// blah\n"
+ "this line will not be parsed\n");
+ parser_->SetStopAfterSyntaxIdentifier(true);
+ EXPECT_TRUE(parser_->Parse(input_.get(), NULL));
+ EXPECT_EQ("", error_collector_.text_);
+ EXPECT_EQ("", parser_->GetSyntaxIdentifier());
+}
+
+TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) {
+ SetupParser(
+ "// blah\n"
+ "syntax = error;\n");
+ parser_->SetStopAfterSyntaxIdentifier(true);
+ EXPECT_FALSE(parser_->Parse(input_.get(), NULL));
+ EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_);
+}
+
+// ===================================================================
+
typedef ParserTest ParseMessageTest;
TEST_F(ParseMessageTest, SimpleMessage) {
@@ -201,7 +233,7 @@ TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) {
" name: \"TestMessage\""
" field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
"}");
- EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier());
+ EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
}
TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
@@ -215,7 +247,7 @@ TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) {
" name: \"TestMessage\""
" field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
"}");
- EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier());
+ EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
}
TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
@@ -230,7 +262,7 @@ TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) {
" name: \"TestMessage\""
" field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }"
"}");
- EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier());
+ EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
}
TEST_F(ParseMessageTest, SimpleFields) {
@@ -673,7 +705,7 @@ TEST_F(ParseErrorTest, MissingSyntaxIdentifier) {
ExpectHasEarlyExitErrors(
"message TestMessage {}",
"0:0: File must begin with 'syntax = \"proto2\";'.\n");
- EXPECT_EQ("", parser_->GetSyntaxIndentifier());
+ EXPECT_EQ("", parser_->GetSyntaxIdentifier());
}
TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
@@ -681,14 +713,14 @@ TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) {
"syntax = \"no_such_syntax\";",
"0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser "
"only recognizes \"proto2\".\n");
- EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIndentifier());
+ EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier());
}
TEST_F(ParseErrorTest, SimpleSyntaxError) {
ExpectHasErrors(
"message TestMessage @#$ { blah }",
"0:20: Expected \"{\".\n");
- EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier());
+ EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier());
}
TEST_F(ParseErrorTest, ExpectedTopLevel) {