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